Как плавно обновить Flutter AnimatedList без использования GlobalKey.currentState?

Все примеры, которые я нашел для вставки элементов во Flutter AnimatedList, используют GlobalKey.currentState, чтобы сообщить виджету AnimatedList, что элемент был вставлен. То же самое с удалением из списка.

Известно, что в Flutter значение currentState у GlobalKey может быть нулевым.

В моем случае, я жду сообщения Firebase, чтобы пройти. Когда кажется, что сообщение вставлено в данные Списка AnimatedList и если нужно следовать распространенным примерам, показанным для 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() );
          })
       );
}

Фактические результаты - ошибка нулевого указателя, возникающая во время работы из-за того, что currentKtate GlobalKey имеет значение 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 предоставила способ запуска обновления, внешнего по отношению к дереву виджетов, я просто не знаю, как к нему добраться. Возможно, мои методы неверны.

0 ответов

У меня была такая же проблема при анимации введения нового элемента в виджет анимированного списка. Как ни странно, вы можете решить эту проблему, проверив, остается ли состояние нулевым:

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

Это означает, что он не будет пытаться вставить элемент во время перестройки, пока состояние не станет доступным. Попробуй это.

Вы можете проверить код из моего руководства здесь: https://github.com/Morthor/flutter_todo_app_talk/blob/youtube_animatedList/lib/main.dart

Другие вопросы по тегам