Code Monkey home page Code Monkey logo

flutter_sticky_and_expandable_list's Introduction

sticky_and_expandable_list

Flutter implementation of sticky headers and expandable list.Support use it in a CustomScrollView.

Pub README i18n:中文说明

Screenshot

Features

  • Build a grouped list, which support expand/collapse section and sticky header.
  • Use it with CustomScrollView、SliverAppBar.
  • Listen the scroll offset of current sticky header, current sticky header index and switching header index.
  • Only use one list widget, so it supports large data and a normal memory usage.
  • More section customization support, you can return a new section widget by sectionBuilder, to customize background,expand/collapse animation, section layout, and so on.
  • Support add divider.
  • Support overlap content.
  • Support scroll to index like ListView, by scroll-to-index.
  • Pull to refresh and load more, by pull_to_refresh.

Getting Started

In the pubspec.yaml of your flutter project, add the following dependency:

dependencies:
  sticky_and_expandable_list: ^1.1.3

Basic Usage

sectionList is a custom data source for ExpandableListView. We should create a model list to store the information of each section, the model must implement ExpandableListSection.

    //In this example, we create a custom model class(ExampleSection).
    //class ExampleSection implements ExpandableListSection<String> {}
    //so: SliverExpandableChildDelegate<String, ExampleSection>()
    List<ExampleSection> sectionList = List<ExampleSection>();
    return ExpandableListView(
      builder: SliverExpandableChildDelegate<String, ExampleSection>(
          sectionList: sectionList,
          headerBuilder: (context, sectionIndex, index) =>
              Text("Header #$sectionIndex"),
          itemBuilder: (context, sectionIndex, itemIndex, index) {
            String item = sectionList[sectionIndex].items[itemIndex];
            return ListTile(
              leading: CircleAvatar(
                child: Text("$index"),
              ),
              title: Text(item),
            );
          }),
    );

Detail Examples

If you want to use it with sliver widget, use SliverExpandableList instead of ExpandableListView.

FAQ

How to expand/collapse item?

setState(() {
  sectionList[i].setSectionExpanded(true);
});

Example

How to listen current sticky header or the sticky header scroll offset?

  @override
  Widget build(BuildContext context) {
    ExpandableListView(
      builder: SliverExpandableChildDelegate<String, ExampleSection>(
        headerController: _getHeaderController(),
      ),
    )
  }

  _getHeaderController() {
    var controller = ExpandableListController();
    controller.addListener(() {
      print("switchingSectionIndex:${controller.switchingSectionIndex}, stickySectionIndex:" +
          "${controller.stickySectionIndex},scrollPercent:${controller.percent}");
    });
    return controller;
  }

How to set background for each section?

Use sectionBuilder

Customize expand/collapse animation support?

Example

Change Log

CHANGELOG

Donate

Buy a cup of coffee for me (Scan by wechat):

qrcode

flutter_sticky_and_expandable_list's People

Contributors

tp7309 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

flutter_sticky_and_expandable_list's Issues

Usage with Dismissible widget

How to properly remove section from screen in onDismissed() callback of Dismissible widget?
I tried to call widget.fetchedData.removeAt(position), but it seems to fail, resulting in 'RangeError (index)'.

当items 为空或者items.length =0 时有问题,

The method '_addFromInteger' was called on null.
Receiver: null
Tried calling: _addFromInteger(1)

The relevant error-causing widget was:
ExampleListView file:///Users/mac/Downloads/flutter_sticky_and_expandable_list-master/example/lib/main.dart:43:50
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 int.+ (dart:core-patch/integers.dart:12:38)
#2 SliverExpandableChildDelegate._buildSectionRealIndexes (package:sticky_and_expandable_list/src/sliver_expandable_list.dart:214:22)
#3 new SliverExpandableChildDelegate (package:sticky_and_expandable_list/src/sliver_expandable_list.dart:81:30)
#4 _ExampleListViewState.build (package:example/example_listview.dart:18:20)

scroll_to_index

If I want to scroll to the 100th item the first time, it won't happen because the 100th item hasn't been rendered yet, right? Is there any solution? This library is great. I have given you a little reward

stop scrolling items up at end of list

