Skip to content

Commit

Permalink
Separated builder (#26)
Browse files Browse the repository at this point in the history
fixes
#25

---------

Co-authored-by: matteo.gentile <[email protected]>
  • Loading branch information
Maatteogekko and matteo.gentile authored Aug 3, 2023
1 parent 17cf0ba commit 3319a9c
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 26 deletions.
2 changes: 1 addition & 1 deletion example/lib/examples.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,4 @@ class Examples extends StatelessWidget {
);
}
}
*/
*/
12 changes: 8 additions & 4 deletions example/lib/util/box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ class Box extends StatelessWidget {
child: child,
);

if (boxShape == BoxShape.circle || (customBorders != null || borderRadius > 0.0)) {
if (boxShape == BoxShape.circle ||
(customBorders != null || borderRadius > 0.0)) {
content = ClipRRect(
borderRadius: br,
child: content,
Expand All @@ -97,14 +98,17 @@ class Box extends StatelessWidget {
content = Material(
color: Colors.transparent,
type: MaterialType.transparency,
shape: circle ? const CircleBorder() : RoundedRectangleBorder(borderRadius: br),
shape: circle
? const CircleBorder()
: RoundedRectangleBorder(borderRadius: br),
child: InkWell(
splashColor: splashColor ?? theme.splashColor,
highlightColor: theme.highlightColor,
hoverColor: theme.hoverColor,
focusColor: theme.focusColor,
customBorder:
circle ? const CircleBorder() : RoundedRectangleBorder(borderRadius: br),
customBorder: circle
? const CircleBorder()
: RoundedRectangleBorder(borderRadius: br),
onTap: onTap,
onLongPress: onLongPress,
onDoubleTap: onDoubleTap,
Expand Down
16 changes: 12 additions & 4 deletions example/lib/util/highlight_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ List<Triplet<int, int, bool>> getQueryHighlights(String text, String query) {
final t = text.toLowerCase();
final q = query.toLowerCase();

if (t.isEmpty || q.isEmpty || !t.contains(q)) return [Triplet(0, t.length, false)];
if (t.isEmpty || q.isEmpty || !t.contains(q))
return [Triplet(0, t.length, false)];

List<Triplet<int, int, bool>> idxs = [];

Expand All @@ -92,12 +93,16 @@ List<Triplet<int, int, bool>> getQueryHighlights(String text, String query) {
if (idx.first == 0) {
result.add(idx);
} else {
result..add(Triplet(0, idx.first, false))..add(idx);
result
..add(Triplet(0, idx.first, false))
..add(idx);
}
} else if (last.second == idx.first) {
result.add(idx);
} else {
result..add(Triplet(last.second, idx.first, false))..add(idx);
result
..add(Triplet(last.second, idx.first, false))
..add(idx);
}

if (isLast && idx.second != t.length) {
Expand Down Expand Up @@ -140,7 +145,10 @@ class Triplet<A, B, C> {

@override
bool operator ==(Object o) {
return o is Triplet && o.first == first && o.second == second && o.third == third;
return o is Triplet &&
o.first == first &&
o.second == second &&
o.third == third;
}

@override
Expand Down
7 changes: 5 additions & 2 deletions example/lib/util/languages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,16 @@ class Language {
});

@override
String toString() => 'Language englishName: $englishName, nativeName: $nativeName';
String toString() =>
'Language englishName: $englishName, nativeName: $nativeName';

@override
bool operator ==(Object o) {
if (identical(this, o)) return true;

return o is Language && o.englishName == englishName && o.nativeName == nativeName;
return o is Language &&
o.englishName == englishName &&
o.nativeName == nativeName;
}

@override
Expand Down
2 changes: 1 addition & 1 deletion example/lib/util/util.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export 'box.dart';
export 'highlight_text.dart';
export 'languages.dart';
export 'languages.dart';
12 changes: 11 additions & 1 deletion lib/src/custom_sliver_animated_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@ import 'package:flutter/material.dart';

const Duration _kDuration = Duration(milliseconds: 300);

typedef DelegateBuilder = SliverChildBuilderDelegate Function(
NullableIndexedWidgetBuilder builder,
int itemCount,
);

class CustomSliverAnimatedList extends StatefulWidget {
/// Creates a sliver that animates items when they are inserted or removed.
const CustomSliverAnimatedList({
Key? key,
required this.itemBuilder,
this.initialItemCount = 0,
this.delegateBuilder,
}) : assert(initialItemCount >= 0),
super(key: key);

Expand All @@ -30,6 +36,9 @@ class CustomSliverAnimatedList extends StatefulWidget {
/// {@macro flutter.widgets.animatedList.initialItemCount}
final int initialItemCount;

/// Builds the delegate to use for the list view.
final DelegateBuilder? delegateBuilder;

@override
CustomSliverAnimatedListState createState() =>
CustomSliverAnimatedListState();
Expand Down Expand Up @@ -149,7 +158,8 @@ class CustomSliverAnimatedListState extends State<CustomSliverAnimatedList>
}

SliverChildDelegate _createDelegate() {
return SliverChildBuilderDelegate(_itemBuilder, childCount: _itemsCount);
return widget.delegateBuilder?.call(_itemBuilder, _itemsCount) ??
SliverChildBuilderDelegate(_itemBuilder, childCount: _itemsCount);
}

/// Insert an item at [index] and start an animation that will be passed to
Expand Down
101 changes: 90 additions & 11 deletions lib/src/implicitly_animated_list.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:animated_list_plus/src/custom_sliver_animated_list.dart';
import 'package:animated_list_plus/src/util/sliver_child_separated_builder_delegate.dart';
import 'package:flutter/material.dart' hide AnimatedItemBuilder;

import 'src.dart';
Expand All @@ -13,6 +14,10 @@ class ImplicitlyAnimatedList<E extends Object> extends StatelessWidget {
/// List items are only built when they're scrolled into view.
final AnimatedItemBuilder<Widget, E> itemBuilder;

/// Called to build widgets that get placed between
/// itemBuilder(context, index) and itemBuilder(context, index + 1).
final NullableIndexedWidgetBuilder? separatorBuilder;

/// An optional builder when an item was removed from the list.
///
/// If not specified, the [ImplicitlyAnimatedList] uses the [itemBuilder] with
Expand Down Expand Up @@ -126,6 +131,7 @@ class ImplicitlyAnimatedList<E extends Object> extends StatelessWidget {
required this.items,
required this.itemBuilder,
required this.areItemsTheSame,
this.separatorBuilder,
this.removeItemBuilder,
this.updateItemBuilder,
this.insertDuration = const Duration(milliseconds: 500),
Expand All @@ -143,6 +149,8 @@ class ImplicitlyAnimatedList<E extends Object> extends StatelessWidget {

@override
Widget build(BuildContext context) {
final separatorBuilder = this.separatorBuilder;

return CustomScrollView(
scrollDirection: scrollDirection,
reverse: reverse,
Expand All @@ -153,17 +161,30 @@ class ImplicitlyAnimatedList<E extends Object> extends StatelessWidget {
slivers: <Widget>[
SliverPadding(
padding: padding ?? const EdgeInsets.all(0),
sliver: SliverImplicitlyAnimatedList<E>(
items: items,
itemBuilder: itemBuilder,
areItemsTheSame: areItemsTheSame,
updateItemBuilder: updateItemBuilder,
removeItemBuilder: removeItemBuilder,
insertDuration: insertDuration,
removeDuration: removeDuration,
updateDuration: updateDuration,
spawnIsolate: spawnIsolate,
),
sliver: separatorBuilder == null
? SliverImplicitlyAnimatedList<E>(
items: items,
itemBuilder: itemBuilder,
areItemsTheSame: areItemsTheSame,
updateItemBuilder: updateItemBuilder,
removeItemBuilder: removeItemBuilder,
insertDuration: insertDuration,
removeDuration: removeDuration,
updateDuration: updateDuration,
spawnIsolate: spawnIsolate,
)
: SliverImplicitlyAnimatedList<E>.separated(
items: items,
itemBuilder: itemBuilder,
separatorBuilder: separatorBuilder,
areItemsTheSame: areItemsTheSame,
updateItemBuilder: updateItemBuilder,
removeItemBuilder: removeItemBuilder,
insertDuration: insertDuration,
removeDuration: removeDuration,
updateDuration: updateDuration,
spawnIsolate: spawnIsolate,
),
),
],
);
Expand Down Expand Up @@ -210,6 +231,63 @@ class SliverImplicitlyAnimatedList<E extends Object>
key: key,
items: items,
itemBuilder: itemBuilder,
delegateBuilder: null,
areItemsTheSame: areItemsTheSame,
removeItemBuilder: removeItemBuilder,
updateItemBuilder: updateItemBuilder,
insertDuration: insertDuration,
removeDuration: removeDuration,
updateDuration: updateDuration,
spawnIsolate: spawnIsolate,
);

/// Creates a Flutter Sliver that implicitly animates between the changes of two lists.
///
/// {@template implicitly_animated_reorderable_list.constructor}
/// The [items] parameter represents the current items that should be displayed in
/// the list.
///
/// The [itemBuilder] callback is used to build each child as needed. The parent must
/// be a [Reorderable] widget.
///
/// The [separatorBuilder] is the widget that gets placed between
/// itemBuilder(context, index) and itemBuilder(context, index + 1).
///
/// The [areItemsTheSame] callback is called by the DiffUtil to decide whether two objects
/// represent the same item. For example, if your items have unique ids, this method should
/// check their id equality.
///
/// The [onReorderFinished] callback is called in response to when the dragged item has
/// been released and animated to its final destination. Here you should update
/// the underlying data in your model/bloc/database etc.
///
/// The [spawnIsolate] flag indicates whether to spawn a new isolate on which to
/// calculate the diff between the lists. Usually you wont have to specify this
/// value as the MyersDiff implementation will use its own metrics to decide, whether
/// a new isolate has to be spawned or not for optimal performance.
/// {@endtemplate}
SliverImplicitlyAnimatedList.separated({
Key? key,
required List<E> items,
required AnimatedItemBuilder<Widget, E> itemBuilder,
required ItemDiffUtil<E> areItemsTheSame,
required NullableIndexedWidgetBuilder separatorBuilder,
RemovedItemBuilder<Widget, E>? removeItemBuilder,
UpdatedItemBuilder<Widget, E>? updateItemBuilder,
Duration insertDuration = const Duration(milliseconds: 500),
Duration removeDuration = const Duration(milliseconds: 500),
Duration updateDuration = const Duration(milliseconds: 500),
bool? spawnIsolate,
}) : super(
key: key,
items: items,
itemBuilder: itemBuilder,
delegateBuilder: (builder, itemCount) =>
SliverChildSeparatedBuilderDelegate(
itemBuilder: builder,
separatorBuilder: separatorBuilder,
itemCount: itemCount,
),
areItemsTheSame: areItemsTheSame,
removeItemBuilder: removeItemBuilder,
updateItemBuilder: updateItemBuilder,
Expand Down Expand Up @@ -246,6 +324,7 @@ class _SliverImplicitlyAnimatedListState<E extends Object>
return itemBuilder(context, animation, item, index);
}
},
delegateBuilder: widget.delegateBuilder,
);
}
}
5 changes: 5 additions & 0 deletions lib/src/implicitly_animated_list_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ abstract class ImplicitlyAnimatedListBase<W extends Widget, E extends Object>
/// List items are only built when they're scrolled into view.
final AnimatedItemBuilder<W, E> itemBuilder;

/// Called to build widgets that get placed between
/// itemBuilder(context, index) and itemBuilder(context, index + 1).
final DelegateBuilder? delegateBuilder;

/// An optional builder when an item was removed from the list.
///
/// If not specified, the [ImplicitlyAnimatedList] uses the [itemBuilder] with
Expand Down Expand Up @@ -67,6 +71,7 @@ abstract class ImplicitlyAnimatedListBase<W extends Widget, E extends Object>
required this.items,
required this.areItemsTheSame,
required this.itemBuilder,
required this.delegateBuilder,
required this.removeItemBuilder,
required this.updateItemBuilder,
required this.insertDuration,
Expand Down
Loading

0 comments on commit 3319a9c

Please sign in to comment.