在react-native開(kāi)發(fā)過(guò)程中,往往會(huì)遇到產(chǎn)品的各種關(guān)于轉(zhuǎn)場(chǎng)動(dòng)畫的需求,比如登錄頁(yè)需要從地步modal上來(lái),又或者有這種需求,push的頁(yè)面是A->B->C->D,然后他要求pop回去的路線是
D->B->A,這就是跨頁(yè)回跳,或者還有這種需求,push的頁(yè)面是A->B->D,然后pop的路線是
D->C->B->A,C頁(yè)面在push過(guò)程中并不存在。
1.modal
效果
react-navigation的StackNavigator
下的屬性mode
可以設(shè)置轉(zhuǎn)場(chǎng)效果,但是這邊一設(shè)置,就是這個(gè)導(dǎo)航下所有頁(yè)面的效果都是這個(gè),也就是要么全是push,要么全是modal,這確實(shí)比較坑,不知道最新版的有沒(méi)有其他解決方案。
最終我找到了transitionConfig
這個(gè)屬性,這個(gè)屬性可以自定義轉(zhuǎn)場(chǎng)動(dòng)畫,我在navigate
方法中傳遞一個(gè)參數(shù)為isModal
的參數(shù),默認(rèn)為false
,當(dāng)需要modal
的時(shí)候
this.props.navigation.navigate('XXX',{isModal:true})
然后在router
那設(shè)置transitionConfig
const TransitionConfiguration = () => (
{
containerStyle:{},
screenInterpolator: (sceneProps) => {
global.sceneProps = sceneProps
const { scene } = sceneProps;
const { route } = scene;
const params = route.params || {};
const isModal = params.isModal;
if (isModal){
//當(dāng)為`true`時(shí),采用`modal`效果
return CardStackStyleInterpolator.forVertical(sceneProps);
}else {
return CardStackStyleInterpolator.forHorizontal(sceneProps);
}
},
2.跨頁(yè)回跳
push:A->B->C->D pop:D->B->A
起初我們找到了goback()
方法可以傳key
,所以采用了在需要回跳的頁(yè)面設(shè)置key
,然后在之后的頁(yè)面回跳回來(lái)直接使用goback(key)
,這樣就能回到設(shè)置key
的頁(yè)面。
上面是一種思路,這是由上一個(gè)的頁(yè)面控制下一個(gè)頁(yè)面是否需要保持key,是否需要之后的頁(yè)面直接回跳到這里,前兩天又看了遍react-navigation的api,
pop: (n, params) =>
navigation.dispatch(
NavigationActions.pop({ n, immediate: params && params.immediate })
),
發(fā)現(xiàn)這個(gè)api可以傳n,經(jīng)過(guò)嘗試是可以直接傳n,控制回跳頁(yè)面數(shù)量,當(dāng)傳超過(guò)棧的數(shù)量時(shí),直接回道棧底。但是這是由后級(jí)頁(yè)面決定回跳幾個(gè)頁(yè)面的,邏輯判斷要寫在觸發(fā)回跳的頁(yè)面。
3.跨頁(yè)跳轉(zhuǎn)
push:A->B->D pop:D->C->B->A
解決方案
我仔細(xì)看了react-navigation的底層文件,發(fā)現(xiàn)了他transitionConfig
屬性可以配置轉(zhuǎn)場(chǎng)動(dòng)畫,CardStackStyleInterpolator
對(duì)象下默認(rèn)有5種動(dòng)畫
export default {
forHorizontal, //水平,正常push,從右往左
forVertical, //modal模式,從下到上
forFadeFromBottomAndroid, //安卓的效果
forFade, //fade模式
canUseNativeDriver, //閃一下
};
然后我加了一種模式forHorizontalBack
,效果類似back返回,實(shí)際上是push,新增了一個(gè)方法
function forHorizontalBack(props) {
const { layout, position, scene } = props;
if (!layout.isMeasured) {
return forInitial(props);
}
const interpolate = getSceneIndicesForInterpolationInputRange(props);
if (!interpolate) return { opacity: 0 };
const { first, last } = interpolate;
const index = scene.index;
const opacity = position.interpolate({
inputRange: [first, first + 0.01, index, last - 0.01, last],
outputRange: [0, 1, 1, 0.85, 0],
});
const width = layout.initWidth;
const { scenes } = props;
const lastSceneIndexInScenes = scenes.length - 1;
const isBack = !scenes[lastSceneIndexInScenes].isActive;
var translateX
if (isBack){
//改了動(dòng)畫后造成back的時(shí)候pop動(dòng)畫變成了push效果,所以在這邊判斷,系數(shù)用之前的,效果為pop效果
translateX = position.interpolate({
inputRange: [first, index, last],
outputRange: I18nManager.isRTL
? [-width, 0, width * 0.3]
: [width, 0, width * -0.3],
});
}else {
translateX = position.interpolate({
inputRange: [first, index, last],
outputRange: I18nManager.isRTL
? [-width, 0, width * 0.3]
: [width * -0.7, 0, width],//修改了這個(gè)系數(shù),效果是本來(lái)push從右往左變成從左往右
});
}
const translateY = 0;
return {
opacity,
transform: [{ translateX }, { translateY }],
};
}
然后在router
那設(shè)置transitionConfig
const TransitionConfiguration = () => (
{
containerStyle:{},
screenInterpolator: (sceneProps) => {
global.sceneProps = sceneProps
const { scene } = sceneProps;
const { route } = scene;
const params = route.params || {};
const isModal = params.isModal;
const isSpan = params.span;
if(isSpan){
return CardStackStyleInterpolator.forHorizontalBack(sceneProps);
}
if (isModal){
return CardStackStyleInterpolator.forVertical(sceneProps);
}else {
return CardStackStyleInterpolator.forHorizontal(sceneProps);
}
},
})
因?yàn)楸救嗽瓉?lái)是做iOS的,項(xiàng)目需要才開(kāi)始摸索react-native,開(kāi)發(fā)時(shí)間也不長(zhǎng),上面的總結(jié)如有不正確或者更好的方案,希望大神們多多指教。