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
141 stars 27 forks source link

Error regarding dispose when scroll halfway through the section and collapse the section #21

Closed lemy319 closed 4 years ago

lemy319 commented 4 years ago

I was testing on the custom section animation example and was trying to replace list tile text with an image as shown below, the error happens when i scroll halfway through the section and tap the header to collapse the section. Simulator Screen Shot - iPhone SE (2nd generation) - 2020-09-18 at 14 32 55 Screenshot 2020-09-18 at 1 46 25 PM

tp7309 commented 4 years ago

Could you give me an example code?

lemy319 commented 4 years ago

I changed section and items size to 5 in example_custom_section_animation.dart

var sectionList = MockData.getExampleSections(5, 5);

and replace String with Image

class MockData {
  ///return a example list, by default, we have 10 sections,
  ///each section has 5 items.
  static List<ExampleSection> getExampleSections(
      [sectionSize = 10, itemSize = 5]) {
    var sections = List<ExampleSection>();
    for (int i = 0; i < sectionSize; i++) {
      var section = ExampleSection()
        ..header = "Header #$i"
        ..items = List.generate(itemSize, (index) => Image.network('http://via.placeholder.com/640x1080'))
        ..expanded = true;
      sections.add(section);
    }
    return sections;
  }
}
tp7309 commented 4 years ago
@override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
lemy319 commented 4 years ago

Oh great, that get rid of the dispose error, but I also noticed that the scroll behaviour not working properly after collapsing the section, the header will gone at first, and come back when start scrolling, plus, if you scroll to top and scroll back down, the header will not be sticky anymore.

tp7309 commented 4 years ago

the header will gone at first, and come back when start scrolling: Bug.

if you scroll to top and scroll back down, the header will not be sticky anymore: Header sticky range is [section top, section bottom], when section collapsed, the height of section equals to height of header, so header can not sticky anymore.

lemy319 commented 4 years ago

Re: Header sticky range is [section top, section bottom], when section collapsed, the height of section equals to height of header, so header can not sticky anymore.

When section collapsed, it looks fine to me that it will not be sticky, however, I noticed headers which are in expanded state will not sticky as well, from the video we can see it looks fine on header0 for not being sticky, but header1 and header2 are in expanded state and they are not sticky as well

scrolling demo

tp7309 commented 4 years ago

Is you called onStateChanged after animation?

sectionBuilder: (context, containerInfo) => _SectionWidget(
              section: sectionList[containerInfo.sectionIndex],
              containerInfo: containerInfo,
              onStateChanged: () {
                //notify ExpandableListView that expand state has changed.
                WidgetsBinding.instance.addPostFrameCallback((_) {
                  if (mounted) {
                    setState(() {});
                  }
                });
              },
            ),
lemy319 commented 4 years ago

yes, nothing i have changed on the onStateChanged, what i found out is it didn't called the onStateChanged after the controller dispose, so i tried call onStateChanged whenever the controller disposed, and it did get rid of the header not sticky issue

@override
  void dispose() {
    widget.onStateChanged();
    _controller.dispose();
    super.dispose();
  }
tp7309 commented 4 years ago

I see, or you can always update listview state on animation end:

void _onTap() {
    widget.section.setSectionExpanded(!widget.section.isSectionExpanded());
    if (widget.section.isSectionExpanded()) {
      widget?.onStateChanged();
      _controller.forward().then((_) {
        widget?.onStateChanged();
      });
    } else {
      _controller.reverse().then((_) {
        widget?.onStateChanged();
      });
    }
  }
lemy319 commented 4 years ago

Hmm, I tried that out, but still the same, it also unable to call the onStateChanged because of the controller disposed. Anyway, thank you for working on this package and helping me out. 😃

tp7309 commented 4 years ago

Thank you for your feedback. 😁