Анимация изменений в SliverList

У меня сейчас есть SliverList чьи элементы загружаются динамически. Проблема заключается в том, что после загрузки этих SliverList обновления без анимации изменений, что делает переход между загрузкой и загрузкой очень резким.

я вижу это AnimatedList существует, но это не осколок, поэтому я не могу поместить его прямо в CustomScrollView,

0 ответов

Вы, наверное, знаете об этом сейчас, но можете упомянуть об этом здесь, чтобы помочь людям.

Вы можете использовать SliverAnimatedList. Достигает желаемого результата.

Конструкция SliverAnimatedList:

itemBuilderопределяет способ создания новых предметов. Строитель обычно должен возвращатьTransition виджет или любой виджет, который будет использовать animation параметр.

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

Добавление / удаление динамически

Вы делаете это, используя insertItem а также removeItem методы SliverAnimatedListState. Вы можете получить доступ к состоянию либо:

  1. предоставление Key к SliverAnimatedList и использовать key.currentState
  2. с помощью SliverAnimatedList.of(context) статический метод.

В случаях, когда вам нужно внести изменения извне списка, вам всегда нужно будет использовать ключ.

Вот полный пример, чтобы прояснить ситуацию. Элементы добавляются нажатием наFloatingActionButtonи удаляются касанием самого элемента. Я использовал какkey а также of(context) способы доступа к 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,
            )));
  }
}

Вы можете использовать неявно анимированный переупорядочиваемый список

import 'package:implicitly_animated_reorderable_list/implicitly_animated_reorderable_list.dart';
import 'package:implicitly_animated_reorderable_list/transitions.dart';
...

SliverImplicitlyAnimatedList<Comment>(
  items: comments,
  areItemsTheSame: (a, b) => a.id == b.id,
  itemBuilder: (BuildContext context, Animation<double> animation, Comment item, int index) {
    return SizeFadeTransition(
      sizeFraction: 0.7,
      curve: Curves.easeInOut,
      animation: animation,
      child: CommentSliver(
        comment: item,
      ),
    );
  },
);

У меня есть обходной путь для использования простого ListView с Sliver. Он не идеален и имеет ограничения, но он работает для случая, когда у вас есть только 2 Slivers, AppBar и SliverList.

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

Вы можете настроить дерево виджетов, но это основная идея. Оберните небольшую панель приложений в NestedScrollView и поместите список в тело.

Вы можете обернуть элементы списка в AnimatedWidget

Об этом читайте в документации AnimatedWidget

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