I have created ExpandableListView with header and have only 4 items in each section. If I collapse all sections and scroll up the list still scroll up and hide above sections below header.

Animation issue, header jumps to top after animation

Hi, thank you for your work on this package.

I noticed an animation issue on larger lists.

  1. set /MockData/.getExampleSections(3, 12);
  2. Open CustomSectionAnimation Example
  3. scroll to bottom
  4. collapse header #2
  5. Note that during the animation header #1 sticks to header #2 until section #2 collapse is finished, after that header #1 jumps to top.

2020-10-06 13 59 32

Cannot use custom model as ExpandableListSection Type

I want to create sectioned list with String as header title and BoardWithCategory as the child

Here is my code

BoardWithcategory model that i want to use as child

class BoardWithCategory {
  final Board board;
  final BoardCategoryData boardCategoryData;

  BoardWithCategory(this.board, this.boardCategoryData);
}

The board section,


class BoardSection implements ExpandableListSection<BoardWithCategory> {
  bool isExpanded;
  List<BoardWithCategory> boardWithCategory = List();
  String title;

  @override
  List<BoardWithCategory> getItems() => boardWithCategory;

  @override
  bool isSectionExpanded() => isExpanded;

  @override
  void setSectionExpanded(bool expanded) {
    this.isExpanded = expanded;
  }
}

How I use this in a page

BlocConsumer.....{

builder: (context, state){
return SliverExpandableList(
                builder: SliverExpandableChildDelegate<String, BoardSection>(
                    sectionList: _sectionList,
                    headerBuilder: _buildHeaderList,
                    controller: _controller,
                    itemBuilder: (context, sectionIndex, itemIndex, index) {
                      BoardWithCategory item = _sectionList[sectionIndex]
                          .boardWithCategory[itemIndex];
                      return ListTile(
                        leading: CircleAvatar(
                          child: Text("$index"),
                        ),
                        title: Text(item.boardCategoryData.name),
                      );
                    }),
              );

}
}

And here is the error
Screenshot from 2020-08-24 13-34-19

The error says
'BoardSection' doesn't extend 'ExpandableListSection'.
Try using a type that is or is a subclass of 'ExpandableListSection'

I already extends the BoardSection with ExpandableListSection not ExpandableListSection,
in the documentation it said that I need diamond interface , for this case im not using String as my model class but I get this error

Not collapse

Im usign the 1.0.0-nullsafety.1 version, the view of items and the sticky header is working fine but when change the param expanded in onTap with:

setState(() { sectionList[sectionIndex].setSectionExpanded(!section.isSectionExpanded()); });
Did not collapse the items.

I debug that the onTap and the changes its applied, when i set initially the expanded true or false its working propertly, the problem is when change it, not trigger nothing.

Anyone more have this problem?

The SliverExpandableList isn't reversible

It looks as if the SliverExpandableList isn't reversible (the ExpandableListView is). Is there a way to get this sort of behaviour (reversing and starting at the bottom)? Thanks!

Jump scroll to header section

Is it possible to scroll the list to a specific index in the header(pinned)?

for example:
scrollControler.jumpTo(sectionIndex);

sorry my bad english

在android设备上运行报错

FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':app:stripDebugDebugSymbols'.

No toolchains found in the NDK toolchains folder for ABI with prefix: arm-linux-androideabi

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

  • Get more help at https://help.gradle.org

BUILD FAILED in 10s
Exception: Gradle task assembleDebug failed with exit code 1

Custom Animation with Sliver not working properly

If I use the exampe_custom_section_animation example and convert it to use a sliver app bar the scroll behaviour of the sections is not working properly

    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            pinned: true,
            floating: true,
            expandedHeight: 200,
            flexibleSpace: FlexibleSpaceBar(
              title: Text("Sliver Example"),
            ),
          ),
          SliverExpandableList(
            builder: SliverExpandableChildDelegate<String, ExampleSection>(
              sectionList: sectionList,
              itemBuilder: (context, sectionIndex, itemIndex, index) {
                String item = sectionList[sectionIndex].items[itemIndex];
                return ListTile(
                  leading: CircleAvatar(
                    child: Text("$index"),
                  ),
                  title: Text(item),
                );
              },
              sectionBuilder: (context, containerInfo) => _SectionWidget(
                section: sectionList[containerInfo.sectionIndex],
                containerInfo: containerInfo,
                onStateChanged: () {
                  //notify ExpandableListView that expand state has changed.
                  WidgetsBinding.instance.addPostFrameCallback((_) {
                    if (mounted) {
                      setState(() {});
                    }
                  });
                },
              ),
            ),
          ),
        ],
      ),
    );

