Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RefreshIndicator with NestedScrollview

Tags:

flutter

dart

I want 2 tab pages with a ListView each to share a single RefreshIndicator. However, a RefreshIndicator must have Scrollable as a child (which a TabBarView isn't) so instead I tried making 2 RefreshIndicators per tab as shown in the code below.

But this brings a different problem, I also wanted a floating AppBar which meant I had to use a NestedScrollView. So as a result I end up triggering both RefreshIndicators' onRefresh method whenever I scroll down. Whereas I only need one to refresh.

import 'package:flutter/material.dart';

main() {
    runApp(
        MaterialApp(
            home: DefaultTabController(
                length: 2,
                child: Scaffold(
                    body: NestedScrollView(
                        headerSliverBuilder: (context, innerBoxIsScrolled) {
                            return [
                                SliverAppBar(
                                    floating: true,
                                    snap: true,
                                    bottom: TabBar(
                                        tabs: [
                                            Tab(text: 'Page1'),
                                            Tab(text: 'Page2'),
                                        ],
                                    ),
                                ),
                            ];
                        },
                        body: TabBarView(
                            children: [
                                Page(1),
                                Page(2),
                            ],
                        ),
                    ),
                ),
            ),
        ),
    );
}

class Page extends StatefulWidget {
    final pageNumber;
    Page(this.pageNumber);
    createState() => PageState();
}

class PageState extends State<Page> with AutomaticKeepAliveClientMixin {
    get wantKeepAlive => true;

    build(context){
        super.build(context);
        return RefreshIndicator(
            onRefresh: () => Future(() async {
                print('Refreshing page no. ${widget.pageNumber}');  // This prints twice once both tabs have been opened
                await Future.delayed(Duration(seconds: 5));
            }),
            child: ListView.builder(
                itemBuilder: ((context, index){
                    return ListTile(
                        title: Text('Item $index')
                    );
                }),
            )
        );
    }
}

The AutomaticKeepAliveClientMixin is there to prevent the pages rebuilding every time I switch tabs as this would be an expensive process in my actual app.

A solution that uses a single RefreshIndicator for both tabs would be most ideal, but any help is appreciated.

like image 519
Steelsmasher Avatar asked Sep 10 '18 19:09

Steelsmasher


People also ask

What is NestedScrollView flutter?

The Flutter documentation defines NestedScrollView as “A scrolling view inside of which can be nested other scrolling views, with their scroll positions being intrinsically linked.” This means that with NestedScrollView , you get two scrolling areas. One is the header part and the other is its body part.

What is RefreshIndicator flutter?

RefreshIndicator class Null safety. A widget that supports the Material "swipe to refresh" idiom.

How do you refresh API in flutter?

This is a simple way to do it. RefreshIndicator( onRefresh: () { setState((){ // Update your data here }); }, child: ... ) Give me some examples for complete code or links to set 'setState' in a flutter.


1 Answers

This code is working for me, it's mostly built on top of @Nuts answer, but it needed some tweaking and my edit was rejected

DefaultTabController(
      length: tabs.length,
      child: RefreshIndicator(
        notificationPredicate: (notification) {
          // with NestedScrollView local(depth == 2) OverscrollNotification are not sent
          return notification.depth == 2;
        },
        onRefresh: () => Future.value(null),
        child: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return [
              SliverAppBar(...)
            ];
          },
          body: TabBarView(
            children: tabs,
          ),
        ),
      ),
    )
like image 184
Basel Abuhadrous Avatar answered Oct 06 '22 13:10

Basel Abuhadrous