前序
優(yōu)秀的交互設計師在參考了京東的過渡動畫后也想在我們的產(chǎn)品上增加類型的效果,在經(jīng)過一番的Google和思考后覺得還是可以實現(xiàn)的,難度沒有想象中的那么大,這里只是做一下總結(jié)。
效果圖
GIF畫質(zhì)較渣,在模擬器上會出現(xiàn)閃動一下,但是在真機上不會出現(xiàn),可以忽略這一點。

屏蔽react-navigation默認的過渡動畫
關(guān)于react-navigation的使用,這里不做詳細的說明,如有需要了解的可戳這里
在創(chuàng)建createStackNavigator的時候,我們可以定制其相應的屬性值,其中有一個transitionConfig屬性值,官方的解釋是用于返回一個屏幕過渡對象的函數(shù),該對象中也包含了其他的屬性,如下代碼所示
/**
* Describes a visual transition from one screen to another.
*/
declare export type TransitionConfig = {
// The basics properties of the animation, such as duration and easing
transitionSpec?: NavigationTransitionSpec,
// How to animate position and opacity of the screen
// based on the value generated by the transitionSpec
screenInterpolator?: (props: NavigationSceneRendererProps) => {},
// How to animate position and opacity of the header componetns
// based on the value generated by the transitionSpec
headerLeftInterpolator?: (props: NavigationSceneRendererProps) => {},
headerTitleInterpolator?: (props: NavigationSceneRendererProps) => {},
headerRightInterpolator?: (props: NavigationSceneRendererProps) => {},
// The style of the container. Useful when a scene doesn't have
// 100% opacity and the underlying container is visible.
containerStyle?: ViewStyleProp,
};
其中我們可以看下screenInterpolator的作用,他是用來配置屏幕過渡動畫的。
因為我們需要實現(xiàn)特殊的過渡動畫,那么我們需要將默認的過渡動畫給取消,代碼如下
const TransitionConfiguration = () => ({
screenInterpolator: (sceneProps) => {
const {scene} = sceneProps
const {route} = scene
const params = route.params || {}
const routeName = sceneProps.scene.route.routeName
const transition = params.transition || 'forHorizontal'
if (routeName === 'SecondPage'){ \\當進入SecondPage頁面的時候,取消默認的過渡動畫
return null
}
return StackViewStyleInterpolator[transition](sceneProps)
},
transitionSpec: {
duration: 350,
easing: Easing.out(Easing.poly(4)),
timing: Animated.timing,
}
})
const StackNavigatorConfig = {
initialRouteName:'FirstPage',
headerMode: 'screen',
mode:'card',
transitionConfig: TransitionConfiguration,
}
同時我們需要注意一下StackViewStyleInterpolator 的引用:
在react-navigation的2.11.2之前:
import StackViewStyleInterpolator from 'react-navigation/src/views/StackView/StackViewStyleInterpolator'
在react-navigation的2.11.2之后:
import StackViewStyleInterpolator from 'react-navigation-stack/dist/views/StackView/StackViewStyleInterpolator'
自定義過渡動畫
這一部分要根據(jù)實際的場景去實現(xiàn),一般由設計師來決定。其實我們是沒有辦法自定義這個過渡動畫的,除非去修改源碼,但是那樣做的難度和風險都比較的大,為了實現(xiàn)這樣的“效果”,我只是在第一個頁面過渡之前加載了一段動畫,在動畫結(jié)束之后再進行跳轉(zhuǎn),因為取消了react-navigation默認的過渡的動畫,所以可以快速的展示出第二個頁面。同時為了保證整個過渡過程的流程性,第一個頁面結(jié)束時的樣子和第二個頁面開始時的樣子保持一致就OK。
第一個頁面的動畫是在點擊了某一個Item之后,在頁面的最上面一層添加一個全屏的View進行動畫,跟ListView無任何的關(guān)系。你們會發(fā)現(xiàn)有一些共用的地方(圖片+名稱),這其實是使用RN提供的UIManager.measure方法獲取到點擊事件的位置,然后計算出圖標和名稱的位置,在最上面一層的View渲染另一個圖標和名稱,從而做到以假亂真的目的。
因為該過渡動畫的重用性不太高,這里就不全部展示出來了。
_startAnimated (rowData, event) {
this.props.navigation.setParams({enable: true})
UIManager.measure(event.target, (x, y, width, height, pageX, pageY) => {
this.setState({
isShowItemModel: true,
currentDataSource: rowData,
currentClickY: pageY - 64,
showReView: false,
})
})
}
在動畫結(jié)束之后,執(zhí)行跳轉(zhuǎn)動作。
this.props.navigation.navigate('SecondPage')
注意點
因為最上層的View只覆蓋了導航欄一下的部分,所以導航欄上面的按鈕還是可以點擊的,所以在執(zhí)行動畫的過程中需要禁止掉按鈕點擊事件。因為導航按鈕是在react-navigation屬性中配置的,所以只能在this.props.navigation.params中添加一個變量來控制按鈕的點擊。
static navigationOptions = ({navigation, screenProps}) => ({
title: 'FirstPage', // 固定標題
headerRight: <TouchableOpacity style={{marginRight:20}}
disabled={navigation.state.params ? navigation.state.params.disable : false}
onPress={() => {
const {params = {}} = navigation.state
params.showAlert()
}}><Text style={{fontSize: 14,color: '#333'}}>新增</Text></TouchableOpacity>
})
componentDidMount () {
this.props.navigation.setParams({showAlert: this.showAlert.bind(this),disable: false})
}
goSecondPage() {
this.props.navigation.setParams({disable: true})
this.staggerAnimated.start(()=>{
this.props.navigation.navigate('SecondPage')
this.props.navigation.setParams({disable: false})
this.staggerAnimated.reset()
})
}
結(jié)束語
該過渡動畫的實現(xiàn)也不是太過于復雜,希望這篇文章給你有幫助。寫了一個簡單的小Demo,希望可以幫助你理解。