Flutter AnimatedList - Добавление CurvedAnimation в SlideTransition

Мне удалось добраться до точки, когда у меня есть AnimatedList, который будет вставлять новые добавленные элементы. Виджет Dismissible, который обертывает мои элементы списка, управляет анимацией удаления. Мой вопрос в том, как я могу добавить какую-то кривую анимации к SlideTransition, чтобы я мог контролировать, как новый элемент списка появляется, когда он вставляется. Вот где я сейчас нахожусь:

@override
Widget build(BuildContext context) {
final checklists = Provider.of<Checklists>(context);

return AnimatedList(
  key: listKey,
  initialItemCount: checklists.lists.length,
  itemBuilder: (ctx, i, animation) {
    return SlideTransition(
      position: CurvedAnimation(parent: ).drive(child)  // <- this line needs changing
      child: _buildListItem(checklists.lists[i], i),          
    );
  },      
);
}

Я не уверен, что делать с аргументом position. Раньше для стандартного SlideTransition я просто использовал

animation.drive(Tween(begin: Offset(0.2, 0), end: Offset(0.0, 0))),

который работает нормально, но ему не хватает плавности хода. Любые идеи?

Редактировать Вот полный файл .dart для ясности, а также место, куда я вставляю новый элемент из родительского виджета:

GlobalKey<AnimatedListState> recentListsAnimationKey = GlobalKey();

class RecentLists extends StatefulWidget {
  @override
  _RecentListsState createState() => _RecentListsState();
}

class _RecentListsState extends State<RecentLists>
    with TickerProviderStateMixin {
  Widget _buildListItem(Checklist list, int listIndex) {
    return Dismissible(
      key: ObjectKey(list.id),
      direction: DismissDirection.endToStart,
      background: Container(
        alignment: AlignmentDirectional.centerEnd,
        color: Theme.of(context).accentColor,
        child: Padding(
          padding: EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
          child: Icon(
            Icons.delete,
            color: Colors.white,
          ),
        ),
      ),
      child: ListTile(
        onTap: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (ctx) => ListItemsScreen(list.id),
            ),
          );
        },
        title: Text(list.name),
        leading: Checkbox(
          value: list.completed,
          onChanged: (value) {
            setState(() {
              list.completed = value;
            });
          },
        ),
      ),
      onDismissed: (direction) {
        _onDeleteList(list, listIndex);
      },
    );
  }

  void _onDeleteList(Checklist list, int listIndex) {
    Provider.of<Checklists>(context).deleteList(list.id);
    recentListsAnimationKey.currentState
        .removeItem(listIndex, (_, __) => Container());

    Scaffold.of(context).showSnackBar(
      SnackBar(
        action: SnackBarAction(
          label: 'UNDO',
          onPressed: () {
            Provider.of<Checklists>(context).undoDeleteList(list, listIndex);
            recentListsAnimationKey.currentState
                .insertItem(listIndex, duration: Duration(milliseconds: 100));
          },
        ),
        content: Text(
          'List deleted',
          style: TextStyle(color: Theme.of(context).accentColor),
        ),
      ),
    );
  }

  AnimationController _controller;
  Animation<Offset> _position;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(milliseconds: 200),
      vsync: this,
    );
    _position = Tween(
      begin: Offset(0.5, 0),
      end: Offset(0.0, 0),
    ).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Curves.decelerate,
      ),
    );
    _controller.forward();
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final checklists = Provider.of<Checklists>(context);

    return AnimatedList(
      key: recentListsAnimationKey, 
      initialItemCount: checklists.lists.length,
      itemBuilder: (ctx, i, animation) {
        return SlideTransition(
          position: _position,
          child: _buildListItem(checklists.lists[i], i),
        );
      },
    );
  }
}

Здесь я вставляю новые элементы в список. Слайд-анимация не отображается.

void createNewList(BuildContext context) {
  if (nameController.text.isNotEmpty) {
    Provider.of<Checklists>(context).addList(nameController.text);
    recentListsAnimationKey.currentState.insertItem(0, duration: Duration(milliseconds: 100));
    nameController.clear();
   }
    Navigator.of(context).pop();
  }

person rejy11    schedule 19.11.2019    source источник


Ответы (2)


Используйте функцию Animation.drive с CurveTween, привязанный к вашему смещенному Tween. Ваш itemBuilder должен выглядеть так:

itemBuilder: (ctx, i, animation) {
    return SlideTransition(
      position: animation.drive(Tween(begin: Offset(2, 0.0), end: Offset(0.0, 0.0))
            .chain(CurveTween(curve: Curves.elasticInOut))),
      child: _buildListItem(checklists.lists[i], i),          
    );
  },
person Baalint02    schedule 02.04.2020

В Flutter Animation - это просто класс, который изменяет данные от начала до конца на основе процента, предоставленного AnimationController. Вы должны подготовить position, какой экземпляр Animation<Offset>.

class DemoWidget extends StatefulWidget {
  @override
  _DemoWidgetState createState() => _DemoWidgetState();
}

class _DemoWidgetState extends State<DemoWidget>with TickerProviderStateMixin {
  AnimationController _controller;
  Animation<Offset> _position;

  @override
  Widget build(BuildContext context) {
    final checklists = Provider.of<Checklists>(context);

    return AnimatedList(
      key: listKey,
      initialItemCount: checklists.lists.length,
      itemBuilder: (ctx, i, animation) {
        return SlideTransition(
          position: _position,
          child: _buildListItem(checklists.lists[i], i),          
        );
      },      
    );
  }

  @override
  initState() {
    super.initState();
    _controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
    _position = Tween(begin: Offset(0.2, 0), end: Offset(0.0, 0)).animate(CurvedAnimation(parent: _controller, curve: Curves.decelerate));
    _controller.forward();
  }

  @override
  dispose() {
    _controller.dispose();
    super.dispose();
  }
}
person Trần Đức Tâm    schedule 20.11.2019
comment
Это работает для начальных элементов в списке, но когда я добавляю элемент, он не анимируется. Как анимировать добавление элементов в список? - person rejy11; 20.11.2019
comment
: / Задайте новый вопрос и разместите ссылку здесь. Или вы можете управлять анимацией с помощью _controller. - person Trần Đức Tâm; 20.11.2019
comment
Я отредактировал свой вопрос, чтобы показать больше кода для лучшего контекста. Анимация слайдов теперь работает при первоначальной загрузке списка, но при добавлении новых элементов анимация слайдов отсутствует. - person rejy11; 20.11.2019