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

时间:2019-11-20 19:35:09

标签: flutter flutter-animation flutter-pageview

我对飘动很陌生,我正在尝试在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 个答案:

答案 0 :(得分:1)

我不确定这是否是您要寻找的东西,但是可以。

一种方法是简单地使用Flutter中提供的小部件。其中两个将帮助您:AnimatedListDismissible

现在,您可以执行以下操作:

// 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)来简单地“自我调用”的吗?这样便可以对行本身进行动画处理(不存在)。

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

可解雇的内容预览: Dismissible removal

SizedTransition的外观预览: SizedTransition removal