[譯] 使用 Flutter 製作 3D 翻轉動畫

ALVIN君發表於2018-07-23

從 UI 挑戰中學習 Flutter

作為我的第一篇文章的續篇,我將開始新的挑戰。這個將比前一個(微光閃爍)複雜一點。我稱之為翻轉動畫:

[譯] 使用 Flutter 製作 3D 翻轉動畫

這已經足夠值得挑戰了,不是嗎?是的,我們將製作一個看起來有些 3D 效果的動畫。

怎麼做呢

乍一看,有個很簡單的想法:我們有一堆皮膚,每個皮膚被分成兩半,每一半可以圍繞 X 軸旋轉並顯示下一個皮膚。

如何用程式碼實現呢?我把它分為了兩個小任務:

  • 將皮膚分割為兩半
  • 圍繞 X 軸旋轉一半皮膚

那麼 Flutter 如何幫助我們呢?檢視 Flutter 文件,我發現有兩個元件非常適合完成任務:ClipRectTransform

實現

  • 將皮膚分割為兩半:

ClipRect 元件有一個 clipper 引數來定義裁剪矩形的大小和位置,但是文件建議另一種使用 ClipRect 的方法:將它與 Align 一起使用:

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,
        )),
      ],
    );
  }
}
複製程式碼

嘗試一下:

[譯] 使用 Flutter 製作 3D 翻轉動畫

就是這樣。此外,child 可以讓我們隨心所欲設計動畫的內容(無論如何是文字,還是影象)。

  • 圍繞 X 軸旋轉一半皮膚

Transform 元件有一個 transform 引數,型別是 Matrix4,用於定義所應用的變換型別。Matrix4 暴露了一個名為 rotationX() 的工廠建構函式,看起來是我們需要用的,讓我們嘗試一下用在皮膚的上半部分:

@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 製作 3D 翻轉動畫

什麼!!!!它看起來像放縮效果,不是嗎?

到底怎麼回事呢?回答出這個問題是這個任務中最難的一點。我回看 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,
  )),
),
...
複製程式碼

再試一下:

[譯] 使用 Flutter 製作 3D 翻轉動畫

不錯。但是不如試一下神奇的數字 0.006?說實話,我不知道如何準確計算它,只是嘗試選個我感覺很好的一些值。

剩下的就是為我們的元件新增動畫。這裡有一點點棘手。實際上,每個皮膚都有兩面(正面和背面)的內容,但是在程式碼中實現它並不明智,因為同一時刻只能看到一面。我假設要建立一個皮膚向上翻轉的動畫,那麼動畫可以分解成連續的兩個階段(順序),第一個是向上翻轉下半部分以使動畫顯示下一個皮膚的下半部分,然後隱藏當前皮膚的下半部分,第二個是在同一方向翻轉上半部分,以顯示下一半的上半部分,同時隱藏當前的上半部分:

[譯] 使用 Flutter 製作 3D 翻轉動畫

這個動畫實現的程式碼很長,在此處插入並不太好。你可以在本文底部的連結中找到它。這是我們的最終效果:

[譯] 使用 Flutter 製作 3D 翻轉動畫

真棒。我們剛剛用 Flutter 完成了另一個 UI 挑戰。熟能生巧。我會繼續尋找新的挑戰,使用 Flutter 解決它,並與你分享結果。感謝閱讀。

P/S:透視變換出現了個小問題(會導致變換後的影象偏斜),我在 rotateX() 中使用一個非常小的值而不是零,可以暫時解決這個問題。

完整程式碼: gist.github.com/hnvn/f1094f…

我已將我的程式碼釋出,包名為 flip_panel

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章