【问题标题】:How to detect when the drawer is opened in react-navigation?如何检测抽屉何时在反应导航中打开?
【发布时间】:2017-07-15 19:48:53
【问题描述】:

我在我的应用程序中使用 react-navigation 的 DrawerNavigator。我想检测用户何时拖动打开侧面菜单,以便我可以执行特定操作,例如关闭打开的键盘。 我怎样才能做到这一点?我似乎无法在文档中找到解决方案。谢谢。

这是我的代码

import React from 'react';
import { Dimensions } from 'react-native';
import { Icon } from 'react-native-elements';
import { DrawerNavigator, StackNavigator, addNavigationHelpers } from 'react-navigation';


//redux related imports
import { createStore, combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';

import Attendance from './containers/pages/Attendance';
import Fees from './containers/pages/Fees';
import Exams from './containers/pages/Exams';
import InitializeUser from './containers/pages/InitializeUser';
import Landing from './Landing';
import Login from './containers/pages/Login';
import Search from './containers/pages/Search';
import Staff from './containers/pages/Staff';
import Stats from './containers/pages/Stats';
import Students from './containers/pages/Students';
import Verification from './containers/pages/verify';
import ProfileDetail from './components/pages/ProfileDetail';
import FeesDetail from './containers/pages/FeesDetails';


import MainReport from './containers/pages/Reports/Main_Report';
import AcademicDetails from './containers/pages/Reports/Student_Academic_Details';
import { Constants } from './config';
import ResultsLanding from './containers/pages/Reports/ResultsLanding';
import { CustomDrawerContentComponent } from '../src/components/base/SideMenu';


const screenWidth = Dimensions.get('window').width;
const MainPages = DrawerNavigator({
  StudentsPage: {
    path: '/Students',
    screen: Students
  },
  SearchPage: {
    path: '/Seacrh',
    screen: Search
  },

  Staff: {
    path: '/Staff',
    screen: Staff
  },

  Fees: {
    path: '/Fees',
    screen: Fees
  },
  Stats: {
    path: '/Stats',
    screen: Stats
  },
  Results: {
    screen: ResultsLanding,
    navigationOptions: {
      tintColor: 'red',
      flex: 1,
      drawerIcon: ({ tintColor }) => (
        <Icon
          name="content-paste"
          color={tintColor}
        />
      )
    }
  },
  Attendance:
  {
    path: '/Attendance',
    screen: Attendance
  },
},
  {
    initialRouteName: 'StudentsPage',
    contentOptions: {
      activeTintColor: Constants.ui.THEME,
      activeBackgroundColor: 'rgba(0,0,0,0.1)',
      inactiveTintColor: 'rgba(0,0,0,0.6)',
      labelStyle: {
        fontSize: 12,
        marginLeft: 10,
      },
    },

    drawerWidth: screenWidth > 320 ? 300 : 250,
    contentComponent: CustomDrawerContentComponent

  });

export const Navigator = StackNavigator({
  LandingPage: {
    screen: Landing,
    navigationOptions: {
      header: null
    }
  },
  LoginPage: {
    screen: Login,
    navigationOptions: {
      header: null
    },
  },
  ProfileDetailPage: {
    screen: ProfileDetail,
    headerMode: 'screen',
    navigationOptions: {
      header: null
    }
  },
  FeesDetailPage:
  {
    screen: FeesDetail,
    navigationOptions: {
      header: null
    },
  },
  VerifyPage: {
    screen: Verification,
    navigationOptions: {
      header: null
    },
  },
  InitUserPage: {
    screen: InitializeUser,
    navigationOptions: {
      header: null
    },
  },
  MainPages: {
    screen: MainPages,
    navigationOptions: {
      header: null
    }
  },

  MainReportPage: {
    screen: MainReport,
    navigationOptions: {
      header: null
    }
  },
  ExamsMainPage: {
    screen: Exams,
    navigationOptions: {
      header: null
    }
  },
  AcademicDetailsPage: {
    screen: AcademicDetails,
    navigationOptions: {
      header: null
    }
  },

});  

const initialState = MainPages.router.getStateForAction(
  MainPages.router.getActionForPathAndParams('StudentsPage'));  

const navReducer = (state = initialState, action) => {
  const nextState = MainPages.router.getStateForAction(action, state);
  return nextState || state;
}; 

const appReducer = combineReducers({
  nav: navReducer
});

class App extends React.Component {
  componentWillReceiveProps(nextProps) {
    console.warn('nextProps: ', JSON.stringify(nextProps, null, 4));
  }
  render() {
    return (
      <MainPages 
        navigation={addNavigationHelpers({
        dispatch: this.props.dispatch,
        state: this.props.nav,
      })} />
    );
  }
}

const mapStateToProps = (state) => ({
  nav: state.nav
});

const AppWithNavigationState = connect(mapStateToProps)(App);

const store = createStore(appReducer);

class Root extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <AppWithNavigationState />
      </Provider>
    );
  }
}

enter image description here 这是我运行代码时遇到的错误的屏幕截图

