Статус ящика React Navigation? (открытый или закрытый)

Я создаю ящик с помощью React Navigation и хочу выполнить некоторую логику, если пользователь закроет ящик. Я не вижу в документации ничего очевидного, что позволило бы мне это сделать. Кто-нибудь знает способ сделать это?


person callmetwan    schedule 15.06.2017    source источник
comment
вы найдете какое-либо решение, не из тех, что работает для меня   -  person Braian Mellor    schedule 23.10.2017
comment
Как я могу закрыть ящик в Интернете?? Нажатие на оверлей не закрывает его. См. stackoverflow.com/questions/59817071/   -  person Dimitri Kopriwa    schedule 20.01.2020


Ответы (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);
};
person ufxmeng    schedule 15.07.2017
comment
В моем случае для "react-navigation": "^2.0.2" мне нужно было проверить action.type === 'Navigation/OPEN_DRAWER', чтобы он обнаружил действие. routeName остается тем, что является именем Drawer Navigator, а не DrawerOpen. - person Friendly-Robot; 12.06.2018
comment
Как мне получить прослушиватель для ящика на экранах, так как это решение работает в файле, где создается DrawerNavigator. какие решения вы имеете в виду для этого варианта использования? - person hasn; 09.02.2019
comment
@minimalist попробуйте это с помощью screenProps, используя технику Рикардо Б.М. Я смог подключить его к своему домашнему экрану, передав объект маршрутизатора в свое приложение как screenProps stackoverflow.com/questions/52248849/ - person Brandon Culley; 05.10.2019

Согласно @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

person Stophface    schedule 18.08.2017

Это для тех, кто использует версию реактивной навигации 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);
};

person BradByte    schedule 13.09.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);
};

person Thiago Siqueira    schedule 25.04.2019

Для тех, кто хочет подключить его так, чтобы события ящика были доступны на одном из ваших экранов или компонентов вместо приложения верхнего уровня, я смог подключить это с помощью 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
  }

}
person Brandon Culley    schedule 05.10.2019

Я нашел что-то похожее на asdfghjklm.

Вот мой код, который отлично работает, даже когда вы открываете его смахиванием, а затем используете кнопку, чтобы закрыть его:

openCloseDrawer = (props) => {
  if (props.navigation.state.index == 1) {
    props.navigation.navigate('DrawerClose');
  } else {
    props.navigation.navigate('DrawerOpen');
  }
}

Я выполняю эту функцию, когда пользователь нажимает кнопку «Открыть/закрыть ящик».

person Mike_NotGuilty    schedule 08.08.2018
comment
Не понимаю, почему за это проголосовали - это работает! - person Mubeen Hussain; 19.09.2018

Основываясь на решении Брэда Бамбалоу, 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.

person Ricardo BM    schedule 03.01.2019

Теперь в реагирующей навигации 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>
);}
person Ahlem Jarrar    schedule 15.05.2020

Хм, особо не видел. Одним из способов было бы управлять открытием/закрытием ящика вручную, используя:

this.props.navigation.navigate('DrawerOpen'); // open drawer
this.props.navigation.navigate('DrawerClose'); // close drawer

Таким образом, вы можете обернуть свои события закрытия/открытия в функцию, где вы можете делать все, что хотите, перед открытием/закрытием.

Единственным другим возможным решением, которое я видел в их документах, было использование пользовательского файла contentComponent. Вы можете передать функцию событию onItemPress(route), так что, возможно, вы можете попробовать подключиться к этому.

person Chase DeAnda    schedule 15.06.2017
comment
Проблема в том, что DrawerNavigator сам обрабатывает нажатия за пределы ящика, поэтому мои ручные вызовы для навигации будут пропущены. contentComponent будет работать, если мне нужно будет что-то сделать, когда эти элементы будут нажаты. На самом деле я пытаюсь просто скрыть строку состояния, когда ящик открыт. - person callmetwan; 15.06.2017
comment
Хм, да, я удивлен, что у них нет встроенного события для этого. Грязным/хакерским способом было бы просто прикрепить прослушиватель событий щелчка к переключателю ящика с помощью vanilla JS. Просто поместите его в метод жизненного цикла componentDidMount в компоненте, где находится DrawerNavigator. Таким образом, каждый раз, когда пользователь щелкает, чтобы открыть ящик, вы запускаете свое собственное событие. - person Chase DeAnda; 15.06.2017
comment
Я ценю усилия, но опять же проблема в том, что пользователь закрывает ящик, а не открывает. У меня нет возможности запечатлеть это событие. - person callmetwan; 16.06.2017
comment
Как они закрывают ящик? Щелчком? Вы можете прикрепить обработчик кликов к body, а затем проверить, открыт или закрыт ящик, проверив его css. Это определенно можно сделать, просто зависит от того, насколько вы халтурите, лол, удачи. - person Chase DeAnda; 16.06.2017
comment
Я делаю это в React Native, а не в Интернете. По сути, мне нужно было бы вычислить, где пользователь нажимает по сравнению с открытым ящиком. Похоже, вы можете подключиться к действиям отправки, если подключите Redux. Я, скорее всего, так и сделаю, хотя пока мне не нужен Redux. - person callmetwan; 16.06.2017
comment
Ах, ладно, раньше я нигде не видел родной реакции. Удачи, надеюсь ты что-нибудь придумаешь - 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;

Если решение не работает, мне очень жаль, но, прежде всего, ответ не сработал! Так что это версия, которая работает для меня:))

person Vaibhav Moradiya    schedule 24.09.2019

Без интеграции 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} />
    );
  }
person Georgiy T.    schedule 28.08.2017

Я знаю, что уже поздно, но для тех, кто ищет ответ:

Логика открытия/закрытия ящика:

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);

person asdfghjklm    schedule 18.04.2018