Scroll up first section and then try to open close. It opens and closes but sometimes the section header scrolls up too, which should not happen.

What is the appropriate way to do it?

Migrate to 3.0.0

../../flutter/.pub-cache/hosted/pub.flutter-io.cn/sticky_and_expandable_list-1.0.3/lib/src/expandable_section_container.dart:170:22: Warning: Operand of null-aware operation '?.' has type 'WidgetsBinding' which excludes null.

  • 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../flutter/packages/flutter/lib/src/widgets/binding.dart').
    WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
    ^
    ../../flutter/.pub-cache/hosted/pub.flutter-io.cn/sticky_and_expandable_list-1.0.3/lib/src/sliver_expandable_list.dart:410:22: Warning: Operand of null-aware operation '!' has type 'WidgetsBinding' which excludes null.
  • 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../flutter/packages/flutter/lib/src/widgets/binding.dart').
    WidgetsBinding.instance!.addPostFrameCallback((_) {
    ^

Error NoSuchMethodError in the example

When building any example, an error is written in the debag (I attach the log below). What is the reason for it and how to fix it? When scrolling the list, it is repeated.

Flutter 1.17.0
Dart 2.8.1

debug log

Launching lib/main.dart on iPhone 11 Pro Max in debug mode...
Xcode build done. 9,4s

�[38;5;248m════════ Exception caught by rendering library ═════════════════════════════════�[39;49m
�[38;5;244mThe following NoSuchMethodError was thrown during performLayout():�[39;49m
The method '>' was called on null.
Receiver: null
Tried calling: >(0)

�[38;5;244mThe relevant error-causing widget was�[39;49m
�[38;5;248mExpandableSectionContainer�[39;49m
�[38;5;244mWhen the exception was thrown, this was the stack�[39;49m
�[38;5;244m#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)�[39;49m
�[38;5;248m#1 RenderExpandableSectionContainer.performLayout�[39;49m
�[38;5;244m#2 RenderObject.layout�[39;49m
�[38;5;244m#3 RenderProxyBoxMixin.performLayout�[39;49m
�[38;5;244m#4 RenderObject.layout�[39;49m
�[38;5;244m...�[39;49m
�[38;5;244mThe following RenderObject was being processed when the exception was fired: RenderExpandableSectionContainer#0ab60 relayoutBoundary=up5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mRenderObject: RenderExpandableSectionContainer#0ab60 relayoutBoundary=up5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mneeds compositing�[39;49m
�[38;5;244mparentData: (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(w=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 224.0)�[39;49m
�[38;5;244mchild 1: RenderClipRect#cabbc relayoutBoundary=up6 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mparentData: offset=Offset(0.0, 56.0); id=null (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(0.0<=w<=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 168.0)�[39;49m
�[38;5;244mchild: RenderPositionedBox#807d2 relayoutBoundary=up7 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mparentData: (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(0.0<=w<=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 168.0)�[39;49m
�[38;5;244malignment: AlignmentDirectional.centerStart�[39;49m
�[38;5;244mtextDirection: ltr�[39;49m
�[38;5;244mwidthFactor: expand�[39;49m
�[38;5;244mheightFactor: 1.0�[39;49m
�[38;5;244mchild: RenderFlex#b3e29 relayoutBoundary=up8 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mparentData: offset=Offset(0.0, 0.0) (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(0.0<=w<=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 168.0)�[39;49m
�[38;5;244mdirection: vertical�[39;49m
�[38;5;244mmainAxisAlignment: start�[39;49m
�[38;5;244mmainAxisSize: max�[39;49m
�[38;5;244mcrossAxisAlignment: center�[39;49m
�[38;5;244mverticalDirection: down�[39;49m
�[38;5;244mchild 1: RenderSemanticsAnnotations#16f4f relayoutBoundary=up9 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mparentData: offset=Offset(0.0, 0.0); flex=null; fit=null (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(0.0<=w<=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 56.0)�[39;49m
�[38;5;244mchild 2: RenderSemanticsAnnotations#441e3 relayoutBoundary=up9 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mparentData: offset=Offset(0.0, 56.0); flex=null; fit=null (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(0.0<=w<=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 56.0)�[39;49m
�[38;5;244mchild 3: RenderSemanticsAnnotations#2956d relayoutBoundary=up9 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mparentData: offset=Offset(0.0, 112.0); flex=null; fit=null (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(0.0<=w<=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 56.0)�[39;49m
�[38;5;244mchild 2: _RenderColoredBox#2653f relayoutBoundary=up6 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mparentData: offset=Offset(0.0, 0.0); id=null (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(0.0<=w<=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 56.0)�[39;49m
�[38;5;244mbehavior: opaque�[39;49m
�[38;5;244mchild: RenderSemanticsAnnotations#51d35 relayoutBoundary=up7 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mparentData: (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(0.0<=w<=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 56.0)�[39;49m
�[38;5;244mchild: RenderMouseRegion#d1710 relayoutBoundary=up8 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mparentData: (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(0.0<=w<=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 56.0)�[39;49m
�[38;5;244mlisteners: enter, exit�[39;49m
�[38;5;244mchild: RenderSemanticsGestureHandler#ba4af relayoutBoundary=up9 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE�[39;49m
�[38;5;244mparentData: (can use size)�[39;49m
�[38;5;244mconstraints: BoxConstraints(0.0<=w<=414.0, 0.0<=h<=Infinity)�[39;49m
�[38;5;244msize: Size(414.0, 56.0)�[39;49m
�[38;5;244mgestures: tap�[39;49m
�[38;5;248m════════════════════════════════════════════════════════════════════════════════�[39;49m

�[38;5;248m════════ Exception caught by rendering library ═════════════════════════════════�[39;49m
The method '>' was called on null.
Receiver: null
Tried calling: >(0)
�[38;5;244mThe relevant error-causing widget was�[39;49m
�[38;5;248mExpandableSectionContainer�[39;49m
�[38;5;248m════════════════════════════════════════════════════════════════════════════════�[39;49m

Horizontal Scrolling

Do you have any advice on how to do Horizontal scrolling and also keep the first column fixed?

展开一个Header#0 滑动一点点, 然后展开第二个的时候,Header#1时候,展开不是现实的第一个ListTitle#0这条数据

xin

Hello, I have a situation here. I'm going to expand one Header#0 by sliding a little bit, and then I'm going to expand the second one, and then I'm going to expand the first ListTitle#0 that's not actually real, and occasionally I'm going to flash. Don't know how to solve this?

demo Repetition can be

您好,我这边出现这种情况。展开一个Header#0 滑动一点点, 然后展开第二个的时候,Header#1时候,展开不是现实的第一个ListTitle#0这条数据,偶尔还有闪屏的情况。不知道这个怎么解决?

demo可复现

'Method '_add from Integer' was called on Null' error on launch of the app

This error occurs on every launch of the app, even if there's no SliverExpandableList widget built on the screen.

Screenshot_20200316_181606

Here's the log:

I/flutter ( 5599): The method '_addFromInteger' was called on null.
I/flutter ( 5599): Receiver: null
I/flutter ( 5599): Tried calling: _addFromInteger(1)
I/flutter ( 5599): 
I/flutter ( 5599): The relevant error-causing widget was:
I/flutter ( 5599):   Feed-[LabeledGlobalKey<FeedState>#fb6be]
I/flutter ( 5599):   file:///home/max/%D0%9A%D0%BE%D0%B4/Flutter%20Projects/Feed-master/lib/main.dart:257:15
I/flutter ( 5599): 
I/flutter ( 5599): When the exception was thrown, this was the stack:
I/flutter ( 5599): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
I/flutter ( 5599): #1      int.+ (dart:core-patch/integers.dart:12:38)
I/flutter ( 5599): #2      SliverExpandableChildDelegate._buildSectionRealIndexes (package:sticky_and_expandable_list/src/sliver_expandable_list.dart:168:22)
I/flutter ( 5599): #3      new SliverExpandableChildDelegate (package:sticky_and_expandable_list/src/sliver_expandable_list.dart:69:30)

Sticky header issue in Tab layout

I am trying to implement the ExampleCustomSectionAnimation in a TabLayout

image

But as soon as I scroll and the AppBar collapses the header no longer remains sticky and gets under the AppBar. This AppBar is in the TabLayout Main view

image

But if give another AppBar in the ExampleCustomSectionAnimation list view - In Red over here

image

The header becomes sticky again

image

I want the headers to remain sticky without the additional AppBar (Red),

Thanks for the package, Love it!

The issue can be easily replicated by placing the ExampleCustomSectionAnimation provided in the sample in a TabBarView

MainTabLayout
image

unable to build Error: Method 'addPostFrameCallback' cannot be called on 'WidgetsBinding?' because it is potentially null.

      ] ../../../../.pub-cache/hosted/pub.dartlang.org/sticky_and_expandable_list-1.1.0/lib/src/expandable_section_container.dart:170:31: Error: Method 'addPostFrameCallback' cannot be called on 'WidgetsBinding?' because it is potentially null.
../…/src/expandable_section_container.dart:170
[        ]  - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../../../SDK_all/flutter/packages/flutter/lib/src/widgets/binding.dart').
package:flutter/…/widgets/binding.dart:1

[        ] Try calling using ?. instead.
[        ]       WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
[        ]                               ^^^^^^^^^^^^^^^^^^^^
[        ] ../../../../.pub-cache/hosted/pub.dartlang.org/sticky_and_expandable_list-1.1.0/lib/src/sliver_expandable_list.dart:414:31: Error: Method 'addPostFrameCallback' cannot be called on 'WidgetsBinding?' because it is potentially null.
../…/src/sliver_expandable_list.dart:414
[        ]  - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../../../SDK_all/flutter/packages/flutter/lib/src/widgets/binding.dart').
package:flutter/…/widgets/binding.dart:1
[        ] Try calling using ?. instead.
[        ]       WidgetsBinding.instance.addPostFrameCallback((_) {

Error ''owner!._debugCurrentBuildTarget == this': is not true in Flutter v2.15.1

Another exception was thrown: 'package:flutter/src/widgets/framework.dart': Failed assertion: line 4313 pos 14: 'owner!._debugCurrentBuildTarget == this':
is not true.

Another exception was thrown: 'package:flutter/src/widgets/framework.dart': Failed assertion: line 4313 pos 14: 'owner!._debugCurrentBuildTarget == this':
is not true.
[VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: 'package:flutter/src/widgets/framework.dart': Failed assertion: line 2535 pos 20: '_debugCurrentBuildTarget == context': is not true.
#0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:47:61)
#1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:36:5)
#2 BuildOwner.buildScope. (package:flutter/src/widgets/framework.dart:2535:20)
#3 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2539:12)
#4 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1111:13)
#5 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:944:7)
#6 WidgetsBinding.scheduleAttachRootWidget. (package:flutter/src/widgets/binding.dart:924:7)
#7 _rootRun (dart:async/zone.dart:1420:47)
#8 _CustomZone.run (dart:async/zone.dart:1328:19)
#9 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#10 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1276:23)
#11 _rootRun (dart:async/zone.dart:1428:13)
#12 _CustomZone.run (dart:async/zone.dart:1328:19)
#13 _CustomZone.bindCallback. (dart:async/zone.dart:1260:23)
#14 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15)
#15 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
#16 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
#17 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)

NestedScrollView SliverAppBar and sticky header overlap

This package has been really great for creating complex applications but I've had trouble now implementing the SliverExpandableList with a NestedScrollView. Specifically, the sticky header overlaps with the SliverAppBar I have in the headerSliver section of the NestedScrollView when the pin option is set to true. If I set pin to false there will no longer be any overlap but for the purposes of my application I need the appbar to be pinned.

I saw in another issue someone mentioned something similar and they used a SafeArea widget around the CustomScrollView to circumvent this, however this only fixes this issue when pin is set to false. Similarly, using a regular appbar within the scaffold with the toolbarheight set to 0 has the same effect as using the SafeArea widget. I tested with the example application listed to find a solution to no avail. This is what it looks with a SafeArea widget around the CustomScrollView vs without:

As you can see while the SafeArea widget does fix the header from being trapped in the statusbar, it is now stuck within the sliverappbar.
After reading the NestedScrollView documentation here are the series of steps I've tried:

  1. According to the NestedScrollView documentation, SliverOverlapAbsorber and SliverOverlapInjector should stop the body from scrolling underneath the sliverappbar, however this does not seem to be the case. It still refuses to respect the sliverappbar.

  2. Setting floating to true instead of pinned does not work as intended either. The sliverappbar never appears when scrolling upwards even if I set "floatHeaderSlivers" of NestedScrollView to true.

  3. Setting floating and snapped to true also does not resolve this issue. While it does show the sliverappbar when I scroll up now, it completely overlaps the body. Additionally, setting "floatHeaderSlivers" of NestedScrollView to true with these options does not change this behavior.
    image

Any ideas on how to solve this issue? It would be greatly appreciated. The code below is based off the code from the example in this package.

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var sectionList = MockData.getExampleSections();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        // appBar: AppBar(
        //   toolbarHeight: 0,
        // ),
        body: NestedScrollView(
          // floatHeaderSlivers: true,
          headerSliverBuilder: (context, innerBoxIsScrolled) => [
            // SliverOverlapAbsorber(
            //   handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
            //   sliver:
            SliverAppBar(
              backgroundColor: Colors.transparent,
              // pinned: true,
              floating: true,
              snap: true,
              expandedHeight: 200,
              flexibleSpace: FlexibleSpaceBar(
                title: Text("Sliver Example"),
              ),
            ),
            // ),
          ],
          body: SafeArea(
            child: Builder(
              builder: (context) => CustomScrollView(
                slivers: <Widget>[
                  // SliverOverlapInjector(
                  //   handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                  //       context),
                  // ),
                  SliverExpandableList(
                    builder:
                        SliverExpandableChildDelegate<String, ExampleSection>(
                      sectionList: sectionList,
                      headerBuilder: _buildHeader,
                      itemBuilder: (context, sectionIndex, itemIndex, index) {
                        String item =
                            sectionList[sectionIndex].items[itemIndex];
                        return ListTile(
                          leading: CircleAvatar(
                            child: Text("$index"),
                          ),
                          title: Text(item),
                        );
                      },
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
[√] Flutter (Channel stable, 1.22.2, on Microsoft Windows [Version 10.0.19041.610], locale en-US)
    • Flutter version 1.22.2 at C:\flutter
    • Framework revision 84f3d28555 (3 weeks ago), 2020-10-15 16:26:19 -0700
    • Engine revision b8752bbfff
    • Dart version 2.10.2

 
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at C:\Users\aaqib\AppData\Local\Android\sdk
    • Platform android-30, build-tools 30.0.2
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
    • All Android licenses accepted.

[!] Android Studio (version 4.1.0)
    • Android Studio at C:\Program Files\Android\Android Studio
    X Flutter plugin not installed; this adds Flutter specific functionality.
    X Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)

[√] VS Code (version 1.50.1)
    • VS Code at C:\Users\aaqib\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.16.0

[√] Connected device (1 available)
    • sdk gphone x86 (mobile) • emulator-5554 • android-x86 • Android 11 (API 30) (emulator)

! Doctor found issues in 1 category.

Performance issue

All item in ExampleSection.items will call initState at once time, although the item is not visible.
This will affect the smoothness of scrolling and the expanded/collapse action.

The example code as follow, the ExampleSection.items size set to 50.

  @override
  Widget build(BuildContext context) {
    //In this example, we create a custom model class(ExampleSection).
    //class ExampleSection implements ExpandableListSection<String> {}
    //so: SliverExpandableChildDelegate<String, ExampleSection>()
    return Scaffold(
        appBar: AppBar(title: Text("ListView Example")),
        body: ExpandableListView(
          builder: SliverExpandableChildDelegate<String, ExampleSection>(
              sectionList: sectionList,
              headerBuilder: _buildHeader,
              itemBuilder: (context, sectionIndex, itemIndex, index) {
                String item = sectionList[sectionIndex].items[itemIndex];
                return ListItem(index, item);

              }),
        ));
  }

class ListItem extends StatefulWidget {
  final int index;
  final String item;

  ListItem(this.index, this.item);

  @override
  _ListItemState createState() => _ListItemState();
}

class _ListItemState extends State<ListItem> {
  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: CircleAvatar(
        child: Text("${widget.index}"),
      ),
      title: Text(widget.item),
    );
  }

  @override
  void initState() {
    print("tiger-test initState: ${widget.index}");
    super.initState();
  }

  @override
  void dispose() {
    print("tiger-test dispose: ${widget.index}");
    super.dispose();
  }
}

The log:
I/flutter (16350): tiger-test initState: 1
I/flutter (16350): tiger-test initState: 2
...
省略
...
I/flutter (16350): tiger-test initState: 49
I/flutter (16350): tiger-test initState: 50

type 'List<Widget?>' is not a subtype of type 'List<Widget>' in type cast

Get this error on line 260 of sliver_expandable_list.dart

  ///By default, build a Column widget for layout all children's size.
  static Widget buildDefaultContent(
      BuildContext context, ExpandableSectionContainerInfo containerInfo) {
    var childDelegate = containerInfo.childDelegate!;
    var children = List<Widget?>.generate(childDelegate.childCount!,
        (index) => childDelegate.builder(context, index));
    return Column(
      children: children as List<Widget>, //line 260
    );
  }

sliver sticky header does not work?

Hi, I use ExampleSliver code, sticky header does not work?

XRecorder_15072022_143553.mp4

`import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:secuxtwallet/controller/gallery_controller.dart';
import 'package:secuxtwallet/model/secux_asset.dart';
import 'package:secuxtwallet/model/secux_collection.dart';
import 'package:secuxtwallet/util/socket_io_client.dart';
import 'package:sticky_and_expandable_list/sticky_and_expandable_list.dart';

class ExampleSliver extends StatefulWidget {
@OverRide
_ExampleSliverState createState() => _ExampleSliverState();
}

class _ExampleSliverState extends State {
final controller = Get.find();
final sectionList = [];
final expandableListController = ExpandableListController();
final socketIoClient = SocketIoClient();
final collectionMap = <String, List>{}.obs;
final collections = SecuXCollectionsResponse(count: '', dataList: [], isCompleted: false).obs;
final isScanning = true.obs;

@OverRide
initState() {
super.initState();
Future.delayed(Duration(seconds: 1), () async {
await socketIoClient.getNFTCollectionsByOwner(
collections, 'eth,bsc,polygon', '0xa96F57429c77352d625A3F57a94eC27C6c128f5D', '300');
await socketIoClient.getCollectionNFTsByOwner(
collectionMap, isScanning, 'eth,bsc,polygon', '0xa96F57429c77352d625A3F57a94eC27C6c128f5D', '', '50');

  while (isScanning.isTrue) {
    await Future.delayed(const Duration(seconds: 1), null);
  }
  for (final collection in collections.value.dataList) {
    ExampleSection section = ExampleSection();
    section.header = collection.collectionName;
    section.items =
        collectionMap['${collection.chain}_${collection.slug}']?.map((e) => e.imageName).toList() ?? <String>[];
    section.expanded = true;
    setState(() {
      sectionList.add(section);
    });
  }
});

}

@OverRide
Widget build(BuildContext context) {
return sectionList.isEmpty
? const SafeArea(child: Scaffold(body: Text('1111')))
: SafeArea(
child: Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
floating: true,
expandedHeight: 50,
flexibleSpace: FlexibleSpaceBar(
title: Text(
"Sliver Example",
style: TextStyle(color: Colors.white),
),
),
iconTheme: IconThemeData(color: Colors.white),
),
SliverExpandableList(
builder: SliverExpandableChildDelegate<String, ExampleSection>(
sectionList: sectionList,
headerBuilder: _buildHeader,
itemBuilder: (context, sectionIndex, itemIndex, index) {
String item = sectionList[sectionIndex].items[itemIndex];
return ListTile(
leading: CircleAvatar(
child: Text("$index"),
),
title: Text(item),
);
},
),
),
],
),
),
);
}

Widget _buildHeader(BuildContext context, int sectionIndex, int index) {
ExampleSection section = sectionList[sectionIndex];
return InkWell(
child: Container(
color: Colors.lightBlue,
height: 48,
padding: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
child: Text(
section.header,
style: TextStyle(color: Colors.white),
)),
onTap: () {
//toggle section expand state
setState(() {
section.setSectionExpanded(!section.isSectionExpanded());
});
});
}
}

class ExampleSection implements ExpandableListSection {
//store expand state.
late bool expanded;

//return item model list.
late List items;

//example header, optional
late String header;

@OverRide
List getItems() {
return items;
}

@OverRide
bool isSectionExpanded() {
return expanded;
}

@OverRide
void setSectionExpanded(bool expanded) {
this.expanded = expanded;
}
}
`

Weird behavior of header item

I have some weird behavior.
If I scroll into some particular position like this gif below,
the header will move from top to the position where i click last item/position

ezgif com-video-to-gif (2)

Adding a separatorBuilder to the package's ListView example causes overlapping items

The argument passed to SliverExpandableChildDelegate:
separatorBuilder: (context, isHeader, index) { return Container(); },

Steps to reproduce:

  1. Expand some headers (Including header 0 and header 1 to allow scrolling.
  2. Close Header 0
  3. Expand Header 0
  4. Scroll down
    This will make header 1's items overlap with header 0

Visual:

issue_visual_example

Tested on:
Flutter 2.5.3, sticky_and_expandable_list: 1.0.2,
Android phone and Chrome.

Error '_debugCanPerformMutations': is not true in Flutter v2.5.1

An assertion is being thrown when opening a collapsed header using the latest stable Flutter version, v2.5.1.

Error description

════════ Exception caught by scheduler library ═════════════════════════════════
The following assertion was thrown during a scheduler callback:
'package:flutter/src/rendering/object.dart': Failed assertion: line 1607 pos 12: '_debugCanPerformMutations': is not true.
2

Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.md

When the exception was thrown, this was the stack
#2      RenderObject.markNeedsLayout  package:flutter/…/rendering/object.dart:1607
#3      RenderBox.markNeedsLayout  package:flutter/…/rendering/box.dart:2320
#4      RenderExpandableSectionContainer.scrollable=.<anonymous closure> 
 package:sticky_and_expandable_list/src/expandable_section_container.dart:171
#5      SchedulerBinding._invokeFrameCallback  package:flutter/…/scheduler/binding.dart:1143
#6      SchedulerBinding.handleDrawFrame  package:flutter/…/scheduler/binding.dart:1088
#7      SchedulerBinding._handleDrawFrame  package:flutter/…/scheduler/binding.dart:996
#11     _invoke (dart:ui/hooks.dart:166:10)
#12     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
#13     _drawFrame (dart:ui/hooks.dart:129:31)
(elided 5 frames from class _AssertionError and dart:async)
════════════════════════════════════════════════════════════════════════════════

Steps to reproduce it

Use the example project and run it using Flutter 2.5.1. In any of the examples, collapse any header and open it again. It will throw an error.

The error happens in both iOS simulator and Android emulator. I checked it also happens if you are debugging from a real iOS device.

My configuration

> flutter --version
Flutter 2.5.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision ffb2ecea52 (9 days ago) • 2021-09-17 15:26:33 -0400
Engine • revision b3af521a05
Tools • Dart 2.14.2
Error.mp4

Expand/Collapse All - New feature request

First of all thanks you for this library. I have been waiting for one of these for quite some time :-)

One thing I think would be very useful is to the ability to expand/collapse all sections at the same time so the user does not have to do it one by one which is quite tedious especially for longer lists.

Sticky side menu

Hello, is there a way to create side menu with all header items on side to have quick navigation?
something like azlistview has.

Customize section class

You can define an section class as you like, the only requirement is implement ExpandableListSection, this is to provide item data list in section. Like this:

class Section implements ExpandableListSection<Widget> {
  bool expanded;
  Widget header;
  List<Widget> items;

  @override
  List<Widget> getItems() {
    return items;
  }

  @override
  bool isSectionExpanded() {
    return expanded;
  }

  @override
  void setSectionExpanded(bool expanded) {
    this.expanded = expanded;
  }
}
``

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.