本文介绍了如何在不使用GlobalKey.currentState的情况下平滑更新Flutter AnimatedList?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

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

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

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

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.

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

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

否则我该怎么用?我知道我可以使用setState,但是这会导致完整的小部件刷新,在这种情况下,它似乎是屏幕上的闪光,而不是所需的AnimatedList插入内容,它很好且平滑.

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.

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

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

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

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

///更新:

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

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:

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

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.

推荐答案

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

I've had this same issue when animating the introduction of a new item in an animated list widget. As strange as it may seem you can solve this problem by checking if the state is still null:

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

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

This means that it won't try to insert the item, while rebuilding, until the state is available. Try it.

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

这篇关于如何在不使用GlobalKey.currentState的情况下平滑更新Flutter AnimatedList?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-18 13:05