Flutter - how using SliverAppBar with Infinite Scroll Pagination?
Asked Answered
I

4

9

I using Infinite Scroll Pagination plugin in my flutter's app. I need also using SilverAppBar in my page. This is my code:

return Scaffold(
  body: DefaultTabController(
    length: 2,
    child: NestedScrollView(
      headerSliverBuilder: (context, value) {
        return [
          SliverAppBar(
            bottom: TabBar(
              tabs: [
                Tab(icon: Icon(Icons.call), text: "1"),
                Tab(icon: Icon(Icons.message), text: "2"),
              ],
            ),
          ),
        ];
      },
      body: TabBarView(
        children: [
          const MyListWidget()
          Text('2')
        ],
      ),
    ),
  ),
);

this is my MyListWidget:

Widget build(BuildContext context) {
return PagedSliverList<int, MyModel>(
      pagingController: _сontroller,
      builderDelegate: PagedChildBuilderDelegate<MyModel>(
        itemBuilder: (context, item, index) {
          return Text(item.Title);
        },
      ),
    );
  }

But I have error:

A RenderRepaintBoundary expected a child of type RenderBox but received a child of type RenderSliverList.

Also I tried:

body: SliverFillRemaining(
            child: TabBarView(
              children: [
                const ProfileSelections(),
                //Container(child: Text('1')),
                Text('2')
              ],
            ),
          )

Than but I have error:

 A RenderSliverFillRemainingWithScrollable expected a child of type RenderBox but received a child of type RenderSliverFillRemainingWithScrollable.

how can I fix these errors? any advice - I will be grateful

Interesting answered 15/12, 2021 at 20:7 Comment(1)
Can you please share what are you trying to get actually?Fuzz
C
12

No need to use the Infinite scroll pagination, you can simply do with the flutter built-in scroll notification.

Scroll notification - abstract class ScrollNotification extends LayoutChangedNotification with ViewportNotificationMixin.

A Notification related to scrolling.

Scrollable widgets notify their ancestors about scrolling-related changes.

The notifications have the following lifecycle:

  • A ScrollStartNotification, which indicates that the widget has started scrolling.

  • Zero or more ScrollUpdateNotifications, which indicate that the widget has changed its scroll position, mixed with zero or more

  • OverscrollNotifications, which indicate that the widget has not changed its scroll position because the change would have caused its scroll position to go outside its scroll bounds.Interspersed with the ScrollUpdateNotifications and OverscrollNotifications are zero or more UserScrollNotifications, which indicate that the user has changed the direction in which they are scrolling.

  • A ScrollEndNotification, which indicates that the widget has stopped scrolling.

  • A UserScrollNotification, with a UserScrollNotification.direction of ScrollDirection.idle.

Here is the complete source code with explanations

import 'package:flutter/material.dart';

class InfiniteScrollPagination extends StatefulWidget {
  const InfiniteScrollPagination({Key key}) : super(key: key);

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

class _InfiniteScrollPaginationState extends State<InfiniteScrollPagination> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: DefaultTabController(
        length: 2,
        child: NestedScrollView(
          headerSliverBuilder: (context, value) {
            return [
              SliverAppBar(
                pinned: true,
                toolbarHeight: 0,
                bottom: TabBar(
                  tabs: [
                    Tab(icon: Icon(Icons.call), text: "1"),
                    Tab(icon: Icon(Icons.message), text: "2"),
                  ],
                ),
              ),
            ];
          },
          body: TabBarView(
            children: [MyListWidget(), Text('2')],
          ),
        ),
      ),
    );
  }
}

class MyListWidget extends StatefulWidget {
  const MyListWidget({Key key}) : super(key: key);

  @override
  State<MyListWidget> createState() => _MyListWidgetState();
}

class _MyListWidgetState extends State<MyListWidget> {
  int count = 15;

  @override
  Widget build(BuildContext context) {
    return NotificationListener<ScrollNotification>(
      onNotification: (ScrollNotification scrollInfo) {
        if (scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
          // here you update your data or load your data from network
          setState(() {
            count += 10;
          });
        }
        return true;
      },
      // if you used network it would good to use the stream or future builder
      child: Container(
        child: getDataList(count),
      ),
    );
  }
}

getDataList(listOfData) {
  return ListView.separated(
      itemBuilder: (context, index) {
        return ListTile(
          title: Text("index $index"),
        );
      },
      separatorBuilder: (context, index) => Divider(
        thickness: 2,
        color: Colors.grey,
      ),
      itemCount: listOfData);
}

output:

enter image description here

Cottbus answered 20/12, 2021 at 21:56 Comment(1)
Best solution to the pagination, thanks a lot. I had an implementation where i added a listener to the scroll controller, but it was buggy.Qianaqibla
S
2

it's happening because tabBarView needs normal box children rather than slivers because it uses pageview by default as you can read here in official documentation.

if you use normal list instead of slivers like below it will solve the problem:

Widget build(BuildContext context) {
return  PagedListView<int, MyModel>(
      pagingController: _сontroller,
      builderDelegate: PagedChildBuilderDelegate<MyModel>(
        itemBuilder: (context, item, index) {
          return Text(item.Title);
        },
      ),
    );
  }
Stormie answered 20/12, 2021 at 4:9 Comment(0)
H
1

Using PagedListView instead of PagedSliverList would solve the issue. Slivers are not widgets and Slivers are rendered in a different manner. we mostly use Slivers in CustomScrollView widget.

Hadron answered 21/12, 2021 at 13:9 Comment(0)
O
-1

I implemented infinite scroll with a SliverAppBar and SliverList.separated(). I wrapped them in NotificationListener<ScrollNotification> like below and it all works nicely:

NotificationListener<ScrollNotification>(
  onNotification: (scrollNotification) {
  if (scrollNotification is ScrollEndNotification) {
    onScrollListener();
  }

  return true;
}

void onScrollListener() {
  if (reachedEnd) {
    return;
  }

  if (!isPageLoading) {
    isPageLoading = true;
    Future.microtask(() async {
      final newItems = await getItemsUseCase.get(page: nextPage);
      if (newItems.length < pageSize) {
        reachedEnd= true;
      } else {
        nextPage++;
      }

      allItems.addAll(newItems);
      isPageLoading = false;
    });
  }
}

I've added a complete code example here.

Orchidaceous answered 31/1 at 8:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.