Need help with loading_more_list?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

fluttercandies
154 Stars 24 Forks MIT License 46 Commits 1 Opened issues

Description

A loading more list which supports ListView,GridView,WaterfallFlow and Slivers.

Services available

!
?

Need anything else?

Contributors list

loadingmorelist

A loading more list which supports ListView,GridView,WaterfallFlow and Slivers.

pub package GitHub stars GitHub forks GitHub license GitHub issues flutter-candies

Language: English | 中文简体

Web demo for LoadingMoreList

Use

  • add library to your pubspec.yaml
dependencies:
  loading_more_list: any

  • import library in dart file
  import 'package:loading_more_list/loading_more_list.dart';

Prepare Data Collection

LoadingMoreBase is data collection for loading more. override loadData method to load your data. set hasMore to false when it has no more data.

class TuChongRepository extends LoadingMoreBase {
  int pageindex = 1;
  bool _hasMore = true;
  bool forceRefresh = false;
  @override
  bool get hasMore => (_hasMore && length < 30) || forceRefresh;

@override Future refresh([bool clearBeforeRequest = false]) async { _hasMore = true; pageindex = 1; //force to refresh list when you don't want clear list before request //for the case, if your list already has 20 items. forceRefresh = !clearBeforeRequest; var result = await super.refresh(clearBeforeRequest); forceRefresh = false; return result; }

@override Future loadData([bool isloadMoreAction = false]) async { String url = ""; if (this.length == 0) { url = "https://api.tuchong.com/feed-app"; } else { int lastPostId = this[this.length - 1].postId; url = "https://api.tuchong.com/feed-app?post_id=$lastPostId&page=$pageindex&type=loadmore"; } bool isSuccess = false; try { //to show loading more clearly, in your app,remove this await Future.delayed(Duration(milliseconds: 500));

  var result = await HttpClientHelper.get(url);

  var source = TuChongSource.fromJson(json.decode(result.body));
  if (pageindex == 1) {
    this.clear();
  }
  for (var item in source.feedList) {
    if (item.hasImage &amp;&amp; !this.contains(item) &amp;&amp; hasMore) this.add(item);
  }

  _hasMore = source.feedList.length != 0;
  pageindex++;
  isSuccess = true;
} catch (exception, stack) {
  isSuccess = false;
  print(exception);
  print(stack);
}
return isSuccess;

} }

Argument

almost of arguments are the same as official.

following arguments are made for loading more.

ListConfig and SliverListConfig

| argument | description | default | | -------------------- | ------------------------------------------------------------------------------ | ------------------------ | | itemBuilder | The item builder of list. | required | | sourceList | The source list of data which extends LoadingMoreBase. | required | | showGlowLeading | Whether to show the overscroll glow on the side with negative scroll offsets. | 0.0 | | showGlowTrailing | Whether to show the overscroll glow on the side with positive scroll offsets. | - | | lastChildLayoutType | Layout type of last child(loadmore/no more item). | LastChildLayoutType.foot | | extendedListDelegate | The delegate for WaterfallFlow or ExtendedList. | - | | gridDelegate | The delegate for GridView. | - | | indicatorBuilder | widget builder for different loading state. | IndicatorWidget | | padding | The amount of space by which to inset the child sliver for SliverListConfig | - | | childCountBuilder | The builder to get child count, the input is sourceList.length | - |

Widget

LoadingMoreList

| argument | description | default | | -------------------- | ---------------------------------------------------------------------------------------------- | -------- | | listConfig | ListConfig | required | | onScrollNotification | Called when a ScrollNotification of the appropriate type arrives at this location in the tree. | - |

LoadingMoreSliverList

| argument | description | default | | ---------------- | ------------------- | -------- | | sliverListConfig | SliverListConfig | required |

LoadingMoreCustomScrollView

| argument | description | default | | ----------------------- | ---------------------------------------------------------------------------------------------- | ------- | | onScrollNotification | Called when a ScrollNotification of the appropriate type arrives at this location in the tree. | - | | rebuildCustomScrollView | in NestedScrollView, rebuild CustomScrollView, viewport can be computed again. | false |

ListView

