Flutter PageView,我可以动画从列表中删除项目吗?

Posted

技术标签:

【中文标题】Flutter PageView,我可以动画从列表中删除项目吗?【英文标题】:Flutter PageView, can i animate removing items from list? 【发布时间】:2020-03-16 15:01:08 【问题描述】:

我是 Flutter 的新手,我正在尝试在 PageView 上做一些动画。准确地说,我想动画删除一个项目。

我尝试了多种方法来制作动画,除了解决方案之外,你们解决此类问题的方式也将有助于我的颤振技巧。

到目前为止我已经尝试过:

动画填充和不透明度 问题在于,当我在 onLongPress 中的 setState 中设置填充时,它会重建小部件并使用活动或非活动 CardPadding 再次覆盖填充(我认为) 动画宽度和高度 我似乎无法让这两个值都起作用 在 PageViewController 上为 viewportFraction 设置动画 不知道该怎么做,是否可以仅针对特定的“页面”执行此操作

下面是我迄今为止编写的(精简的)代码。

class Main extends StatefulWidget 
  @override
  _MainState createState() => _MainState();


class _MainState extends State<Main> 
  int activeCard = 0;

  EdgeInsets inActiveCardPadding = EdgeInsets.symmetric(vertical: 120.0, horizontal: 20.0);
  EdgeInsets activeCardPadding = EdgeInsets.symmetric(vertical: 105.0, horizontal: 10.0);

  PageController pageController = PageController(
    initialPage: 0,
    viewportFraction: 0.8,
  );

  @override
  Widget build(BuildContext context) 

    return Scaffold(
      body: SafeArea(
        child: Stack(
          children: <Widget>[
            PageView.builder(
              itemCount: PlantCareApp.plants.length,
              controller: pageController,
              onPageChanged: (activeCardIndex) 
                setState(() 
                  this.activeCard = activeCardIndex;
                );
              ,
              itemBuilder: (context, cardIndex) 
                return AnimatedContainer(
                  padding: (activeCard == cardIndex) ? activeCardPadding : inActiveCardPadding;,
                  duration: Duration(milliseconds: 250),
                  child: PlantCard(
                    PlantCareApp.plants[cardIndex],
                    onTap: () 
                      Navigator.pushNamed(context, PlantDetailScreen.route, arguments: PlantCareApp.plants[cardIndex]);
                    ,
                    onLongPress: () 
                      setState(() 
                        //
                        // ANIMATE OR TRIGGER ANIMATION HERE
                        //

                        // do the actual removing
                        /*
                          PlantCareApp.plants[cardIndex].remove(); // remove from db
                          PlantCareApp.plants.removeAt(cardIndex); // remove from List
                        */
                      );
                      //PlantCareApp.plants[cardIndex].remove();
                    ,
                  ),
                );
              ,
            ),
          ],
        ),
      ),
    );
  

任何帮助将不胜感激!你们将如何解决这样的问题,或者您将如何解决这个特定的用例。

我想实际上动画 viewportFraction 将是最好的,因为相邻的“页面”也会相互移动?

谢谢!

【问题讨论】:

【参考方案1】:

我不确定这是否是您要找的东西,但就是这样。

这样做的一种方法是简单地使用 Flutter 中提供的小部件。其中两个可以帮助您:AnimatedList 和 Dismissible。

现在,你可以这样做:

// define somewhere
final _animatedListGK = GlobalKey<AnimatedListState>();

// put in a function somewhere
return AnimatedList(
  key: _animatedListGK,
  padding: const EdgeInsets.all(0),
  initialItemCount: PlantCareApp.plants.length,
  itemBuilder: (context, index, animation) 
    return FadeTransition(
      opacity: animation,
      child: _buildDismissibleRow(context, index, PlantCareApp.plants[index])
    );
  
);

注意:你不必使用_animatedListGK 全局键本身,这取决于你是否可以使用AnimatedList.of(context)。虽然这是更简单的方法。

_animatedListGK 只是一个Global Key,它提供对AnimatedList 的访问,因此您可以使用动画执行插入/删除。

您的可关闭行可能类似于:

Widget _buildDismissibleRow(BuildContext context, int index, PlantModel plantModel) 
    return Dismissible(
      key: ValueKey<String>(plantModel.someKey),
      direction: DismissDirection.startToEnd,
      background: Container(color: Colors.red),
      onDismissed: (direction) 
        // You could use:
        // AnimatedList.of(context)
        _animatedListGK.currentState.removeItem(
          index,
          (context, animation) => Container(),
          duration: Duration.zero
        );
      ,
      child: _buildContent(context, index, plantModel)
    );

您也可以在没有可关闭行的情况下执行此操作,甚至可以在可关闭行的子行中执行此操作(例如_buildContent())。类似于:

// You could use:
// AnimatedList.of(context)
_animatedListGK.currentState.removeItem(
  index,
  (context, animation) 
    return FadeTransition(
      opacity: CurvedAnimation(parent: animation, curve: Interval(0.5, 1.0)),
      child: SizeTransition(
        sizeFactor: CurvedAnimation(parent: animation, curve: Interval(0.0, 1.0)),
        child: _builContent(context, index, plantModel)
      )
    );
  ,
  duration: const Duration(milliseconds: 300)
);

注意SizeTransition 是如何通过调用_builContent(context, index, plantModel) 简单地“调用自身”的?这就是您可以为行本身设置动画的方式(不存在)。

请务必观看上述文档页面中的视频!它们将有助于理解某些结构。

可解雇的外观预览:

SizedTransition 的外观预览:

【讨论】:

嗨!谢谢你的回答,我一定会试一试的。您能否告诉我 Animatedlist 是否可以水平对齐以及是否可以对齐? @GijsBeijer 我不知道。捕捉到底是什么意思? @voracios 好吧,我正在尝试创建的东西应该像 android 应用程序抽屉一样工作,所以水平刷卡,通过捕捉我的意思是动画结束时总是有一张卡正好在中间

以上是关于Flutter PageView,我可以动画从列表中删除项目吗?的主要内容,如果未能解决你的问题,请参考以下文章

flutter 基于pageview 制作上下轮播文字功能

颤动水平列表视图/页面视图,选定元素动画到全宽

Flutter PageView 自由控制状态保持

如何使用流畅的动画从页面视图中删除页面?

带有 PageView 的 Flutter 底部导航栏

Flutter - 动画列表中容器的消失