[UserListView] Use LazyLoadScrollView for pagination rather than listening scroll controller
This commit is contained in:
@@ -0,0 +1,81 @@
|
|||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
enum LoadingStatus { LOADING, STABLE }
|
||||||
|
|
||||||
|
/// Signature for EndOfPageListeners
|
||||||
|
typedef EndOfPageListenerCallback = void Function();
|
||||||
|
|
||||||
|
/// A widget that wraps a [Widget] and will trigger [onEndOfPage] when it
|
||||||
|
/// reaches the bottom of the list
|
||||||
|
class LazyLoadScrollView extends StatefulWidget {
|
||||||
|
/// The [Widget] that this widget watches for changes on
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
/// Called when the [child] reaches the end of the list
|
||||||
|
final EndOfPageListenerCallback onEndOfPage;
|
||||||
|
|
||||||
|
/// The offset to take into account when triggering [onEndOfPage] in pixels
|
||||||
|
final int scrollOffset;
|
||||||
|
|
||||||
|
/// Used to determine if loading of new data has finished. You should use set this if you aren't using a FutureBuilder or StreamBuilder
|
||||||
|
final bool isLoading;
|
||||||
|
|
||||||
|
LazyLoadScrollView({
|
||||||
|
Key key,
|
||||||
|
@required this.child,
|
||||||
|
@required this.onEndOfPage,
|
||||||
|
this.isLoading = false,
|
||||||
|
this.scrollOffset = 100,
|
||||||
|
}) : assert(onEndOfPage != null),
|
||||||
|
assert(child != null),
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _LazyLoadScrollViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LazyLoadScrollViewState extends State<LazyLoadScrollView> {
|
||||||
|
LoadingStatus _loadMoreStatus = LoadingStatus.STABLE;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(LazyLoadScrollView oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (!widget.isLoading) {
|
||||||
|
_loadMoreStatus = LoadingStatus.STABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return NotificationListener(
|
||||||
|
child: widget.child,
|
||||||
|
onNotification: _onNotification,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _onNotification(Notification notification) {
|
||||||
|
if (notification is ScrollUpdateNotification) {
|
||||||
|
if (notification.metrics.maxScrollExtent > notification.metrics.pixels &&
|
||||||
|
notification.metrics.maxScrollExtent - notification.metrics.pixels <=
|
||||||
|
widget.scrollOffset) {
|
||||||
|
if (_loadMoreStatus != null &&
|
||||||
|
_loadMoreStatus == LoadingStatus.STABLE) {
|
||||||
|
_loadMoreStatus = LoadingStatus.LOADING;
|
||||||
|
widget.onEndOfPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (notification is OverscrollNotification) {
|
||||||
|
if (notification.overscroll > 0) {
|
||||||
|
if (_loadMoreStatus != null &&
|
||||||
|
_loadMoreStatus == LoadingStatus.STABLE) {
|
||||||
|
_loadMoreStatus = LoadingStatus.LOADING;
|
||||||
|
widget.onEndOfPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
-48
@@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart';
|
||||||
import 'package:stream_chat_flutter/src/users_bloc.dart';
|
import 'package:stream_chat_flutter/src/users_bloc.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
@@ -144,8 +145,6 @@ class UserListView extends StatefulWidget {
|
|||||||
|
|
||||||
class _UserListViewState extends State<UserListView>
|
class _UserListViewState extends State<UserListView>
|
||||||
with WidgetsBindingObserver {
|
with WidgetsBindingObserver {
|
||||||
final ScrollController _scrollController = ScrollController();
|
|
||||||
|
|
||||||
bool get _isListView => widget.crossAxisCount == 1;
|
bool get _isListView => widget.crossAxisCount == 1;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -158,14 +157,6 @@ class _UserListViewState extends State<UserListView>
|
|||||||
pagination: widget.pagination,
|
pagination: widget.pagination,
|
||||||
options: widget.options,
|
options: widget.options,
|
||||||
);
|
);
|
||||||
|
|
||||||
_scrollController.addListener(() {
|
|
||||||
usersBloc.queryUsersLoading.first.then((loading) {
|
|
||||||
if (!loading) {
|
|
||||||
_listenUserPagination(usersBloc);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -327,32 +318,35 @@ class _UserListViewState extends State<UserListView>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isListView) {
|
final child = _isListView
|
||||||
return ListView.separated(
|
? ListView.separated(
|
||||||
physics: AlwaysScrollableScrollPhysics(),
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
controller: _scrollController,
|
// controller: _scrollController,
|
||||||
itemCount: items.isNotEmpty ? items.length + 1 : items.length,
|
itemCount: items.isNotEmpty ? items.length + 1 : items.length,
|
||||||
separatorBuilder: (_, index) {
|
separatorBuilder: (_, index) {
|
||||||
if (widget.separatorBuilder != null) {
|
if (widget.separatorBuilder != null) {
|
||||||
return widget.separatorBuilder(context, index);
|
return widget.separatorBuilder(context, index);
|
||||||
}
|
}
|
||||||
return _separatorBuilder(context, index);
|
return _separatorBuilder(context, index);
|
||||||
},
|
},
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return _listItemBuilder(context, index, items);
|
return _listItemBuilder(context, index, items);
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
}
|
: GridView.builder(
|
||||||
return GridView.builder(
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
crossAxisCount: widget.crossAxisCount,
|
||||||
crossAxisCount: widget.crossAxisCount,
|
),
|
||||||
),
|
itemCount: items.isNotEmpty ? items.length + 1 : items.length,
|
||||||
itemCount: items.isNotEmpty ? items.length + 1 : items.length,
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
physics: AlwaysScrollableScrollPhysics(),
|
itemBuilder: (context, index) {
|
||||||
controller: _scrollController,
|
return _gridItemBuilder(context, index, items);
|
||||||
itemBuilder: (context, index) {
|
},
|
||||||
return _gridItemBuilder(context, index, items);
|
);
|
||||||
},
|
|
||||||
|
return LazyLoadScrollView(
|
||||||
|
onEndOfPage: () => _listenUserPagination(usersBlocState),
|
||||||
|
child: child,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -488,18 +482,14 @@ class _UserListViewState extends State<UserListView>
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _listenUserPagination(UsersBlocState usersProvider) {
|
void _listenUserPagination(UsersBlocState usersProvider) {
|
||||||
if (_scrollController.position.maxScrollExtent ==
|
usersProvider.queryUsers(
|
||||||
_scrollController.offset &&
|
filter: widget.filter,
|
||||||
_scrollController.offset != 0) {
|
sort: widget.sort,
|
||||||
usersProvider.queryUsers(
|
pagination: widget.pagination.copyWith(
|
||||||
filter: widget.filter,
|
offset: usersProvider.users?.length ?? 0,
|
||||||
sort: widget.sort,
|
),
|
||||||
pagination: widget.pagination.copyWith(
|
options: widget.options,
|
||||||
offset: usersProvider.users?.length ?? 0,
|
);
|
||||||
),
|
|
||||||
options: widget.options,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
Reference in New Issue
Block a user