            LoadingMoreList(
              ListConfig(
                itemBuilder: ItemBuilder.itemBuilder,
                sourceList: listSourceRepository,
                padding: EdgeInsets.all(0.0),
              ),
            ),

GridView

define GridView with gridDelegate argument.

            LoadingMoreList(
              ListConfig(
                itemBuilder: ItemBuilder.itemBuilder,
                sourceList: listSourceRepository,
                padding: EdgeInsets.all(0.0),
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 2,
                  crossAxisSpacing: 3.0,
                  mainAxisSpacing: 3.0,
                ),
              ),
            ),

WaterfallFlow

define WaterfallFlow with waterfallFlowDelegate argument.

            LoadingMoreList(
              ListConfig(
                extendedListDelegate: SliverWaterfallFlowDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 2,
                  crossAxisSpacing: 5,
                  mainAxisSpacing: 5,
                ),
                itemBuilder: _buildItem,
                sourceList: listSourceRepository,
                padding: EdgeInsets.all(5.0),
              ),
            ),

Sliver/CustomScrollView

| | | | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |

following codes are show how to build loading more list within CustomScrollView.

      LoadingMoreCustomScrollView(
        slivers: [
          SliverAppBar(
            pinned: true,
            title: Text("MultipleSliverDemo"),
          ),
          ///SliverList
          LoadingMoreSliverList(SliverListConfig(
            itemBuilder: ItemBuilder.itemBuilder,
            sourceList: listSourceRepository,
          )),
          SliverToBoxAdapter(
            child: Container(
              alignment: Alignment.center,
              child: Text("Next list"),
              color: Colors.blue,
              height: 100.0,
            ),
          ),
          ///SliverGrid
          LoadingMoreSliverList(
            SliverListConfig(
              itemBuilder: ItemBuilder.itemBuilder,
              sourceList: listSourceRepository1,
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 3.0,
                mainAxisSpacing: 3.0,
              ),
            ),
          ),
          SliverPersistentHeader(
            delegate: CommonExtentSliverPersistentHeaderDelegate(
                Container(
                  alignment: Alignment.center,
                  child: Text("Pinned Content"),
                  color: Colors.red,
                ),
                100.0),
            pinned: true,
          ),
          ///SliverWaterfallFlow
          LoadingMoreSliverList(
            SliverListConfig(
              itemBuilder: buildWaterfallFlowItem,
              sourceList: listSourceRepository2,
              padding: EdgeInsets.symmetric(horizontal: 5.0),
              extendedListDelegate: SliverWaterfallFlowDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 5,
                mainAxisSpacing: 5,
              ),
            ),
          ),
        ],
      ),

IndicatorStatus

| | | | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |

define loading status with indicatorBuilder argument.

        enum IndicatorStatus {
          None,
          LoadingMoreBusying,
          FullScreenBusying,
          Error,
          FullScreenError,
          NoMoreLoad,
          Empty
        }
      LoadingMoreList(
        ListConfig(
          itemBuilder: ItemBuilder.itemBuilder,
          sourceList: listSourceRepository,
          indicatorBuilder: _buildIndicator,
          padding: EdgeInsets.all(0.0),
        ),
      ),

//you can use IndicatorWidget or build yourself widget //in this demo, we define all status. Widget _buildIndicator(BuildContext context, IndicatorStatus status) { //if your list is sliver list ,you should build sliver indicator for it //isSliver=true, when use it in sliver list bool isSliver = false;

