Animating changes in a SliverList

后端 未结 3 1422
心在旅途
心在旅途 2021-02-12 18:24

I currently have a SliverList whose items are loaded dynamically. The issue is that once these items are loaded, the SliverList updates without animati

相关标签:
3条回答
  • 2021-02-12 19:08

    You probably know about this now, but might as well mention it here to help people.

    You can use SliverAnimatedList. It achieves the required result.

    SliverAnimatedList Construction:

    itemBuilder defines the way new items are built. The builder should typically return a Transition widget, or any widget that would use the animation parameter.

    SliverAnimatedList(
         key: someKey,
         initialItemCount: itemCount,
         itemBuilder: (context, index, animation) => SizeTransition(
                  sizeFactor: animation,
                  child: SomeWidget()
         )
    )
    

    Adding/removing dynamically

    You do that by using insertItem and removeItem methods of SliverAnimatedListState. You access the state by either:

    1. providing a Key to the SliverAnimatedList and use key.currentState
    2. using SliverAnimatedList.of(context) static method.

    In cases where you need to make changes from outside of the list, you're always going to need to use the key.

    Here's a full example to clarify things. Items are added by tapping the FloatingActionButton and are removed by tapping the item itself. I used both the key and of(context) ways to access the SliverAnimatedListState.

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    
    class SliverAnimatedListTest extends StatefulWidget {
      @override
      _SliverAnimatedListTestState createState() => _SliverAnimatedListTestState();
    }
    
    class _SliverAnimatedListTestState extends State<SliverAnimatedListTest> {
      int itemCount = 2;
    
      // The key to be used when accessing SliverAnimatedListState
      final GlobalKey<SliverAnimatedListState> _listKey =
          GlobalKey<SliverAnimatedListState>();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text("Sliver Animated List Test")),
    
          // fab will handle inserting a new item at the last index of the list.
          floatingActionButton: FloatingActionButton(
            child: Icon(Icons.add),
            onPressed: () {
              _listKey.currentState.insertItem(itemCount);
              itemCount++;
            },
          ),
    
    
          body: CustomScrollView(
            slivers: <Widget>[
              SliverAnimatedList(
                  key: _listKey,
                  initialItemCount: itemCount,
    
                  // Return a widget that is wrapped with a transition
                  itemBuilder: (context, index, animation) => 
                     SizeTransition(
                        sizeFactor: animation,
                        child: SomeWidget(
                            index: index,
    
                            // Handle removing an item using of(context) static method.
                            // Returned widget should also utilize the [animation] param
                            onPressed: () {
                              SliverAnimatedList.of(context).removeItem(
                                  index,
                                  (context, animation) => SizeTransition(
                                      sizeFactor: animation,
                                      child: SomeWidget(
                                        index: index,
                                      )));
    
                              itemCount--;
                            }),
                      ))
            ],
          ),
        );
      }
    }
    
    class SomeWidget extends StatelessWidget {
      final int index;
    
      final Function() onPressed;
    
      const SomeWidget({Key key, this.index, this.onPressed}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Padding(
            padding: const EdgeInsets.all(20.0),
            child: Center(
                child: FlatButton(
                  child: Text("item $index"), 
                  onPressed: onPressed,
                )));
      }
    }
    
    0 讨论(0)
  • 2021-02-12 19:08

    You could Wrap your list items in an AnimatedWidget

    Read about it in the docs AnimatedWidget

    0 讨论(0)
  • 2021-02-12 19:13

    I have a workaround for using a simple ListView with a Sliver. It's not perfect and it has limitations, but it works for the case where you just have 2 Slivers, the AppBar and a SliverList.

    NestedScrollView(
      headerSliverBuilder: (_, _a) => SliverAppBar(<Insert Code Here>),
      body: MediaQuery.removePadding(
        removeTop: true, 
        context: context, 
        child: AnimatedList(
          <InsertCodeHere>
        )))
    

    You can tweak around with the Widget tree, but that's the basic idea. Wrap the sliver appbar in a NestedScrollView and place the List in the body.

    0 讨论(0)
提交回复
热议问题