【问题讨论】:

    标签: react-native react-navigation


    【解决方案1】:

    简单地说,如果你使用 react-navigation v5 -

    import { useIsDrawerOpen } from '@react-navigation/drawer'
    
    const isOpen: boolean = useIsDrawerOpen()
    

    那么你必须通过钩子useEffect订阅“isOpen”标志:

    useEffect(() => {
        if (!isOpen) {
          // Your dismiss logic here 
        }
    }, [isOpen])
    

    您的自定义抽屉可能看起来像DrawerContent

    希望对你有帮助

    【讨论】:

    • 钩子现在被称为useDrawerStatus,它的值是一个字符串('open''closed')参考文档的this part
    【解决方案2】:

    通过遵循Redux Integration 指南并将其修改为使用 DrawerNavigator 而不是 StackNavigator,我能够检测到 DrawerNavigator 的打开和关闭侧菜单操作。这是我的index.ios.js 文件中的内容。在App 类的底部附近,我使用componentWillReceiveProps,每次抽屉打开或关闭时都会显示警告。

    import React from 'react';
    import {
      AppRegistry,
      Image,
      Text,
      View,
      ScrollView
    } from 'react-native';
    import {DrawerNavigator, DrawerItems, addNavigationHelpers } from 'react-navigation';
    import { Provider, connect } from 'react-redux'
    import { createStore, combineReducers } from 'redux'
    
    class MyHomeScreen extends React.Component {
      static navigationOptions = {
        drawerLabel: 'Home',
        drawerIcon: ({ tintColor }) => (
          <Image
            source={require('./images/Groups.png')}
            style={{tintColor: tintColor, width: 26, height: 26}}/>
        ),
      };
      render() {
        return (
          <View>
            <Text>Home Screen</Text>
          </View>
        );
      }
    }
    
    class MyNotificationsScreen extends React.Component {
      static navigationOptions = {
        drawerLabel: 'Notifications',
        drawerIcon: ({ tintColor }) => (
          <Image
            source={require('./images/Events.png')}
            style={{tintColor: tintColor, width: 26, height: 26}}/>
        ),
      };
      render() {
        return (
          <View>
            <Text>Notifications Screen</Text>
          </View>
        );
      }
    }
    
    const NavDemo = DrawerNavigator({
      Home: { screen: MyHomeScreen },
      Notifications: { screen: MyNotificationsScreen }
    }, {
      tabBarOptions: {
        activeTintColor: '#e91e63',
      },
      drawerWidth: 200,
      drawerPosition: 'left',
      contentComponent: props => <ScrollView><DrawerItems {...props} /></ScrollView>
    });
    
    const initialState = NavDemo.router.getStateForAction(NavDemo.router.getActionForPathAndParams('Home'));
    
    const navReducer = (state = initialState, action) => {
      const nextState = NavDemo.router.getStateForAction(action, state);
      return nextState || state;
    };
    
    const appReducer = combineReducers({
      nav: navReducer
    });
    
    class App extends React.Component {
      componentWillReceiveProps(nextProps) {
        console.warn('nextProps: ' + JSON.stringify(nextProps, null, 4))
      }
      render() {
        return (
          <NavDemo navigation={addNavigationHelpers({
            dispatch: this.props.dispatch,
            state: this.props.nav,
          })} />
        );
      }
    }
    
    const mapStateToProps = (state) => ({
      nav: state.nav
    });
    
    const AppWithNavigationState = connect(mapStateToProps)(App);
    
    const store = createStore(appReducer);
    
    class Root extends React.Component {
      render() {
        return (
          <Provider store={store}>
            <AppWithNavigationState />
          </Provider>
        );
      }
    }
    
    AppRegistry.registerComponent('NavDemo', () => Root);
    

    当我打开抽屉并展开警告时,nextProps 看起来像这样:

    然后在我关闭抽屉后,新的警告显示如下:

    nextProps.nav 是一个有两个键的对象,routesindex。当抽屉打开时,index 变为 1,当它关闭时,索引变为 0

    使用该信息,您可以添加 if 语句以在抽屉打开时执行必要的操作。

    【讨论】:

    • 非常感谢 Pat Needham 我会检查一下并给您反馈。再次感谢您的早期回复。
    • 不,我想把我的代码和我收到的错误截图发给你,所以请你帮我检查一下
    • Pat 你能帮我看看吗?如果有什么你没有得到请让我尽快知道我需要在抽屉打开时关闭键盘,因为反应导航不会自动为我关闭它。多么痛苦....
    • @danieldoe 我查看了屏幕截图错误消息 - 打开应用程序后立即发生这种情况还是在打开或关闭导航抽屉等某个时间点发生?此外,您可以从另一个终端/命令提示符窗口运行react-native log-android 以获取更详细的日志记录吗?这可能比屏幕截图错误消息更有用,我认为它没有提供任何线索,因为我没有看到 actiontype 在您的代码 sn-p 的任何地方使用。还可以尝试在项目目录中搜索所有 action.type 实例的使用位置
    • 好的老板,我实际上正在和我的教授一起编写代码,我会和他一起完成它,因为它必须按照 react-navigation redux 集成文档工作。非常感谢帕特,我当然很感激。好吧,如果您有其他方法可以在打开抽屉时关闭键盘,请随时填写。在此之前再次感谢您的时间。
    【解决方案3】:

    这是一个旧线程,但我想分享一下我是如何做到这一点的。

    在您的应用中添加以下代码(最好在您创建 DraweStack 的位置。)

    const defaultGetStateForAction = DrawerStack.router.getStateForAction;
    DrawerStack.router.getStateForAction = (action, state) => {
      switch (action.type) {
        case "Navigation/DRAWER_OPENED":
        case "Navigation/MARK_DRAWER_ACTIVE":
          Keyboard.dismiss();
          break;
      }
    
      return defaultGetStateForAction(action, state);
    };
    

    有多种action.type。例如:

    • 在抽屉开始打开时调用导航/MARK_DRAWER_ACTIVE
    • 在抽屉打开时调用导航/MARK_DRAWER_SETTLING。

    干杯。

    【讨论】:

      【解决方案4】:
      • this.props.navigation.state.isDrawerOpen => 真/假

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-10-29
        • 2022-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多