tp7309 / flutter_sticky_and_expandable_list

粘性头部与分组列表Sliver实现 Build a grouped list, which support expand/collapse section and sticky headers, support use it with sliver widget.
MIT License
140 stars 29 forks source link

ExpandableListHeaderController.percent jumps from 0.9 to 0.0 during scroll #4

Closed emvaized closed 4 years ago

emvaized commented 4 years ago

Screenshot_20200317_050741

Please implement more intuitive behavior, for all 3 states of header: like -1.0 for header being off-screen, 0.0 for pinned, and 1.0 for not-pinned (floating) header, as it is implemented here.

tp7309 commented 4 years ago

I don't want callback header offset every frame.You can get such information:

Maybe example_animable_header can give you some tips. ^_^

emvaized commented 4 years ago

@tp7309 Thanks :) I'm currently using this approach to create a shadow below header only when it's pinned on top:

Card(
        elevation:
            stickyController.stickySectionIndex == sectionIndex
                ? 3
                : 0,
)

But it works with some issues -- for example, when there's padding on top of the list, header of the first card always has shadow, even when it's not pinned. Maybe I'm just missing something?

tp7309 commented 4 years ago

Padding on top of the list? Could you give me an example?

emvaized commented 4 years ago

For example (approximation of my use case):

CustomScrollView(
  slivers: [
    /// First child of my CustomScrollView, which can be considered as a 'padding'
    SliverToBoxAdapter(
       child: Container(height: 100, width: 100)
    ),
    ExpandableListView(
        controller: stickyController,
        builder: SliverExpandableChildDelegate<String, ExampleSection>(
            headerBuilder: (context, section, index) => Text("Header #$index"),
            itemBuilder: (context, section, item, index) {
            int sectionIndex = sectionList.indexOf(section); 
               return Card(
                  elevation:
                      stickyController.stickySectionIndex == sectionIndex
                        ? 3
                        : 0, /// <-- when list is scrolled to top, first header never reach this value
                  child: Text(item),
              );
         }
    ))
  ]
);
emvaized commented 4 years ago

@tp7309 Previously I used flutter_sticky_headers, and with implementation below there were no problems:

...
return Card(
    elevation: stickiness < 0.0 ? 3 : 0,
    child: Text(item)
)

That's why I suggested to implement some analog of stickiness parameter, with values of -1.0(completely off-screen), 0.0 ('sticked') and 1.0 (not sticked, floating).

tp7309 commented 4 years ago

@emvaized Thanks for your feedback! Built-in animation are planned to be added in this weekend! For your feature, you can try the following code:

class _ExampleSliverState extends State<ExampleSliver> {
  var sectionList = MockData.getExampleSections();

  int _stickySectionIndex = -1;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: CustomScrollView(slivers: [
          /// First child of my CustomScrollView, which can be considered as a 'padding'
          SliverToBoxAdapter(child: Container(height: 100, width: 100)),
          SliverExpandableList(
              builder: SliverExpandableChildDelegate<String, ExampleSection>(
                  sectionList: sectionList,
                  headerController: _getHeaderController(),
                  headerBuilder: (context, section, index) {
                    int sectionIndex = sectionList.indexOf(section);
                    return Card(
                      elevation: _stickySectionIndex == sectionIndex ? 10 : 0,
                      child: Text("Header #$index"),
                    );
                  },
                  itemBuilder: (context, section, item, index) {
                    int sectionIndex = sectionList.indexOf(section);
                    return Card(
                      elevation: _stickySectionIndex == sectionIndex ? 10 : 0,
                      child: Text(item),
                    );
                  }))
        ]),
      ),
    );
  }

  _getHeaderController() {
    var controller = ExpandableListHeaderController();
    //when changing sticky header, listener will be called.
    controller.addListener(() {
      /// if you want call itemBuilder when changing sticky header, call setState() manually.
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (!mounted || _stickySectionIndex == controller.stickySectionIndex) {
          return;
        }
//        print(controller);
        setState(() {
          _stickySectionIndex = controller.stickySectionIndex;
        });
      });

      /// if you only want call headerBuilder when changing sticky header, no need to call setState().
      /// just change some value in headerBuilder.
    });
    return controller;
  }
}
tp7309 commented 4 years ago

@tp7309 Previously I used flutter_sticky_headers, and with implementation below there were no problems:

...
return Card(
    elevation: stickiness < 0.0 ? 3 : 0,
    child: Text(item)
)

That's why I suggested to implement some analog of stickiness parameter, with values of -1.0(completely off-screen), 0.0 ('sticked') and 1.0 (not sticked, floating).

It will trigger widget rebuild high frequency, so if you need rebuild item widget, call setState() manually is another option.

emvaized commented 4 years ago

@tp7309 Very nice! Will be glad to try out these animations.

About subject: Please let me illustrate my issue with this GIF (with your solution already implemented): ezgif com-video-to-gif(2)

The issue I mentioned above can be seen in the end of this GIF, and your solution created another issue, that can be seen in the beginning of GIF (previous header keeps at elevation == 0 despite being over content).

tp7309 commented 4 years ago

There has a bug, when scroll out SliverExpandableList, stickySectionIndex are not updated, I'm trying to fix it.

emvaized commented 4 years ago

@tp7309 Oh, I see now. Glad you're working on it! I'll be waiting for updates.

tp7309 commented 4 years ago

@emvaized Hi, I have updated the library, you can try to use 0.2.0-beta. In order to use it more conveniently, some API changed, so you may need read the lastest REMDME. fixed animable header example

emvaized commented 4 years ago

@tp7309 I see. A lot of changes :) Seems like bug is fixed now. Great, thanks a lot for your work!

tp7309 commented 4 years ago

@emvaized Thank you for you feedback:)