- 原文地址:Animated Transition in React Native!
- 原文做者:Jiří Otáhal
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:talisk
- 校對者:foxxnuaa
這篇文章有近 15k 的瀏覽量。對某些人來講,這可能沒什麼,但對我來講是一個很大的動力。這正是我決定構建 Pineapple — Financial Manager 的緣由。僅僅 20 天,我已經完成了 iOS 版,Android 版以及網頁版,花費 300 美金,並寫了幾篇關於它的文章。我沒法用言語表達我多麼享受這段時間。你也應該試試!前端
最近我試圖爲下一個動畫挑戰尋找靈感。咱們開始吧 —— 由 Ivan Parfenov 建立。我很好奇我是否可以用 React Native 來作這個過渡效果。你能夠在個人 expo 賬戶中查看結果!爲何咱們還須要這樣的動畫?來讀讀 Pablo Stanley 寫的絕佳的 UI 動畫技巧。react
Ivan Parfenov 設計的 PLΛTES。android
咱們能夠看到有幾個動畫。工具欄(顯示/隱藏),底欄(顯示/隱藏),移動所選項目,隱藏全部其餘項目,顯示詳細信息項目甚至更多。ios
動畫時間線。git
過渡動畫的難點在於同步全部這些動畫。由於咱們須要等到全部動畫都完成,咱們沒法真正移除列表頁面並顯示詳細信息頁面。此外,我對整潔的代碼有所追求。代碼要易於維護,若是您曾嘗試爲項目實現動畫,則代碼一般會變得混亂。處處都是輔助變量,各類計算等。這正是我想介紹 react-native-motion 的緣由。github
你能看到工具欄標題的動畫嗎?你只需稍微移動標題並將不透明度設置爲 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 的工做方式以下:
你能夠想象在同一時刻同一個 React Node 有 3 個 element。這是由於在移動動畫期間,DetailPage 會覆蓋列表頁面。這就是爲何咱們能夠看到全部 3 個元素。可是咱們想要創造一種咱們實際移動了原始 element 的幻覺。
SharedElement 的時間線。
您能夠看到 A 點和 B 點。這是移動正在執行的時間段。您還能夠看到 SharedElement 觸發一些有用的事件。在這種狀況下,咱們使用 WillStart 和 DidFinish 事件。在啓動移動目標 element 時,將源 element 和目標 element 的不透明度設置爲 0,並在動畫完成後將目標 element 的不透明度設置爲 1。
社區這裏一直不斷在維護和更新:react-native-motion。這毫不是這個庫的最終和穩定版本。可是一個好的開始 :) 我很想聽聽你怎麼想!
我一直在尋找新的挑戰和機會。若是您須要幫助,請告訴我,我很樂意討論它。
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。