Skip to content

Instantly share code, notes, and snippets.

@IkhwanSI13
Last active October 4, 2024 13:05
Show Gist options
  • Save IkhwanSI13/eb09a588096db4c88f96ad9f2faf91d1 to your computer and use it in GitHub Desktop.
Save IkhwanSI13/eb09a588096db4c88f96ad9f2faf91d1 to your computer and use it in GitHub Desktop.
load more data in NestedScrollView with NotificationListener
import 'package:cartenz_djp/style/colors.dart';
import 'package:cartenz_djp/widget/override/customTabs.dart' as Tabs;
import 'package:flutter/material.dart';
class ExampleWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() => ExampleState();
}
class ExampleState extends State<ExampleWidget> {
onLoadMore() {
//Load More, do something
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ColorWhite,
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Builder(builder: (BuildContext context) {
return NestedScrollView(
//controller: scrollController,
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
bottom: getTabHeader(),
)
];
}, body: Builder(builder: (BuildContext context) {
return Stack(children: <Widget>[
getTabBody(),
]);
}));
}),
)
],
),
);
}
Widget getTabHeader() {
return Tabs.TabBar(tabs: [
Tabs.Tab(child: Text("Tab 1")),
Tabs.Tab(child: Text("Tab 2")),
Tabs.Tab(child: Text("Tab 3")),
]);
}
Widget getTabBody() {
return Column(
children: <Widget>[
Expanded(
child: Tabs.TabBarView(children: [
Container(
child:
//Solved with this
NotificationListener<ScrollNotification>(
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: ListView.builder(
shrinkWrap: true,
itemCount: 3,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return Container();
})),
onNotification: (ScrollNotification scrollInfo) {
if (scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
//load more here
onLoadMore();
}
return false;
},
);
Container(child: Container()),
Container(child: Container())
]))
],
);
}
}
@IkhwanSI13
Copy link
Author

This does not trigger NestedScrollView. SliverAppbar does not get collapsed

In case someone stumbles upon this, you can wrap your inner ListView with a NotificationListener() and check if the Notification is an OverScrollNotification. This is how I got around the issue. As opposed to the solution described above (so no SingleChildScrollView and no Scrollcontroller inside your ListView)

I tried it, and it's work. thanks, dude

@fahadadnaan
Copy link

fahadadnaan commented Mar 29, 2020

@IkhwanSI13 Please can you share your code i have the same issue.

   return Scaffold(
     appBar: AppBar(
       iconTheme: IconThemeData(
         color: Color(0xFF6991C7),
       ),
       title: Text(
         "Search",
         style: TextStyle(
             fontWeight: FontWeight.w700,
             fontSize: 18.0,
             color: Colors.black54,
             fontFamily: "Gotik"),
       ),
       centerTitle: true,
       backgroundColor: Colors.white,
       elevation: 0.0,
     ),
     body: SingleChildScrollView(
       primary: false,
       child: Container(
         color: Colors.white,
         padding: EdgeInsets.only(top: 15.0, bottom: 30.0),
         child:  Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: <Widget>[
             _textHello,
             BlocListener<FilterBloc, FilterState>(
               listener: (context, state) {
                 if (state is ErrorFilter) {
                   Scaffold.of(context).showSnackBar(
                     SnackBar(
                       content: Text(state.message),
                     ),
                   );
                 }
               },
               child: BlocBuilder<FilterBloc, FilterState>(
                 // ignore: missing_return
                 builder: (context, state) {
                   if (state is InitialFilter) {
                     return buildInitialInput();
                   } else if (state is LoadingFilter) {
                     return buildLoading();
                   } else if (state is LoadedFilter) {
                     if (state.products.isEmpty) {
                       return Column(
                         crossAxisAlignment: CrossAxisAlignment.center,
                         children: <Widget>[
                           ProductInputField(),
                           SizedBox(height: 30.0),
                           Center(child: Text('No content'))
                         ],
                       );
                     }
                     return Column(
                       children: <Widget>[
                         ProductInputField(),
                         SizedBox(height: 30.0),
                         NotificationListener<ScrollNotification>(
                           onNotification: (notification) => _onScrollNotification(notification, state),
                           child: GridView.builder(
                             physics: ScrollPhysics(),
                             itemCount: state.products.length,
                             primary: false,
                             shrinkWrap: true,
                             gridDelegate:
                             SliverGridDelegateWithFixedCrossAxisCount(
                               crossAxisSpacing: 10.0,
                               mainAxisSpacing: 10.0,
                               childAspectRatio: 0.605,
                               crossAxisCount: 2,
                             ),
                             itemBuilder: (context, pos) {
                               return ProductWidget(product: state.products[pos]);
                             },
                           ),
                         ),
                       ],
                     );
                   } else if (state is ErrorFilter) {
                     return buildInitialInput();
                   }
                 },
               ),
             ),
           ],
         )
       ),
     ),
   );
 }

 bool _onScrollNotification(ScrollNotification notif, LoadedFilter state) {
   if (notif is ScrollEndNotification && notif.metrics.pixels == notif.metrics.maxScrollExtent) {
     context.bloc<FilterBloc>().add(LoadMoreFilter(products: state.products, productName: 'a', stateName: ''));
   }
   return false;
 }

