Я создаю ящик с помощью React Navigation и хочу выполнить некоторую логику, если пользователь закроет ящик. Я не вижу в документации ничего очевидного, что позволило бы мне это сделать. Кто-нибудь знает способ сделать это?
Статус ящика React Navigation? (открытый или закрытый)
Ответы (12)
Вам необходимо настроить действия навигации, чтобы зафиксировать событие DrawerClose
:
const MyDrawerNavigator = DrawerNavigator({
//...
});
const defaultGetStateForAction = MyDrawerNavigator.router.getStateForAction;
MyDrawerNavigator.router.getStateForAction = (action, state) => {
//use 'DrawerOpen' to capture drawer open event
if (state && action.type === 'Navigation/NAVIGATE' && action.routeName === 'DrawerClose') {
console.log('DrawerClose');
//write the code you want to deal with 'DrawerClose' event
}
return defaultGetStateForAction(action, state);
};
"react-navigation": "^2.0.2"
мне нужно было проверить action.type === 'Navigation/OPEN_DRAWER'
, чтобы он обнаружил действие. routeName
остается тем, что является именем Drawer Navigator, а не DrawerOpen
.
- person Friendly-Robot; 12.06.2018
Согласно @ufxmeng
import {
StatusBar,
} from "react-native";
const MyDrawerNavigator = DrawerNavigator({
//...
});
const defaultGetStateForAction = MyDrawerNavigator.router.getStateForAction;
MyDrawerNavigator.router.getStateForAction = (action, state) => {
if(state && action.type === 'Navigation/NAVIGATE' && action.routeName === 'DrawerClose') {
StatusBar.setHidden(false);
}
if(state && action.type === 'Navigation/NAVIGATE' && action.routeName === 'DrawerOpen') {
StatusBar.setHidden(true);
}
return defaultGetStateForAction(action, state);
};
См. здесь https://github.com/react-community/react-navigation/blob/673b9d2877d7e84fbfbe2928305ead7e51b04835/docs/api/routers/Routers.md и здесь https://github.com/aksonov/react-native-router-flux/issues/699
Это для тех, кто использует версию реактивной навигации v2.0+. Теперь есть действия с ящиками, которые вы можете отслеживать.
{
OPEN_DRAWER: 'Navigation/OPEN_DRAWER',
CLOSE_DRAWER: 'Navigation/CLOSE_DRAWER',
TOGGLE_DRAWER: 'Navigation/TOGGLE_DRAWER',
DRAWER_OPENED: 'Navigation/DRAWER_OPENED',
DRAWER_CLOSED: 'Navigation/DRAWER_CLOSED'
}
react-navigation.js, строка 825 а>
Однако кажется, что подразумеваемая навигация по ящикам, скажем, смахиванием, не запускает действия OPEN_
/CLOSE_
, поскольку вы не переключали их вручную. Однако действия _OPENED
/_CLOSED
срабатывают впоследствии.
const MyDrawerNavigator = createDrawerNavigator(...);
const defaultGetStateForAction = MyDrawerNavigator.router.getStateForAction;
MyDrawerNavigator.router.getStateForAction = (action, state) => {
switch (action.type) {
case 'Navigation/OPEN_DRAWER':
case 'Navigation/DRAWER_OPENED':
StatusBar.setHidden(true, 'slide');
break;
case 'Navigation/CLOSE_DRAWER':
case 'Navigation/DRAWER_CLOSED':
StatusBar.setHidden(false, 'slide');
break;
}
return defaultGetStateForAction(action, state);
};
case 'Navigation/NAVIGATE'
, если вам нужно подключиться к этому, а также case 'Navigation/BACK'
- person fredrivett; 17.12.2018
Работа с "реагирующей навигацией": "^3.5.1"
const defaultGetStateForAction = DrawerNav.router.getStateForAction;
DrawerNav.router.getStateForAction = (action, state) => {
if(action){
if(action.type == 'Navigation/MARK_DRAWER_SETTLING' && action.willShow){
StatusBar.setHidden(true);
} else if(action.type == 'Navigation/MARK_DRAWER_SETTLING' && !action.willShow) {
StatusBar.setHidden(false);
}
}
return defaultGetStateForAction(action, state);
};
Для тех, кто хочет подключить его так, чтобы события ящика были доступны на одном из ваших экранов или компонентов вместо приложения верхнего уровня, я смог подключить это с помощью screenProps, как описано в этот пост. Сначала вы настраиваете screenProps в своем приложении и передаете маршрутизатор и все остальное, что вам нужно. Вы можете вытащить screenProps из реквизита и использовать его на своем экране или компоненте (я подключил его в конструкторе в этом примере), используйте getStateForAction для setState в вашем компоненте, управляемом событиями маршрутизатора.
Вот пример (некоторый код удален для ясности)
App.js
import React from 'react';
import { AppLoading } from 'expo';
import {
createDrawerNavigator,
createAppContainer,
createStackNavigator,
} from 'react-navigation';
import { HomeScreen } from './src/screens/HomeScreen.android';
import { LanguageSelectScreen } from './src/screens/LanguageSelectScreen';
export default class App extends React.Component {
state = {
isLoadingComplete: false,
isTilted: false,
};
constructor() {
super();
}
render() {
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return (
<AppLoading />
);
} else {
return (
<MyApp screenProps={MyAppNavigator.router} />
);
}
}
}
const MyAppNavigator = createDrawerNavigator(
{
Home: {
screen: HomeScreen,
},
PlayerNameScreen: {
screen: PlayerNameScreen,
},
},
{
unmountInactiveRoutes: true,
initialRouteName: 'PlayerNameScreen',
},
);
const RootStack = createStackNavigator(
{
Main: {
screen: MyAppNavigator,
},
MyModal: {
screen: LanguageSelectScreen,
},
},
{
mode: 'modal',
headerMode: 'none',
},
);
export const MyApp = createAppContainer(RootStack);
HomeScreen.android.js
import React from 'react';
import {Icon} from 'react-native-elements';
export class HomeScreen extends React.Component {
static navigationOptions = {
drawerLabel: () => 'Home',
drawerIcon: ({ tintColor }) => (
<Icon
name="checkerboard"
type="material-community"
size={25}
color={tintColor}
/>
),
};
constructor(props) {
super(props);
const router = props.screenProps;
const defaultGetStateForAction = router.getStateForAction;
router.getStateForAction = (action, state) => {
switch (action.type) {
case 'Navigation/MARK_DRAWER_SETTLING':
if (action.willShow == false) {
console.log('CLOSED');
this.setState({ isTilted: false });
} else if (action.willShow == true) {
this.setState({ isTilted: true });
console.log('OPEN');
}
break;
}
return defaultGetStateForAction(action, state);
};
this.state = {
isTilted: false,
};
}
render() {
const { isTilted } = this.state;
// ... render using isTilted
}
}
Я нашел что-то похожее на asdfghjklm
.
Вот мой код, который отлично работает, даже когда вы открываете его смахиванием, а затем используете кнопку, чтобы закрыть его:
openCloseDrawer = (props) => {
if (props.navigation.state.index == 1) {
props.navigation.navigate('DrawerClose');
} else {
props.navigation.navigate('DrawerOpen');
}
}
Я выполняю эту функцию, когда пользователь нажимает кнопку «Открыть/закрыть ящик».
Основываясь на решении Брэда Бамбалоу, fredrivett (спасибо, ребята), я нашел решение с более быстрым откликом (другое решение задерживает секунды в некоторых случаях).
const defaultGetStateForAction = StackLogadoDrawer.router.getStateForAction;
StackLogadoDrawer.router.getStateForAction = (action, state) => {
switch (action.type) {
case 'Navigation/MARK_DRAWER_SETTLING':
if (action.willShow == false) {
console.log('CERRADO');
} else if (action.willShow == true) {
console.log('ABIERTO');
}
break;
}
return defaultGetStateForAction(action, state);
};
Это срабатывает сразу же, как только происходит действие (или очень близко).
Он работает с жестами или вызовом openDrawer()
В любом случае, я думаю, что это «должен быть» простой и прямой способ в API.
Теперь в реагирующей навигации 5 вы можете напрямую получить доступ к статусу вашего ящика, используя этот подход:
useIsDrawerOpen()
это хук для определения того, открыт ли ящик в родительском навигаторе.
Например, в вашем представлении вы можете проверить, открыт ли ваш ящик или нет напрямую, используя этот подход:
import { useIsDrawerOpen } from '@react-navigation/drawer';
const MainContainer = () => {
return (
<View style={(useIsDrawerOpen()) ? styles.conatinerOpenStyle : styles.containerClosedStyle}>
<Text>{console.log("Test drawer "+useIsDrawerOpen())}</Text>
</View>
);}
Хм, особо не видел. Одним из способов было бы управлять открытием/закрытием ящика вручную, используя:
this.props.navigation.navigate('DrawerOpen'); // open drawer
this.props.navigation.navigate('DrawerClose'); // close drawer
Таким образом, вы можете обернуть свои события закрытия/открытия в функцию, где вы можете делать все, что хотите, перед открытием/закрытием.
Единственным другим возможным решением, которое я видел в их документах, было использование пользовательского файла contentComponent
. Вы можете передать функцию событию onItemPress(route)
, так что, возможно, вы можете попробовать подключиться к этому.
componentDidMount
в компоненте, где находится DrawerNavigator. Таким образом, каждый раз, когда пользователь щелкает, чтобы открыть ящик, вы запускаете свое собственное событие.
- person Chase DeAnda; 15.06.2017
body
, а затем проверить, открыт или закрыт ящик, проверив его css. Это определенно можно сделать, просто зависит от того, насколько вы халтурите, лол, удачи.
- person Chase DeAnda; 16.06.2017
Это отлично работает в React-Native, не уверен в React.
В моем случае мне пришлось изменить StatusBar, поэтому мне не нужно было знать, закрыт ли ящик полностью или нет, поэтому приведенный ниже код работал для меня...
props.navigation.state.drawerMovementDirection === 'closing'
? //it is closing not fully closed
: (props.navigation.state.drawerMovementDirection === 'opening' ||
props.navigation.state.isDrawerOpen) && (
//fully opened or opening
)
Если вам не нужно знать немедленно, вы можете использовать приведенный ниже код, и это будет работать нормально и даст вам точный ответ, открыт ли ящик или нет!
Примечание. Это будет отложенный ответ, в моем случае это заняло 1 секунду.
props.navigation.state.isDrawerOpen?
//open
:
//close;
Если решение не работает, мне очень жаль, но, прежде всего, ответ не сработал! Так что это версия, которая работает для меня:))
Без интеграции Redux можно использовать onNavigationStateChange на компоненте маршрутизатора. Просто перехватите действия ящика: DrawerOpen и DrawerClose.
Пример:
handleNavigationState = (previous, next, action) => {
if (action.routeName === 'DrawerOpen') {
this.props.setDrawerState(true);
} else if (action.routeName === 'DrawerClose') {
this.props.setDrawerState(false);
}
}
render() {
return (
<Router onNavigationStateChange={this.handleNavigationState} />
);
}
Я знаю, что уже поздно, но для тех, кто ищет ответ:
Логика открытия/закрытия ящика:
this.props.navigation.state.routes[0].index
Это 0 для закрытых, 1 для открытых.
Вы также можете переключать ящики с помощью
this.props.navigation.navigate('DrawerToggle')
вместо
this.props.navigation.navigate('DrawerOpen');
or
this.props.navigation.navigate('DrawerClose');
Мне так удобнее и проблем пока не возникало. Хотя приятно знать, переключаются ли они или нет, чтобы вызывать другие действия.
Я искренне верю, что документация React-Navigation одна из худших, которые я когда-либо видел. Есть команды, о которых никто не знает. Я не смог найти действие DrawerToggle в документах, и я столкнулся с ним только с помощью console.log(this.props.navigation);