Skip to content

Commit

Permalink
add transition animations
Browse files Browse the repository at this point in the history
  • Loading branch information
EdsonBueno committed Jul 3, 2021
1 parent e553a98 commit 61f8572
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 88 deletions.
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

COCOAPODS: 1.10.0
COCOAPODS: 1.10.1
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class _CharacterListViewState extends State<CharacterListView> {
final nextPageKey = pageKey + newItems.length;
_pagingController.appendPage(newItems, nextPageKey);
}
} catch(error) {
} catch (error) {
_pagingController.error = error;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ class CharacterSliverGridBloc {

Sink<int> get onPageRequestSink => _onPageRequest.sink;

final _onSearchInputChangedSubject = BehaviorSubject<String>();
final _onSearchInputChangedSubject = BehaviorSubject<String?>.seeded(null);

Sink<String> get onSearchInputChangedSink =>
Sink<String?> get onSearchInputChangedSink =>
_onSearchInputChangedSubject.sink;

String? get searchInputValue => _onSearchInputChangedSubject.value;
String? get _searchInputValue => _onSearchInputChangedSubject.value;

Stream<CharacterListingState> _resetSearch() async* {
yield CharacterListingState();
Expand All @@ -51,20 +51,20 @@ class CharacterSliverGridBloc {
final newItems = await RemoteApi.getCharacterList(
pageKey,
_pageSize,
searchTerm: searchInputValue,
searchTerm: _searchInputValue,
);
final isLastPage = newItems.length < _pageSize;
final nextPageKey = isLastPage ? null : pageKey + newItems.length;
yield CharacterListingState(
error: null,
nextPageKey: nextPageKey,
itemList: [...lastListingState?.itemList ?? [], ...newItems],
itemList: [...lastListingState.itemList ?? [], ...newItems],
);
} catch (e) {
yield CharacterListingState(
error: e,
nextPageKey: lastListingState?.nextPageKey,
itemList: lastListingState?.itemList,
nextPageKey: lastListingState.nextPageKey,
itemList: lastListingState.itemList,
);
}
}
Expand Down
20 changes: 10 additions & 10 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ packages:
name: cached_network_image
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0-nullsafety"
version: "3.0.0"
characters:
dependency: transitive
description:
Expand Down Expand Up @@ -96,14 +96,14 @@ packages:
name: flutter_blurhash
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.2-nullsafety.0"
version: "0.6.0"
flutter_cache_manager:
dependency: transitive
description:
name: flutter_cache_manager
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0-nullsafety.1"
version: "3.1.1"
flutter_test:
dependency: "direct dev"
description: flutter
Expand All @@ -115,7 +115,7 @@ packages:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.0"
version: "0.13.3"
http_parser:
dependency: transitive
description:
Expand All @@ -136,7 +136,7 @@ packages:
path: ".."
relative: true
source: path
version: "3.0.1"
version: "3.0.1+1"
matcher:
dependency: transitive
description:
Expand All @@ -157,7 +157,7 @@ packages:
name: octo_image
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0-nullsafety.1"
version: "1.0.0+1"
path:
dependency: transitive
description:
Expand Down Expand Up @@ -206,7 +206,7 @@ packages:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0"
version: "1.11.0"
petitparser:
dependency: transitive
description:
Expand Down Expand Up @@ -241,7 +241,7 @@ packages:
name: rxdart
url: "https://pub.dartlang.org"
source: hosted
version: "0.26.0"
version: "0.27.1"
sky_engine:
dependency: transitive
description: flutter
Expand All @@ -253,7 +253,7 @@ packages:
name: sliver_tools
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
version: "0.2.5"
source_span:
dependency: transitive
description:
Expand All @@ -267,7 +267,7 @@ packages:
name: sqflite
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0+2"
version: "2.0.0+3"
sqflite_common:
dependency: transitive
description:
Expand Down
6 changes: 3 additions & 3 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ environment:
sdk: '>=2.12.0 <3.0.0'

dependencies:
cached_network_image: ^3.0.0-nullsafety
cached_network_image: ^3.0.0
flutter:
sdk: flutter
http: ^0.13.0
http: ^0.13.3
infinite_scroll_pagination:
path: ../
rxdart: ^0.26.0
rxdart: ^0.27.1

dev_dependencies:
flutter_test:
Expand Down
8 changes: 8 additions & 0 deletions lib/src/core/paged_child_builder_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class PagedChildBuilderDelegate<ItemType> {
this.newPageProgressIndicatorBuilder,
this.noItemsFoundIndicatorBuilder,
this.noMoreItemsIndicatorBuilder,
this.animateTransitions = false,
this.transitionDuration = const Duration(milliseconds: 250),
});

/// The builder for list items.
Expand All @@ -41,4 +43,10 @@ class PagedChildBuilderDelegate<ItemType> {

/// The builder for an indicator that all items have been fetched.
final WidgetBuilder? noMoreItemsIndicatorBuilder;

/// Whether to animate transitions between various Widget states
final bool animateTransitions;

/// If animateTransitions is true, use this duration for the transition spped.
final Duration transitionDuration;
}
155 changes: 94 additions & 61 deletions lib/src/ui/paged_sliver_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:infinite_scroll_pagination/src/ui/default_indicators/new_page_er
import 'package:infinite_scroll_pagination/src/ui/default_indicators/new_page_progress_indicator.dart';
import 'package:infinite_scroll_pagination/src/ui/default_indicators/no_items_found_indicator.dart';
import 'package:infinite_scroll_pagination/src/utils/listenable_listener.dart';
import 'package:sliver_tools/sliver_tools.dart';

typedef CompletedListingBuilder = Widget Function(
BuildContext context,
Expand Down Expand Up @@ -140,70 +141,101 @@ class _PagedSliverBuilderState<PageKeyType, ItemType>
bool _hasRequestedNextPage = false;

@override
Widget build(BuildContext context) =>
// The SliverPadding is used to avoid changing the topmost item inside a
// CustomScrollView.
// https://github.com/flutter/flutter/issues/55170
SliverPadding(
padding: const EdgeInsets.all(0),
sliver: ListenableListener(
listenable: _pagingController,
listener: () {
final status = _pagingController.value.status;

if (status == PagingStatus.loadingFirstPage) {
_pagingController.notifyPageRequestListeners(
_pagingController.firstPageKey,
);
Widget build(BuildContext context) => ListenableListener(
listenable: _pagingController,
listener: () {
final status = _pagingController.value.status;

if (status == PagingStatus.loadingFirstPage) {
_pagingController.notifyPageRequestListeners(
_pagingController.firstPageKey,
);
}

if (status == PagingStatus.ongoing) {
_hasRequestedNextPage = false;
}
},
child: ValueListenableBuilder<PagingState<PageKeyType, ItemType>>(
valueListenable: _pagingController,
builder: (context, pagingState, _) {
Widget child;
final itemList = _pagingController.itemList;
switch (pagingState.status) {
case PagingStatus.ongoing:
child = widget.loadingListingBuilder(
context,
// We must create this closure to close over the [itemList]
// value. That way, we are safe if [itemList] value changes
// while Flutter rebuilds the widget (due to animations, for
// example.)
(context, index) => _buildListItemWidget(
context,
index,
itemList!,
),
_itemCount,
_newPageProgressIndicatorBuilder,
);
break;
case PagingStatus.completed:
child = widget.completedListingBuilder(
context,
(context, index) => _buildListItemWidget(
context,
index,
itemList!,
),
_itemCount,
_noMoreItemsIndicatorBuilder,
);
break;
case PagingStatus.loadingFirstPage:
child = _FirstPageStatusIndicatorBuilder(
builder: _firstPageProgressIndicatorBuilder,
shrinkWrap: _shrinkWrapFirstPageIndicators,
);
break;
case PagingStatus.subsequentPageError:
child = widget.errorListingBuilder(
context,
(context, index) => _buildListItemWidget(
context,
index,
itemList!,
),
_itemCount,
(context) => _newPageErrorIndicatorBuilder(context),
);
break;
case PagingStatus.noItemsFound:
child = _FirstPageStatusIndicatorBuilder(
builder: _noItemsFoundIndicatorBuilder,
shrinkWrap: _shrinkWrapFirstPageIndicators,
);
break;
default:
child = _FirstPageStatusIndicatorBuilder(
builder: _firstPageErrorIndicatorBuilder,
shrinkWrap: _shrinkWrapFirstPageIndicators,
);
}

if (status == PagingStatus.ongoing) {
_hasRequestedNextPage = false;
if (_builderDelegate.animateTransitions) {
return SliverAnimatedSwitcher(
duration: _builderDelegate.transitionDuration,
child: Container(
// The `ObjectKey` makes it possible to differentiate
// transitions between same Widget types, e.g., ongoing to
// completed.
key: ObjectKey(pagingState),
child: child,
),
);
} else {
return child;
}
},
child: ValueListenableBuilder<PagingState<PageKeyType, ItemType>>(
valueListenable: _pagingController,
builder: (context, pagingState, _) {
switch (pagingState.status) {
case PagingStatus.ongoing:
return widget.loadingListingBuilder(
context,
_buildListItemWidget,
_itemCount,
_newPageProgressIndicatorBuilder,
);
case PagingStatus.completed:
return widget.completedListingBuilder(
context,
_buildListItemWidget,
_itemCount,
_noMoreItemsIndicatorBuilder,
);
case PagingStatus.loadingFirstPage:
return _FirstPageStatusIndicatorBuilder(
builder: _firstPageProgressIndicatorBuilder,
shrinkWrap: _shrinkWrapFirstPageIndicators,
);
case PagingStatus.subsequentPageError:
return widget.errorListingBuilder(
context,
_buildListItemWidget,
_itemCount,
(context) => _newPageErrorIndicatorBuilder(context),
);
case PagingStatus.noItemsFound:
return _FirstPageStatusIndicatorBuilder(
builder: _noItemsFoundIndicatorBuilder,
shrinkWrap: _shrinkWrapFirstPageIndicators,
);
default:
return _FirstPageStatusIndicatorBuilder(
builder: _firstPageErrorIndicatorBuilder,
shrinkWrap: _shrinkWrapFirstPageIndicators,
);
}
},
),
),
);

Expand All @@ -212,6 +244,7 @@ class _PagedSliverBuilderState<PageKeyType, ItemType>
Widget _buildListItemWidget(
BuildContext context,
int index,
List<ItemType> itemList,
) {
if (!_hasRequestedNextPage) {
final newPageRequestTriggerIndex =
Expand All @@ -228,7 +261,7 @@ class _PagedSliverBuilderState<PageKeyType, ItemType>
}
}

final item = _pagingController.itemList![index];
final item = itemList[index];
return _builderDelegate.itemBuilder(context, item, index);
}
}
Expand Down
6 changes: 3 additions & 3 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ packages:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.0"
version: "4.0.0"
collection:
dependency: transitive
description:
Expand Down Expand Up @@ -227,7 +227,7 @@ packages:
name: mockito
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.0"
version: "5.0.9"
node_preamble:
dependency: transitive
description:
Expand Down Expand Up @@ -309,7 +309,7 @@ packages:
name: sliver_tools
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
version: "0.2.5"
source_gen:
dependency: transitive
description:
Expand Down
Loading

0 comments on commit 61f8572

Please sign in to comment.