How to smoothly update a Flutter AnimatedList without using a GlobalKey.currentState?

最后都变了- 提交于 2019-12-07 23:54:22

问题


All examples I have found of inserting items into a Flutter AnimatedList utilize a GlobalKey.currentState to tell the AnimatedList widget that an item has been inserted. Same thing with delete from the list.

It is known that in Flutter a GlobalKey's currentState may be null.

In my case, I am waiting on a Firebase message to come through. When it appears that message is inserted into the AnimatedList's List data and if one were to follow the prevalent examples shown for AnimatedList one would use the assigned GlobalKey.currentState to tell the AnimatedList where the new item was inserted.

But, in my case when I attempt to use it, the GlobalKey.currentState is null.

What can I use otherwise? I know I can use setState but that causes a full widget refresh which appears in this case to be a flash on the screen rather than the desired AnimatedList insert which is nice and smooth.

Many people have eluded to using an InheritedWidget but I cannot understand how it would be implemented in this case if that is the correct technique.

/////////
// NOTE:  This is close to real code, but consider it pseudocode since it is a cut and paste from the real code less quite a bit of extra  stuff I have in there.  It certainly will not compile but it is representative of the issue.
///////// 

class Conversation extends StatefulWidget {
  Conversation({Key key, @required this.cid, this.notificationsHub}) : super(key: key);

  // A bit of a hack here, but my Firebase cloud messages come through this object
  MyNotificationsHub notificationsHub;

  // a conversation id 
  final int cid;

  @override
  ConversationState createState() => ConversationState(cid: this.cid, notificationsHub: notificationsHub);
}

//////////

class ConversationState extends State<Conversation> 
    with MyNotificationsListener {
       ConversationState({Key key, @required this.cid, this.notificationsHub}); // : super(key: key);

MyNotificationsHub notificationsHub;

List<ConversationFeed> feed = List();

// The GlobalKey keeps track of the visible state of the list items
// while they are being animated.
final GlobalKey<AnimatedListState> _listKey = GlobalKey();

///////////

initState() {
    notificationsHub.addNotificationsListener(this);
}

///////////
// This is where the issue occurs, when a Firebase message comes in and I attempt to use the GlobalKey the currentState component is null
///////////
void receiveAlert ( MyNotificationItem alert ){
  int insertIndex=0;

  feed.insert(insertIndex, new ConversationFeed( alert ) );

  //******* Issue below, null currentState *******
  _listKey.currentState.insertItem(insertIndex);
  //******* Issue above, null currentState *******
}

////////////

 @override
  Widget build(BuildContext context) {
     return Scaffold(
        appBar: AppBar(
          title: Text("Conversation")),
        body: 

          new AnimatedList(

            // Give the Animated list the global key
            key: _listKey,

            initialItemCount: feed.length,

            itemBuilder: (context, index, animation) {
            return ListTile(
                title: Text ( feed[index].getMessageContentsString() );
          })
       );
}

Actual results are a null pointer error being thrown during running due to the GlobalKey's currentState being null.

/// Updates:

I tried the AnimatedList.of(context) method along with a Builder to solve this problem. I tried it in the following manner:

// Declared an instance variable of BuildContext in my class definition

BuildContext acontext;

// in the Builder call I assigned it in the following manner:

body: Builder(
            builder: (BuildContext zcontext) { 
              acontext = zcontext ;
              return ( AnimatedList (....) ); }
            )

// & inside my receiveAlert method I used it in the following manner:

void receiveAlert ( MyNotificationItem alert ){
 ....
 AnimatedList.of(acontext).insertItem(insertIndex);
}

When using the above constructs I get the following error:

AnimatedList.of() called with a context that does not contain an AnimatedList.

I'm sure the Flutter team has provided a manner to trigger an update external to the Widget tree, I'm just not sure how to get to it. Perhaps my techniques are incorrect.

来源:https://stackoverflow.com/questions/56896814/how-to-smoothly-update-a-flutter-animatedlist-without-using-a-globalkey-currents

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!