原文: Animated Transition in React Native!
作者: Ji?í Otáhal
站點: Medium
這篇文章有近15k的瀏覽量克胳。 對于某些人來說陪汽,它可能不是什么,但對我來說澈驼,這是一個很大的動力。 這就是為什么我決定創(chuàng)建Pineapple?—?Financial Manager。 在僅僅22天的時間里炊昆,我完成了iOS版本,Android版本和網(wǎng)站演示威根,花費了300美元凤巨,并撰寫了一些關(guān)于這方面的文章。 不能說這次我很享受洛搀。 你也應(yīng)該嘗試一下敢茁!
最近我試圖從下一個動畫挑戰(zhàn)中獲得靈感。 由此我們?nèi)タ匆幌?a target="_blank" rel="nofollow">Ivan Parfenov?創(chuàng)建的留美。 我很好奇彰檬,如果我能夠使用React Native來實現(xiàn)這種轉(zhuǎn)換效果。 為什么我們甚至需要像這樣的動畫谎砾? 閱讀Pablo Stanley的優(yōu)秀UI動畫技巧逢倍。
For PLΛTES by Ivan Parfenov
我們可以看到這樣一組動畫。
- 工具欄平鋪(顯示/隱藏)
- 底部欄(顯示/隱藏)
- 移動選定的項目
- 隱藏所有其他項目
- 顯示詳細信息項目甚至更多景图。
關(guān)于轉(zhuǎn)換的難點在于同步所有這些動畫较雕。 我們不能真正卸載列表頁面并顯示詳細信息頁面,因為我們需要等到所有動畫完成挚币。 另外亮蒋,我很喜歡干凈的代碼。 易于維護忘晤。 如果您曾嘗試為您的項目實現(xiàn)動畫宛蚓,那么代碼通常會變得混亂。 充滿輔助變量设塔,瘋狂的計算等凄吏。這就是為什么我想介紹react-native-motion远舅。
關(guān)于react-native-motion的想法
你看到工具欄標題的動畫了嗎? 您只需將標題移動一點并以動畫的方式將透明度設(shè)置為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>
);
}
}
現(xiàn)在我們來看看如何使用react-native-motion來實現(xiàn)這一點。 我知道動畫通常非常具體随抠。 我知道React Native提供了非常強大的動畫API裁着。 無論如何,擁有一個擁有基本動畫庫會很棒拱她。
import { TranslateYAndOpacity } from 'react-native-motion';
class ToolbarTitle extends PureComponent {
render() {
return (
<TranslateYAndOpacity duration={250}>
<View>
// ...
</View>
</TranslateYAndOpacity>
);
}
}
共享元素
這一挑戰(zhàn)最大的問題是選中列表Cell的移動二驰。 這個Cell是列表頁面和詳情頁面之間共享的。 當元素實際上沒有完全定位時秉沼,如何將Cell從FlatList移動到Detail頁面的頂部桶雀? 用react-native-motion就很容易。
// 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>
);
}
}
我們在List Page中指定了SharedElement的源元素唬复。 現(xiàn)在矗积,我們需要為“詳細信息”頁面上的目標元素執(zhí)行幾乎相同的操作。 以此知道我們想要移動共享元素的位置敞咧。
// 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>
);
}
}
魔力到底在哪里棘捣?
我們?nèi)绾螌⑾鄬Χㄎ坏脑貜囊粋€頁面移動到另一個頁面? 其實妄均,我們不能柱锹。 SharedElement的工作原理是這樣的:
- 獲取源元素的位置
- 獲取目標元素的位置(顯然,如果沒有這個步驟丰包,動畫將無法啟動)
- 創(chuàng)建共享元素的一個克隆(重點的魔力H老铩)
- 在屏幕上方渲染一個新圖層
- 渲染將覆蓋源元素的克隆元素(在源元素的位置)
- 開始移動到目標位置
- 一旦到達目的地位置邑彪,移除克隆的元素
您大概可以想象在同一時刻同一個React節(jié)點有3個元素。 這是因為在移動動畫期間胧华,List Page被Detail Page覆蓋寄症。 這就是為什么我們可以看到所有3個元素。 但是我們想要創(chuàng)造一個視覺效果矩动,即我們實際上是移動了原始的源元素(實際上這只是一種錯覺)有巧。
你可以看到A點和B點。這是移動進行的時間段悲没。 你也可以看到SharedElement觸發(fā)了一些有用的事件篮迎。 在這種情況下,我們使用WillStart和DidFinish事件。 當開始移動到目的地時甜橱,將源元素和目標元素的透明度設(shè)置為0逊笆,并在動畫完成后將目標元素的透明度恢復(fù)為1。
你怎么看岂傲?
react-native-motion仍然還在維護和支持中难裆。 這絕對不是這個庫的最終穩(wěn)定版本。 但我希望這是一個好開始??我很想聽聽你對此有何看法镊掖!
原文: Animated Transition in React Native!
作者: Ji?í Otáhal
站點: Medium