Widget widget;
switch (status) {
  case IndicatorStatus.None:
    widget = Container(height: 0.0);
    break;
  case IndicatorStatus.LoadingMoreBusying:
    widget = Row(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <widget>[
        Container(
          margin: EdgeInsets.only(right: 5.0),
          height: 15.0,
          width: 15.0,
          child: getIndicator(context),
        ),
        Text("正在加载...不要着急")
      ],
    );
    widget = _setbackground(false, widget, 35.0);
    break;
  case IndicatorStatus.FullScreenBusying:
    widget = Row(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <widget>[
        Container(
          margin: EdgeInsets.only(right: 0.0),
          height: 30.0,
          width: 30.0,
          child: getIndicator(context),
        ),
        Text("正在加载...不要着急")
      ],
    );
    widget = _setbackground(true, widget, double.infinity);
    if (isSliver) {
      widget = SliverFillRemaining(
        child: widget,
      );
    } else {
      widget = CustomScrollView(
        slivers: <widget>[
          SliverFillRemaining(
            child: widget,
          )
        ],
      );
    }
    break;
  case IndicatorStatus.Error:
    widget = Text(
      "好像出现了问题呢?",
    );
    widget = _setbackground(false, widget, 35.0);

    widget = GestureDetector(
      onTap: () {
        listSourceRepository.errorRefresh();
      },
      child: widget,
    );

    break;
  case IndicatorStatus.FullScreenError:
    widget = Text(
      "好像出现了问题呢?",
    );
    widget = _setbackground(true, widget, double.infinity);
    widget = GestureDetector(
      onTap: () {
        listSourceRepository.errorRefresh();
      },
      child: widget,
    );
    if (isSliver) {
      widget = SliverFillRemaining(
        child: widget,
      );
    } else {
      widget = CustomScrollView(
        slivers: <widget>[
          SliverFillRemaining(
            child: widget,
          )
        ],
      );
    }
    break;
  case IndicatorStatus.NoMoreLoad:
    widget = Text("没有更多的了。。不要拖了");
    widget = _setbackground(false, widget, 35.0);
    break;
  case IndicatorStatus.Empty:
    widget = EmptyWidget(
      "这里是空气!",
    );
    widget = _setbackground(true, widget, double.infinity);
    if (isSliver) {
      widget = SliverToBoxAdapter(
        child: widget,
      );
    } else {
      widget = CustomScrollView(
        slivers: <widget>[
          SliverFillRemaining(
            child: widget,
          )
        ],
      );
    }
    break;
}
return widget;

}

CollectGarbage

track the indexes are collect, you can collect garbage at that monment(for example Image cache)

more detail

        LoadingMoreList(
          ListConfig(
            extendedListDelegate: ExtendedListDelegate(
              collectGarbage: (List indexes) {
                ///collectGarbage
              },
            ),
          ),
        ),

ViewportBuilder

track the indexes go into the viewport, it's not include cache extent.

        LoadingMoreList(
          ListConfig(
            extendedListDelegate: ExtendedListDelegate(
              viewportBuilder: (int firstIndex, int lastIndex) {
                print('viewport : [$firstIndex,$lastIndex]');
              },
            ),
          ),
        ),

LastChildLayoutType

build lastChild as special child in the case that it is loadmore/no more item.

        enum LastChildLayoutType {
        /// as default child
        none,

    /// follow max child trailing layout offset and layout with full cross axis extent
    /// last child as loadmore item/no more item in [ExtendedGridView] and [WaterfallFlow]
    /// with full cross axis extend
    fullCrossAxisExtent,

    /// as foot at trailing and layout with full cross axis extend
    /// show no more item at trailing when children are not full of viewport
    /// if children is full of viewport, it's the same as fullCrossAxisExtent
    foot,
    }

CloseToTrailing

when reverse property of List is true, layout is as following. it likes chat list, and new session will insert to zero index. but it's not right when items are not full of viewport.

     trailing
-----------------
|               |
|               |
|     item2     |
|     item1     |
|     item0     |
-----------------
     leading

to solve it, you could set closeToTrailing to true, layout is as following. support [ExtendedGridView],[ExtendedList],[WaterfallFlow]. and it also works when reverse is flase, layout will close to trailing.

     trailing
-----------------
|     item2     |
|     item1     |
|     item0     |
|               |
|               |
-----------------
     leading
      LoadingMoreList(
        ListConfig(
          extendedListDelegate: ExtendedListDelegate(
            closeToTrailing: true
          ),
        ),
      ),

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.