之前寫過react-navigation使用技巧,那篇文章中主要講了react-navigation的屬性铭污,封裝和一些小技巧恋日。雖然上篇文章中也有一些小技巧,但因為補充的比較晚嘹狞,導致有些人沒有看全岂膳,再加上我又找到了一些新的小玩意,特此寫了本篇文章磅网,如果之后還有新發(fā)現(xiàn)谈截,也會再這篇文章中更新出來。
如果遇到什么問題可以在評論區(qū)回復涧偷,或者加QQ群397885169詢問
1簸喂、讓TabBar擁有點擊事件
在react-navigation
beta13版本之后,已經默認支持點擊事件了嫂丙,它被放在了TabNavigator
中娘赴,屬性名為tabBarOnPress
,內部提供了兩個屬性跟啤,一個方法({ route, index } , jumpToIndex)诽表,使用方法如下:
tabBarOnPress:(obj)=>{
console.log(obj);
obj.jumpToIndex(obj.scene.index)
},
最新幾個版本的react-navigation
中唉锌,將代碼和文件路徑修改了,所以之前的方式失效了竿奏,在這里提供一個新的方法來修改Tabbar的點擊事件袄简。
#### 原文鏈接
一共要修改添加大大小小12處地方哦!涉及4個js文件泛啸。 這個修改已經被作者提交到react-navigation
中了绿语,希望在以后的更新中可以看到這次更新。
使用方法
static navigationOptions = ({navigation,screenProps}) => ({
headerTitle:'首頁',
tabBarOnPress: (scene,jumpToIndex) => {
console.log(scene);
jumpToIndex(scene.index)
},
});
~~ 注意:如果調用了tabBarOnPress
方法候址,會默認關閉點擊跳轉事件吕粹,需要手動開啟。岗仑!~~
以下代碼已被廢棄
感謝群友再遇見
的分享匹耕。
官方的api里面是沒有提供tabBar的點擊事件的,但在開發(fā)中經常需要監(jiān)聽tabBar的點擊事件荠雕,解決這個問題的一種方法就是去修改源碼稳其,另一種是監(jiān)聽onTransitionEnd
。(第二種方法這里先不討論)
源碼中一共需要修改8處地方炸卑,包含3個js文件既鞠。源碼在下面。
1盖文、react-navigation目錄下src/views/TabView/TabBarBottom.js
2嘱蛋、react-navigation目錄下src/views/TabView/TabBarTop.js
3、react-navigation目錄下src/views/TabView/TabView.js
#### 注意:第111行中的getScreenConfig
需要手動改成getScreenOptions
五续,要不然修改完源碼會報錯浑槽。
#### 源碼在這里,要注意修改getScreenOptions
修改源碼之后返帕,在頁面中這么用:
static navigationOptions = ({navigation,screenProps}) => ({
onTabPress:(()=>{
alert('Home');
})
});
2、修改頁面的跳轉動畫
在上一篇文章中篙挽,說了怎么將安卓的跳轉動畫改成iOS那樣的荆萤,但其實react-navigation
一共提供了4種跳轉動畫:
1、從右向左: forHorizontal
铣卡;
2链韭、從下向上: forVertical
;
3煮落、安卓那種的從下向上: forFadeFromBottomAndroid
敞峭;
4、無動畫: forInitial
蝉仇。
但因為庫的限制旋讹,想實現(xiàn)某些頁面使用某種動畫還是很難的殖蚕,只能通過Demo中提供的笨方法來實現(xiàn)。
首先還是導入react-navigation
中的方法
import CardStackStyleInterpolator from 'react-navigation/src/views/CardStack/CardStackStyleInterpolator';
2.0
import StackViewStyleInterpolator from 'react-navigation/src/views/StackView/StackViewStyleInterpolator';
如果要改變跳轉動畫只能在StackNavigator
中實現(xiàn)transitionConfig
方法
const MainStack = StackNavigator({
Main:{
screen:Main,
},
},{
// mode:'modal',
headerMode: 'screen',
transitionConfig:()=>({
// 只要修改最后的forVertical就可以實現(xiàn)不同的動畫了沉迹。
screenInterpolator:CardStackStyleInterpolator.forVertical,
})
});
3睦疫、在Reset方法中傳參
react-navigation
中的reset
方法,應該都不陌生吧鞭呕,重置路由蛤育。但有的需求是在登陸之后,重置路由并傳遞參數(shù)到某個頁面葫松,之前一直以為不可以瓦糕,直到群友的react-native reset方法中傳參的寫法的這篇文章出現(xiàn),感謝群友nextChampion
的貢獻腋么。
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({routeName: 'Home', params: { token: '123456' }})
]
})
this.props.navigation.dispatch(resetAction);
在頁面中可以通過如下方法得到參數(shù)咕娄。
this.props.navigation.state.params.token
4、goBack返回指定頁面
在上篇文章中也有這個技巧党晋,這里是總結重發(fā)谭胚。
react-navigation目錄下src/routers/StackRouter.js
if (action.type === NavigationActions.BACK) {
let backRouteIndex = null;
if (action.key) {
const backRoute = state.routes.find(
/* $FlowFixMe */
/* 修改源碼 */
route => route.routeName === action.key
/* (route: *) => route.key === action.key */
);
/* $FlowFixMe */
console.log('backRoute =====',backRoute);
backRouteIndex = state.routes.indexOf(backRoute);
console.log('backRoute =====',backRouteIndex);
}
if (backRouteIndex == null) {
return StateUtils.pop(state);
}
if (backRouteIndex >= 0) {
return {
...state,
routes: state.routes.slice(0, backRouteIndex+1),
index: backRouteIndex - 1 + 1,
};
}
}
注意:這樣的修改源碼之后,如果項目中使用Redux未玻,并且啟用了滑動返回灾而,很會很大幾率導致app卡死,所以并不太推薦這種方式扳剿,最好使用下面的方式
5旁趟、react-navigation集成Redux
可能會有人認為這樣集成會麻煩,而且react-navigation
內部實現(xiàn)也是類似Redux
的高階函數(shù)庇绽。我之前也是這么認為的锡搜,直到在識兔中,使用 Redux 修改首頁圖片之后 滑動返回 會導致app卡死瞧掺。
react-navigation集成Redux之后耕餐,能獲取當前screen
的key
题禀,routeNmae
等參數(shù)玻孟,goBack()
的時候就可以直接取到key
琐脏,而不用修改源碼啦蓝谨!
具體操作步驟可以在識兔雁刷,一款用來識別圖片的開源項目中查看沮峡。
如果看不懂下面的修改步驟钧唐,可以先看下之前的文章Redux "使用"教程
集成
1征候、添加addNavigationHelpers
import {
StackNavigator,
TabNavigator,
addNavigationHelpers
} from 'react-navigation';
2壹蔓、首先修改識兔中的App.js
的導出方式
const AppWithNavigationState = ({ dispatch, nav }) => (
<MyApp navigation={addNavigationHelpers({ dispatch, state: nav })}/>
);
const mapStateToProps = state => ({
nav: state.nav,
});
export default connect(mapStateToProps)(AppWithNavigationState);
3趟妥、創(chuàng)建StackReducer
// MyApp 是在App.js中導出的
import { MyApp } from '../APP';
export default function StackReducer(state , action) {
let nextState;
switch (action.type) {
default:
nextState = MyApp.router.getStateForAction(action, state);
break;
}
return nextState || state;
}
4、修改rootReducer
import nav from './StackReducer';
const RootReducer = combineReducers({
...,
nav,
});
export default RootReducer;
使用
1佣蓉、修改ShiTu.js
export default connect((state) => {
...
const routes = state.nav.routes;
return {
...
routes
};
},{...})(ShiTu)
2披摄、使用
const {routes} = this.props;
// 會有意想不到的驚喜哦亲雪!
console.log(routes);
感謝群友Roc
的提供的react-navigation集成redux的 腳手架 可以通過它快速實現(xiàn)集成Redux
。
6行疏、安卓返回鍵在react-navigation
中的正常監(jiān)聽
之前使用Navigator
的時候匆光,可以通過下面的方法實現(xiàn)監(jiān)聽安卓的返回鍵,但使用了react-navigation
后酿联,會很迷茫终息,不知該怎么監(jiān)聽了。
解決辦法:集成Redux
咯贞让!?????? 集成完Redux
周崭,在跳轉之后,就能獲得路由的length
喳张,可以通過length
來判斷當前頁面是第幾層续镇。
Navigator的方法
componentWillMount() {
if (Platform.OS === 'android') {
BackAndroid.addEventListener('hardwareBackPress', this.onBackAndroid);
}
}
componentWillUnmount() {
if (Platform.OS === 'android') {
BackAndroid.removeEventListener('hardwareBackPress', this.onBackAndroid);
}
}
onBackAndroid = () => {
const nav = this.navigator;
const routers = nav.getCurrentRoutes();
if (routers.length > 1) {
nav.pop();
return true;
}
return false;
};
……
}
react-navigation的方式
componentWillMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('handwareBackPress',this.onBackAndroid)
}
}
componentWillUnmount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('handwareBackPress',this.onBackAndroid)
}
}
onBackAndroid = () => {
const routers = nav.getCurrentRoutes();
if (routers.length > 1) {
return true;
}
return false;
};
……
}
// 在跳轉之后的頁面中
onBackAndroid = ()=> {
const {routes} = this.props;
console.log(routes);
// alert(routes)
if (routes.length > 1) {
// 因為其他頁面獲得不到this.props,所以只能每個頁面都寫這個方法销部。
this.props.navigation.goBack();
return true;
}
}
7摸航、快速點擊重復跳轉的解決辦法
感謝群友編程大叔
的貢獻
react-navigation目錄下src/addNavigationHelpers.js
可以點擊這里查看原文鏈接
export default function<S: *>(navigation: NavigationProp<S, NavigationAction>) {
// 添加點擊判斷
let debounce = true;
return {
...navigation,
goBack: (key?: ?string): boolean =>
navigation.dispatch(
NavigationActions.back({
key: key === undefined ? navigation.state.key : key,
}),
),
navigate: (routeName: string,
params?: NavigationParams,
action?: NavigationAction,): boolean => {
if (debounce) {
debounce = false;
navigation.dispatch(
NavigationActions.navigate({
routeName,
params,
action,
}),
);
setTimeout(
() => {
debounce = true;
},
500,
);
return true;
}
return false;
},
/**
* For updating current route params. For example the nav bar title and
* buttons are based on the route params.
* This means `setParams` can be used to update nav bar for example.
*/
setParams: (params: NavigationParams): boolean =>
navigation.dispatch(
NavigationActions.setParams({
params,
key: navigation.state.key,
}),
),
};
}
8、安卓上舅桩,使用TextInput的時候會讓TabBar頂起來的解決辦法
最簡單的解決辦法就是在android
目錄中酱虎,添加一句話
目錄:android/app/src/main/AndroidManifest.xml
中,添加
android:windowSoftInputMode="stateAlwaysHidden|adjustPan|adjustResize"
ps:在iOS下如果想一勞永逸的解決鍵盤問題擂涛,請使用IQKeyBoardManager
读串。
總結
上述7個問題,是我暫時發(fā)現(xiàn)的可能在使用react-navigation
遇到的問題撒妈,如果遇到其他問題歡迎加入QQ群397885169
一起討論恢暖,解決。
如果在文章中遇到什么錯誤狰右,歡迎加群反饋杰捂,吐槽。