[譯] React Native 中使用轉場動畫!

這篇文章有近 15k 的瀏覽量。對某些人來講,這可能沒什麼,但對我來講是一個很大的動力。這正是我決定構建 Pineapple — Financial Manager 的緣由。僅僅 20 天,我已經完成了 iOS 版Android 版以及網頁版,花費 300 美金,並寫了幾篇關於它的文章。我沒法用言語表達我多麼享受這段時間。你也應該試試!前端

最近我試圖爲下一個動畫挑戰尋找靈感。咱們開始吧 —— 由 Ivan Parfenov 建立。我很好奇我是否可以用 React Native 來作這個過渡效果。你能夠在個人 expo 賬戶中查看結果!爲何咱們還須要這樣的動畫?來讀讀 Pablo Stanley 寫的絕佳的 UI 動畫技巧react

Ivan Parfenov 設計的 PLΛTESandroid

咱們能夠看到有幾個動畫。工具欄(顯示/隱藏),底欄(顯示/隱藏),移動所選項目,隱藏全部其餘項目,顯示詳細信息項目甚至更多。ios

動畫時間線。git

過渡動畫的難點在於同步全部這些動畫。由於咱們須要等到全部動畫都完成,咱們沒法真正移除列表頁面並顯示詳細信息頁面。此外,我對整潔的代碼有所追求。代碼要易於維護,若是您曾嘗試爲項目實現動畫,則代碼一般會變得混亂。處處都是輔助變量,各類計算等。這正是我想介紹 react-native-motion 的緣由。github

對 react-native-motion 的一個小想法

你能看到工具欄標題的動畫嗎?你只需稍微移動標題並將不透明度設置爲 0 或 1。這很簡單!但正由於如此,你須要編寫這樣的代碼,甚至在你真正開始爲該組件編寫 UI 以前。後端

class TranslateYAndOpacity extends PureComponent {
  constructor(props) {
    // ...
    this.state = {
      opacityValue: new Animated.Value(opacityMin),
      translateYValue: new Animated.Value(translateYMin),
    };
    // ...
  }
  componentDidMount() {
    // ...
    this.show(this.props);
    // ...
  }
  componentWillReceiveProps(nextProps) {
    if (!this.props.isHidden && nextProps.isHidden) {
      this.hide(nextProps);
    }
    if (this.props.isHidden && !nextProps.isHidden) {
      this.show(nextProps);
    }
  }
  show(props) {
    // ...
    Animated.parallel([
      Animated.timing(opacityValue, { /* ... */ }),
      Animated.timing(translateYValue, { /*  ... */ }),
    ]).start();
  }
  hide(props) {
    // ...
    Animated.parallel([
      Animated.timing(opacityValue, { /* ... */ }),
      Animated.timing(translateYValue, { /*  ... */ }),
    ]).start();
  }
  render() {
    const { opacityValue, translateYValue } = this.state;

    const animatedStyle = {
      opacity: opacityValue,
      transform: [{ translateY: translateYValue }],
    };

    return (
      <Animated.View style={animatedStyle}>{this.props.children}</Animated.View>
    );
  }
}
複製代碼

如今讓咱們來看看若是用 react-native-motion 實現這個動畫,要怎麼作。我知道動畫常常是很是具體的。我知道 React Native 提供了很是強大的動畫 API。不管如何,擁有一個帶有基本動畫的庫會很棒。react-native

import { TranslateYAndOpacity } from 'react-native-motion';

class ToolbarTitle extends PureComponent {
  render() {
    return (
      <TranslateYAndOpacity duration={250}>
        <View>
          // ...
        </View>
      </TranslateYAndOpacity>
    );
  }
}
複製代碼

共享的元素

這一挑戰的最大問題是移動選定的列表項。列表頁面和詳細信息頁面之間共享的項目。當元素實際上沒有絕對定位時,如何將項目從 FlatList 移動到 Detail 的頁面頂部?使用 react-native-motion 很是容易。bash

// List items page with source of SharedElement
import { SharedElement } from 'react-native-motion';

class ListPage extends Component {
  render() {
    return (
      <SharedElement id="source">
        <View>{listItemNode}</View>
      </SharedElement>
    );
  }
}
複製代碼

咱們在 ListPage 上指定了 SharedElement 的 source 元素。如今咱們須要對 DetailPage 上的目標元素執行幾乎相同的操做,來知道咱們想要移動共享元素的位置。app

// Detail page with a destination shared element
import { SharedElement } from 'react-native-motion';

class DetailPage extends Component {
  render() {
    return (
      <SharedElement sourceId="source">
        <View>{listItemNode}</View>
      </SharedElement>
    );
  }
}
複製代碼

黑科技在哪裏?

咱們如何將相對定位的元素從一個頁面移動到另外一個頁面?實際上咱們作不到。SharedElement 的工做方式以下:

  • 獲取源 element 的位置
  • 獲取目標 element 的位置(顯然,沒有這一步,動畫不能被初始化)
  • 建立共享的 element(黑科技!)
  • 在屏幕上方渲染一個新圖層
  • 渲染 element 元素,將覆蓋源 element(在源 element 的位置上)
  • 開始移動到目標 element 位置
  • 一旦移動到目標 element 位置後,刪除克隆 element

你能夠想象在同一時刻同一個 React Node 有 3 個 element。這是由於在移動動畫期間,DetailPage 會覆蓋列表頁面。這就是爲何咱們能夠看到全部 3 個元素。可是咱們想要創造一種咱們實際移動了原始 element 的幻覺。

SharedElement 的時間線。

您能夠看到 A 點和 B 點。這是移動正在執行的時間段。您還能夠看到 SharedElement 觸發一些有用的事件。在這種狀況下,咱們使用 WillStart 和 DidFinish 事件。在啓動移動目標 element 時,將源 element 和目標 element 的不透明度設置爲 0,並在動畫完成後將目標 element 的不透明度設置爲 1。

你以爲怎麼樣?

社區這裏一直不斷在維護和更新:react-native-motion。這毫不是這個庫的最終和穩定版本。可是一個好的開始 :) 我很想聽聽你怎麼想!

我一直在尋找新的挑戰和機會。若是您須要幫助,請告訴我,我很樂意討論它。

LinkedIn || Github || Twitter || Facebook || 500px

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


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

相關文章
相關標籤/搜索