@IkhwanSI13
Copy link
Author

@IkhwanSI13 Please can you share your code i have the same issue.

   return Scaffold(
     appBar: AppBar(
       iconTheme: IconThemeData(
         color: Color(0xFF6991C7),
       ),
       title: Text(
         "Search",
         style: TextStyle(
             fontWeight: FontWeight.w700,
             fontSize: 18.0,
             color: Colors.black54,
             fontFamily: "Gotik"),
       ),
       centerTitle: true,
       backgroundColor: Colors.white,
       elevation: 0.0,
     ),
     body: SingleChildScrollView(
       primary: false,
       child: Container(
         color: Colors.white,
         padding: EdgeInsets.only(top: 15.0, bottom: 30.0),
         child:  Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: <Widget>[
             _textHello,
             BlocListener<FilterBloc, FilterState>(
               listener: (context, state) {
                 if (state is ErrorFilter) {
                   Scaffold.of(context).showSnackBar(
                     SnackBar(
                       content: Text(state.message),
                     ),
                   );
                 }
               },
               child: BlocBuilder<FilterBloc, FilterState>(
                 // ignore: missing_return
                 builder: (context, state) {
                   if (state is InitialFilter) {
                     return buildInitialInput();
                   } else if (state is LoadingFilter) {
                     return buildLoading();
                   } else if (state is LoadedFilter) {
                     if (state.products.isEmpty) {
                       return Column(
                         crossAxisAlignment: CrossAxisAlignment.center,
                         children: <Widget>[
                           ProductInputField(),
                           SizedBox(height: 30.0),
                           Center(child: Text('No content'))
                         ],
                       );
                     }
                     return Column(
                       children: <Widget>[
                         ProductInputField(),
                         SizedBox(height: 30.0),
                         NotificationListener<ScrollNotification>(
                           onNotification: (notification) => _onScrollNotification(notification, state),
                           child: GridView.builder(
                             physics: ScrollPhysics(),
                             itemCount: state.products.length,
                             primary: false,
                             shrinkWrap: true,
                             gridDelegate:
                             SliverGridDelegateWithFixedCrossAxisCount(
                               crossAxisSpacing: 10.0,
                               mainAxisSpacing: 10.0,
                               childAspectRatio: 0.605,
                               crossAxisCount: 2,
                             ),
                             itemBuilder: (context, pos) {
                               return ProductWidget(product: state.products[pos]);
                             },
                           ),
                         ),
                       ],
                     );
                   } else if (state is ErrorFilter) {
                     return buildInitialInput();
                   }
                 },
               ),
             ),
           ],
         )
       ),
     ),
   );
 }

 bool _onScrollNotification(ScrollNotification notif, LoadedFilter state) {
   if (notif is ScrollEndNotification && notif.metrics.pixels == notif.metrics.maxScrollExtent) {
     context.bloc<FilterBloc>().add(LoadMoreFilter(products: state.products, productName: 'a', stateName: ''));
   }
   return false;
 }

just check my code above. I updated it

@fahadadnaan
Copy link

@IkhwanSI13 Thanks for replying, Notifications Listener not working with multi ListView like my case, So i resolved this problem by add listener function instead of Notifications Listener.

@prateek601
Copy link

Thanks for the code.It is working well 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment