There are two different scenarios that I have found where tapping outside of an open side menu to close, or swiping the side menu open after setting the side menu visible
option to false
results in unexpected behavior.
My overall question is what is happening on the swiping gesture and when you tap outside of an open side menu? It seems like it opens and closes the side menu as expected, but it doesn't update the screen options, so if visible
is set to false
I am unable to open the side menu with the swiping gesture. And if visible
is set to true
and I tap outside of the side menu to close it, it will close it, but then anytime I navigate to a screen and then back the side menu thinks it is open because the screen options don't seem to get updated on those tap outside to close/swipe to open gestures.
Below is the mergeOptions
function I am using to set visible
to true
/false
in order to show or hide the side menu when tapping on the menu icon, or on one of the links in the menu.
const setSideMenuVisibility = (componentId, isVisible) => {
Navigation.mergeOptions(componentId, {
sideMenu: {
left: {
visible: isVisible
}
}
});
}
mergeOptions
and setting visible
to true
As you can see below, when I tap on the menu icon, it opens the side menu by setting visible
to true
, then I tap outside of the side menu to close it, then I tap on the button to push screen 2 onto my navigation stack, then I tap the topbar button to go back, then I'm back on screen 1, but the side menu is open.
mergeOptions
and setting visible
to true
mergeOptions
and set the side menu visible
option to false
, then push the new screen onto my navigation stack)As you can see below, when I tap on the menu icon, it opens the side menu by setting visible
to true
, then I tap on the Screen 2
link which sets visible
to false using mergeOptions
, then pushes screen 2 onto the navigation stack, then I am able to successfully swipe open the side menu as expected, but when I tap on the back button on the top bar and go back to the original screen, I am not able to swipe open the side menu, it just closes right away.
2.7.1
0.57.8
Android
Tested on Galaxy S6 running Android 7.0. Also tested on a Pixel2 XL simulator running Android 8.1. It occurs on both Debug and Release builds.
Scenario 2 is similar to #4636
@guyca
I'm also dealing with the same problem,
In addition, on opening/closing side menu, appear/disappear events don't get dispatched
Navigation.events().registerComponentDidAppearListener(({componentId}) => {
// does not works for side menu in android
});
and also if I put componentDidAppear
__method__ inside side menu component class,
only fires on @Collin3 __Scenario 1__ situation, when screen got popped and side menu opens automatically!
Update:
__This happens when I use stack for sideMenu__
{
"left": {
"stack": {
"children": [
{
"component": {
"name": "pharma.sideMenu.right"
}
}
],
"id": "pharma.left",
"options": {
"topBar": {
"visible": false,
"drawBehind": true
}
}
}
},
"center": {
"stack": {
"children": [
{
"component": {
"name": "pharma.home",
"options": {
"topBar": {
"title": {
"text": "Home"
},
}
}
}
}
],
"id": "pharma"
}
}
}
@guyca
And also another issue is if _Side Menu_ got opened using mergeOptions,
then try to reload application <R,R
>, app will crash due.
java.lang.RuntimeException: Tried to create view after it has already been destroyed
O
__Stack Trace__
com.reactnativenavigation.viewcontrollers.ViewController.getView ViewController.java:161
com.reactnativenavigation.viewcontrollers.ParentController.getView ParentController.java:60
com.reactnativenavigation.viewcontrollers.ChildController.onViewBroughtToFront ChildController.java:45
com.reactnativenavigation.viewcontrollers.ChildControllersRegistry.onViewDisappear ChildControllersRegistry.java:15
com.reactnativenavigation.viewcontrollers.ChildController.onViewDisappear ChildController.java:41
com.reactnativenavigation.viewcontrollers.ComponentViewController.onViewDisappear ComponentViewController.java:48
com.reactnativenavigation.viewcontrollers.ViewController.destroy ViewController.java:231
com.reactnativenavigation.viewcontrollers.ChildController.destroy ChildController.java:70
com.reactnativenavigation.viewcontrollers.ComponentViewController.destroy ComponentViewController.java:93
com.reactnativenavigation.viewcontrollers.ParentController.destroy ParentController.java:112
com.reactnativenavigation.viewcontrollers.stack.StackController.destroy StackController.java:138
com.reactnativenavigation.viewcontrollers.ParentController.destroy ParentController.java:112
com.reactnativenavigation.viewcontrollers.navigator.Navigator.destroyRoot Navigator.java:121
com.reactnativenavigation.viewcontrollers.navigator.Navigator.destroyViews Navigator.java:117
com.reactnativenavigation.NavigationActivity.onReload NavigationActivity.java:124
com.reactnativenavigation.react.JsDevReloadHandler.reloadReactNative JsDevReloadHandler.java:83
com.reactnativenavigation.react.JsDevReloadHandler.onKeyUp JsDevReloadHandler.java:70
com.reactnativenavigation.react.ReactGateway.onKeyUp ReactGateway.java:68
com.reactnativenavigation.NavigationActivity.onKeyUp NavigationActivity.java:93
android.view.KeyEvent.dispatch KeyEvent.java:2715
android.support.v4.view.KeyEventDispatcher.activitySuperDispatchKeyEventPre28 KeyEventDispatcher.java:137
android.support.v4.view.KeyEventDispatcher.dispatchKeyEvent KeyEventDispatcher.java:87
android.support.v4.app.SupportActivity.dispatchKeyEvent ComponentActivity.java:126
android.support.v7.app.AppCompatActivity.dispatchKeyEvent AppCompatActivity.java:535
android.support.v7.view.WindowCallbackWrapper.dispatchKeyEvent WindowCallbackWrapper.java:59
android.support.v7.app.AppCompatDelegateImpl$AppCompatWindowCallback.dispatchKeyEvent AppCompatDelegateImpl.java:2533
com.android.internal.policy.DecorView.dispatchKeyEvent DecorView.java:354
android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent ViewRootImpl.java:4733
android.view.ViewRootImpl$ViewPostImeInputStage.onProcess ViewRootImpl.java:4605
android.view.ViewRootImpl$InputStage.deliver ViewRootImpl.java:4147
android.view.ViewRootImpl$InputStage.onDeliverToNext ViewRootImpl.java:4200
android.view.ViewRootImpl$InputStage.forward ViewRootImpl.java:4166
android.view.ViewRootImpl$AsyncInputStage.forward ViewRootImpl.java:4293
android.view.ViewRootImpl$InputStage.apply ViewRootImpl.java:4174
android.view.ViewRootImpl$AsyncInputStage.apply ViewRootImpl.java:4350
android.view.ViewRootImpl$InputStage.deliver ViewRootImpl.java:4147
android.view.ViewRootImpl$InputStage.onDeliverToNext ViewRootImpl.java:4200
android.view.ViewRootImpl$InputStage.forward ViewRootImpl.java:4166
android.view.ViewRootImpl$InputStage.apply ViewRootImpl.java:4174
android.view.ViewRootImpl$InputStage.deliver ViewRootImpl.java:4147
android.view.ViewRootImpl$InputStage.onDeliverToNext ViewRootImpl.java:4200
android.view.ViewRootImpl$InputStage.forward ViewRootImpl.java:4166
android.view.ViewRootImpl$AsyncInputStage.forward ViewRootImpl.java:4326
android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent ViewRootImpl.java:4487
android.view.inputmethod.InputMethodManager$PendingEvent.run InputMethodManager.java:2435
android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback InputMethodManager.java:1998
android.view.inputmethod.InputMethodManager.finishedInputEvent InputMethodManager.java:1989
android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished InputMethodManager.java:2412
android.view.InputEventSender.dispatchInputEventFinished InputEventSender.java:141
android.os.MessageQueue.nativePollOnce MessageQueue.java
android.os.MessageQueue.next MessageQueue.java:325
android.os.Looper.loop Looper.java:142
android.app.ActivityThread.main ActivityThread.java:6494
java.lang.reflect.Method.invoke Method.java
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run RuntimeInit.java:438
com.android.internal.os.ZygoteInit.main ZygoteInit.java:807
... but its works perfectly when opened via swipe gesture.
Just tested with 2.12.0-snapshot.211
and the bug is still not fixed!
seems like https://github.com/wix/react-native-navigation/pull/4745 didn't help.
I had the same issue and as a workaround I made a function that is handing the merge
updateNavigationState(){
Navigation.mergeOptions(this.props.componentId, {
sideMenu: {
left: {
visible: THECURRENTSTATE
}
}
});
}
The above function is called when
Navigation.events().registerComponentDidDisappearListener(({ componentId }) => {
...
this.updateNavigationState();
});
and when
navigationButtonPressed({buttonId}) {
...
this.updateNavigationState();
}
As the actual state of the drawer is set when the screens are switched the issue does not appear.
@lbudakov Thanks for sharing your solution. 馃檶
It helped.
I am facing the same issues. Can you, @lbudakov, give a better description of your workaround? Where is the code placed, in the main component (screen) or sidemenu?
@bobmulder it's in the main component
example:
````
class NAME extends Component {
constructor(){
super();
this.sideDrawerVisible = false;
}
componentDidMount() {
this.navigationEventListener = Navigation.events().bindComponent(this);
Navigation.events().registerComponentDidDisappearListener(({ componentId }) => {
if (componentId === 'DrawerID') {
this.sideDrawerVisible = false;
}
this.updateNavigationState();
});
}
navigationButtonPressed({buttonId}) {
if( buttonId == 'DrawerToggleID' ){
(!this.sideDrawerVisible) ? this.sideDrawerVisible = true : this.sideDrawerVisible = false;
this.updateNavigationState();
}
}
updateNavigationState(){
Navigation.mergeOptions(this.props.componentId, {
sideMenu: {
left: {
visible: this.sideDrawerVisible
}
}
});
}
render(){
return(...)
}
}
````
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you believe the issue is still relevant, please test on the latest Detox and report back. Thank you for your contributions.
There are workarounds, but I鈥檇 still consider this a bug. Not stale in my opinion.
Hi @Collin3, I just sent a PR that addresses this issue. If it does indeed fix your issue, do not forget to close the issue!
@ItsNoHax thanks for the PR! I pulled those changes in to test it out and found that it does indeed fix my issue. I'll be sure to close this once it gets merged in.
Thanks again!
Just Close the Sidemenu before pushing the new screen and give setTimeout to 200 millisecond works. Its not Perfect solution just for workaround.
Navigation.mergeOptions(componentId, {
sideMenu: {
right: {
visible:false
}
}
});
setTimeout(()=>{
Navigation.push(componentId, {
component: {
name: screenNAme,
passProps,
options: {
sideMenu: {
right: {
visible: false,
enabled: false
}
},
bottomTabs: {
visible: bottomTabVisible,
drawBehind: true
},
layout: {
orientation: ["portrait"]
}
}
}
});
},200)
Most helpful comment
Hi @Collin3, I just sent a PR that addresses this issue. If it does indeed fix your issue, do not forget to close the issue!