如何在不使用GlobalKey.currentState的情况下平滑更新Flutter AnimatedList?

时间:2019-07-05 05:04:53

标签: flutter flutter-animatedlist

我发现的将项目插入Flutter AnimatedList中的所有示例都利用GlobalKey.currentState告诉AnimatedList小部件已插入项目。从列表中删除也是一样。

众所周知,在Flutter中,GlobalKey的currentState可能为null。

就我而言,我正在等待Firebase消息通过。当出现将消息插入AnimatedList的List数据中的消息时,如果要遵循为AnimatedList显示的常见示例,则可以使用分配的GlobalKey.currentState来告诉AnimatedList插入新项目的位置。

但是,在我尝试使用它的情况下,GlobalKey.currentState为null。

否则我该怎么用?我知道我可以使用setState,但是这样会导致整个窗口小部件刷新,在这种情况下,它看上去像是在屏幕上闪烁,而不是所需的AnimatedList插入内容,它很好且平滑。

许多人都逃避了使用InheritedWidget,但是如果这是正确的技术,我不明白在这种情况下将如何实现。

/////////
// 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() );
          })
       );
}

实际结果是由于GlobalKey的currentState为null而在运行期间抛出了空指针错误。

///更新:

我尝试了AnimatedList.of(context)方法以及一个Builder来解决此问题。我以以下方式尝试过:

// 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);
}

使用上述结构时,出现以下错误:

  

AnimatedList.of()在不包含   AnimatedList。

我确定Flutter团队已经提供了一种触发Widget树外部更新的方式,但我不确定如何获取它。也许我的技术不正确。

1 个答案:

答案 0 :(得分:1)

在动画列表小部件中为新项目引入动画时,我遇到了同样的问题。看起来似乎很奇怪,您可以通过检查状态是否仍然为null来解决此问题:

if(animatedListKey.currentState != null)
  animatedListKey.currentState.insertItem(0);

这意味着在重建状态之前,它将不会尝试插入项目,直到状态可用为止。试试吧。

您可以在此处查看我的教程中的代码:https://github.com/Morthor/flutter_todo_app_talk/blob/youtube_animatedList/lib/main.dart