[译] 使用 Flutter 制做 3D 翻转动画

从 UI 挑战中学习 Flutter前端

做为个人第一篇文章的续篇,我将开始新的挑战。这个将比前一个(微光闪烁)复杂一点。我称之为翻转动画:android

这已经足够值得挑战了,不是吗?是的,咱们将制做一个看起来有些 3D 效果的动画。ios

怎么作呢

乍一看,有个很简单的想法:咱们有一堆面板,每一个面板被分红两半,每一半能够围绕 X 轴旋转并显示下一个面板。git

如何用代码实现呢?我把它分为了两个小任务:github

  • 将面板分割为两半
  • 围绕 X 轴旋转一半面板

那么 Flutter 如何帮助咱们呢?查看 Flutter 文档,我发现有两个组件很是适合完成任务:ClipRectTransform后端

实现

  • 将面板分割为两半:

ClipRect 组件有一个 clipper 参数来定义裁剪矩形的大小和位置,可是文档建议另外一种使用 ClipRect 的方法:将它与 Align 一块儿使用:bash

class FlipWidget extends StatelessWidget {
  Widget child;

  FlipWidget({Key key, this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        ClipRect(
            child: Align(
          alignment: Alignment.topCenter,
          heightFactor: 0.5,
          child: child,
        )),
        Padding(
          padding: EdgeInsets.only(top: 2.0),
        ),
        ClipRect(
            child: Align(
          alignment: Alignment.bottomCenter,
          heightFactor: 0.5,
          child: child,
        )),
      ],
    );
  }
}
复制代码

尝试一下:markdown

就是这样。此外,child 可让咱们为所欲为设计动画的内容(不管如何是文本,仍是图像)。less

  • 围绕 X 轴旋转一半面板

Transform 组件有一个 transform 参数,类型是 Matrix4,用于定义所应用的变换类型。Matrix4 暴露了一个名为 rotationX() 的工厂构造函数,看起来是咱们须要用的,让咱们尝试一下用在面板的上半部分:ide

@override
Widget build(BuildContext context) {
   return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Transform(
          transform: Matrix4.rotationX(pi / 4),
          alignment: Alignment.bottomCenter,
          child: ClipRect(
              child: Align(
            alignment: Alignment.topCenter,
            heightFactor: 0.5,
            child: child,
          )),
        ),
        ...
      ],
    );
  }
复制代码

尝试一下:

什么!!!!它看起来像放缩效果,不是吗?

到底怎么回事呢?回答出这个问题是这个任务中最难的一点。我回看 Flutter 的文档、示例代码、文章……直到找到这篇文章。其中指出,改变 Matrix4 的第 3 行和第 2 列的值,会改变其视角,而且会给变形带来 3D 效果:

...
Transform(
  transform: Matrix4.identity()..setEntry(3, 2, 0.006)..rotateX(pi / 4),
  alignment: Alignment.bottomCenter,
  child: ClipRect(
      child: Align(
    alignment: Alignment.topCenter,
    heightFactor: 0.5,
    child: child,
  )),
),
...
复制代码

再试一下:

不错。可是不如试一下神奇的数字 0.006?说实话,我不知道如何准确计算它,只是尝试选个我感受很好的一些值。

剩下的就是为咱们的组件添加动画。这里有一点点棘手。实际上,每一个面板都有两面(正面和背面)的内容,可是在代码中实现它并不明智,由于同一时刻只能看到一面。我假设要建立一个面板向上翻转的动画,那么动画能够分解成连续的两个阶段(顺序),第一个是向上翻转下半部分以使动画显示下一个面板的下半部分,而后隐藏当前面板的下半部分,第二个是在同一方向翻转上半部分,以显示下一半的上半部分,同时隐藏当前的上半部分:

这个动画实现的代码很长,在此处插入并不太好。你能够在本文底部的连接中找到它。这是咱们的最终效果:

真棒。咱们刚刚用 Flutter 完成了另外一个 UI 挑战。熟能生巧。我会继续寻找新的挑战,使用 Flutter 解决它,并与你分享结果。感谢阅读。

P/S:透视变换出现了个小问题(会致使变换后的图像偏斜),我在 rotateX() 中使用一个很是小的值而不是零,能够暂时解决这个问题。

完整代码: gist.github.com/hnvn/f1094f…

我已将个人代码发布,包名为 flip_panel

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