Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
d2de911d
Commit
d2de911d
authored
May 06, 2019
by
Simon Binder
Committed by
Michael Goderbauer
May 06, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Sliver animated list (#28834)
parent
538a1c66
Changes
2
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
424 additions
and
158 deletions
+424
-158
animated_list.dart
packages/flutter/lib/src/widgets/animated_list.dart
+159
-17
animated_list_test.dart
packages/flutter/test/widgets/animated_list_test.dart
+265
-141
No files found.
packages/flutter/lib/src/widgets/animated_list.dart
View file @
d2de911d
...
@@ -10,6 +10,7 @@ import 'framework.dart';
...
@@ -10,6 +10,7 @@ import 'framework.dart';
import
'scroll_controller.dart'
;
import
'scroll_controller.dart'
;
import
'scroll_physics.dart'
;
import
'scroll_physics.dart'
;
import
'scroll_view.dart'
;
import
'scroll_view.dart'
;
import
'sliver.dart'
;
import
'ticker_provider.dart'
;
import
'ticker_provider.dart'
;
/// Signature for the builder callback used by [AnimatedList].
/// Signature for the builder callback used by [AnimatedList].
...
@@ -75,11 +76,13 @@ class AnimatedList extends StatefulWidget {
...
@@ -75,11 +76,13 @@ class AnimatedList extends StatefulWidget {
/// [AnimatedListState.removeItem] removes an item immediately.
/// [AnimatedListState.removeItem] removes an item immediately.
final
AnimatedListItemBuilder
itemBuilder
;
final
AnimatedListItemBuilder
itemBuilder
;
/// {@template flutter.widgets.animatedList.initialItemCount}
/// The number of items the list will start with.
/// The number of items the list will start with.
///
///
/// The appearance of the initial items is not animated. They
/// The appearance of the initial items is not animated. They
/// are created, as needed, by [itemBuilder] with an animation parameter
/// are created, as needed, by [itemBuilder] with an animation parameter
/// of [kAlwaysCompleteAnimation].
/// of [kAlwaysCompleteAnimation].
/// {@endtemplate}
final
int
initialItemCount
;
final
int
initialItemCount
;
/// The axis along which the scroll view scrolls.
/// The axis along which the scroll view scrolls.
...
@@ -207,6 +210,150 @@ class AnimatedList extends StatefulWidget {
...
@@ -207,6 +210,150 @@ class AnimatedList extends StatefulWidget {
/// [AnimatedList] item input handlers can also refer to their [AnimatedListState]
/// [AnimatedList] item input handlers can also refer to their [AnimatedListState]
/// with the static [AnimatedList.of] method.
/// with the static [AnimatedList.of] method.
class
AnimatedListState
extends
State
<
AnimatedList
>
with
TickerProviderStateMixin
<
AnimatedList
>
{
class
AnimatedListState
extends
State
<
AnimatedList
>
with
TickerProviderStateMixin
<
AnimatedList
>
{
final
GlobalKey
<
SliverAnimatedListState
>
_sliverAnimatedListKey
=
GlobalKey
();
/// Insert an item at [index] and start an animation that will be passed
/// to [AnimatedList.itemBuilder] when the item is visible.
///
/// This method's semantics are the same as Dart's [List.insert] method:
/// it increases the length of the list by one and shifts all items at or
/// after [index] towards the end of the list.
void
insertItem
(
int
index
,
{
Duration
duration
=
_kDuration
})
{
_sliverAnimatedListKey
.
currentState
.
insertItem
(
index
,
duration:
duration
);
}
/// Remove the item at [index] and start an animation that will be passed
/// to [builder] when the item is visible.
///
/// Items are removed immediately. After an item has been removed, its index
/// will no longer be passed to the [AnimatedList.itemBuilder]. However the
/// item will still appear in the list for [duration] and during that time
/// [builder] must construct its widget as needed.
///
/// This method's semantics are the same as Dart's [List.remove] method:
/// it decreases the length of the list by one and shifts all items at or
/// before [index] towards the beginning of the list.
void
removeItem
(
int
index
,
AnimatedListRemovedItemBuilder
builder
,
{
Duration
duration
=
_kDuration
})
{
_sliverAnimatedListKey
.
currentState
.
removeItem
(
index
,
builder
,
duration:
duration
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
CustomScrollView
(
scrollDirection:
widget
.
scrollDirection
,
reverse:
widget
.
reverse
,
controller:
widget
.
controller
,
primary:
widget
.
primary
,
physics:
widget
.
physics
,
shrinkWrap:
widget
.
shrinkWrap
,
slivers:
<
Widget
>[
SliverPadding
(
padding:
widget
.
padding
??
const
EdgeInsets
.
all
(
0
),
sliver:
SliverAnimatedList
(
key:
_sliverAnimatedListKey
,
itemBuilder:
widget
.
itemBuilder
,
initialItemCount:
widget
.
initialItemCount
,
),
),
],
);
}
}
/// A sliver that animates items when they are inserted or removed.
///
/// This widget's [SliverAnimatedListState] can be used to dynamically insert or
/// remove items. To refer to the [SliverAnimatedListState] either provide a
/// [GlobalKey] or use the static [SliverAnimatedList.of] method from an item's
/// input callback.
///
/// See also:
///
/// * [SliverList], which does not animate items when they are inserted or removed.
class
SliverAnimatedList
extends
StatefulWidget
{
/// Creates a sliver that animates items when they are inserted or removed.
const
SliverAnimatedList
({
Key
key
,
@required
this
.
itemBuilder
,
this
.
initialItemCount
=
0
,
})
:
assert
(
itemBuilder
!=
null
),
assert
(
initialItemCount
!=
null
&&
initialItemCount
>=
0
),
super
(
key:
key
);
/// Called, as needed, to build list item widgets.
///
/// List items are only built when they're scrolled into view.
///
/// The [AnimatedListItemBuilder] index parameter indicates the item's
/// position in the list. The value of the index parameter will be between 0
/// and [initialItemCount] plus the total number of items that have been
/// inserted with [SliverAnimatedListState.insertItem] and less the total
/// number of items that have been removed with
/// [SliverAnimatedListState.removeItem].
///
/// Implementations of this callback should assume that
/// [SliverAnimatedListState.removeItem] removes an item immediately.
final
AnimatedListItemBuilder
itemBuilder
;
/// {@macro flutter.widgets.animatedList.initialItemCount}
final
int
initialItemCount
;
@override
SliverAnimatedListState
createState
()
=>
SliverAnimatedListState
();
/// The state from the closest instance of this class that encloses the given context.
///
/// This method is typically used by [SliverAnimatedList] item widgets that
/// insert or remove items in response to user input.
///
/// ```dart
/// SliverAnimatedListState animatedList = SliverAnimatedList.of(context);
/// ```
static
SliverAnimatedListState
of
(
BuildContext
context
,
{
bool
nullOk
=
false
})
{
assert
(
context
!=
null
);
assert
(
nullOk
!=
null
);
final
SliverAnimatedListState
result
=
context
.
ancestorStateOfType
(
const
TypeMatcher
<
SliverAnimatedListState
>());
if
(
nullOk
||
result
!=
null
)
return
result
;
throw
FlutterError
(
'SliverAnimatedList.of() called with a context that does not contain a SliverAnimatedList.
\n
'
'No SliverAnimatedListState ancestor could be found starting from the '
'context that was passed to SliverAnimatedListState.of(). '
'This can happen when the context provided is from the same StatefulWidget that '
'built the AnimatedList. Please see the SliverAnimatedList documentation '
'for examples of how to refer to an AnimatedListState object: '
' https://docs.flutter.io/flutter/widgets/SliverAnimatedListState-class.html
\n
'
'The context used was:
\n
'
'
$context
'
);
}
}
/// The state for a sliver that animates items when they are
/// inserted or removed.
///
/// When an item is inserted with [insertItem] an animation begins running. The
/// animation is passed to [SliverAnimatedList.itemBuilder] whenever the item's
/// widget is needed.
///
/// When an item is removed with [removeItem] its animation is reversed.
/// The removed item's animation is passed to the [removeItem] builder
/// parameter.
///
/// An app that needs to insert or remove items in response to an event
/// can refer to the [SliverAnimatedList]'s state with a global key:
///
/// ```dart
/// GlobalKey<SliverAnimatedListState> listKey = GlobalKey<SliverAnimatedListState>();
/// ...
/// SliverAnimatedList(key: listKey, ...);
/// ...
/// listKey.currentState.insert(123);
/// ```
///
/// [SliverAnimatedList] item input handlers can also refer to their
/// [SliverAnimatedListState] with the static [SliverAnimatedList.of] method.
class
SliverAnimatedListState
extends
State
<
SliverAnimatedList
>
with
TickerProviderStateMixin
{
final
List
<
_ActiveItem
>
_incomingItems
=
<
_ActiveItem
>[];
final
List
<
_ActiveItem
>
_incomingItems
=
<
_ActiveItem
>[];
final
List
<
_ActiveItem
>
_outgoingItems
=
<
_ActiveItem
>[];
final
List
<
_ActiveItem
>
_outgoingItems
=
<
_ActiveItem
>[];
int
_itemsCount
=
0
;
int
_itemsCount
=
0
;
...
@@ -219,10 +366,9 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
...
@@ -219,10 +366,9 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
@override
@override
void
dispose
()
{
void
dispose
()
{
for
(
_ActiveItem
item
in
_incomingItems
)
for
(
_ActiveItem
item
in
_incomingItems
.
followedBy
(
_outgoingItems
))
{
item
.
controller
.
dispose
();
for
(
_ActiveItem
item
in
_outgoingItems
)
item
.
controller
.
dispose
();
item
.
controller
.
dispose
();
}
super
.
dispose
();
super
.
dispose
();
}
}
...
@@ -265,8 +411,12 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
...
@@ -265,8 +411,12 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
return
index
;
return
index
;
}
}
/// Insert an item at [index] and start an animation that will be passed
SliverChildDelegate
_createDelegate
()
{
/// to [AnimatedList.itemBuilder] when the item is visible.
return
SliverChildBuilderDelegate
(
_itemBuilder
,
childCount:
_itemsCount
);
}
/// Insert an item at [index] and start an animation that will be passed to
/// [SliverAnimatedList.itemBuilder] when the item is visible.
///
///
/// This method's semantics are the same as Dart's [List.insert] method:
/// This method's semantics are the same as Dart's [List.insert] method:
/// it increases the length of the list by one and shifts all items at or
/// it increases the length of the list by one and shifts all items at or
...
@@ -307,8 +457,8 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
...
@@ -307,8 +457,8 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
/// to [builder] when the item is visible.
/// to [builder] when the item is visible.
///
///
/// Items are removed immediately. After an item has been removed, its index
/// Items are removed immediately. After an item has been removed, its index
/// will no longer be passed to the [
AnimatedList.itemBuilder]. However the
/// will no longer be passed to the [
SliverAnimatedList.itemBuilder]. However
/// item will still appear in the list for [duration] and during that time
///
the
item will still appear in the list for [duration] and during that time
/// [builder] must construct its widget as needed.
/// [builder] must construct its widget as needed.
///
///
/// This method's semantics are the same as Dart's [List.remove] method:
/// This method's semantics are the same as Dart's [List.remove] method:
...
@@ -365,16 +515,8 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
...
@@ -365,16 +515,8 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
ListView
.
builder
(
return
SliverList
(
itemBuilder:
_itemBuilder
,
delegate:
_createDelegate
(),
itemCount:
_itemsCount
,
scrollDirection:
widget
.
scrollDirection
,
reverse:
widget
.
reverse
,
controller:
widget
.
controller
,
primary:
widget
.
primary
,
physics:
widget
.
physics
,
shrinkWrap:
widget
.
shrinkWrap
,
padding:
widget
.
padding
,
);
);
}
}
}
}
packages/flutter/test/widgets/animated_list_test.dart
View file @
d2de911d
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment