wix / react-native-navigation

A complete native navigation solution for React Native
https://wix.github.io/react-native-navigation/
MIT License
13.04k stars 2.67k forks source link

[V2] [Android] setRoot with bottomTabs crash #3381

Closed sapjax closed 6 years ago

sapjax commented 6 years ago

Issue Description

I use setRoot and pass bottomTabs, if bottomTabs contains more than one stack, it will crash, only one stack will works well.

It works good on iOS.

Steps to Reproduce / Code Snippets / Screenshots

the code of setRoot is:

const bottomTabs = {
      children: [
        {
          stack: {
            children: [
              {
                component: {
                  name: `${PACKAGE_NAME}.Assets`,
                },
              },
            ],
            options: {
              bottomTab: {
                testID: 'TabAssets',
                title: t('wallet'),
                icon: icon.tabAssetThin,
              },
            },
          },
        },
        {
          stack: {
            children: [{
              component: {
                name: `${PACKAGE_NAME}.Market`,
              },
            }],
            options: {
              bottomTab: {
                testID: 'TabMarket',
                title: t('market'),
                icon: icon.tabMarket,
              },
            },
          },
        },
      ],
      options: {
        bottomTabs: {
          visible: true,
          animate: true, // Controls wether BottomTabs visibility changes should be animated
          currentTabIndex: 0,
          // currentTabId: 'currentTabId',
          // testID: 'bottomTabsTestID',
          drawBehind: true,
          translucent: false,
          iconInsets: { top: 5, bottom: -5 },
          disableIconTint: true, // set true if you want to disable the icon tinting
          disableSelectedIconTint: true,
          backgroundColor: color.t10,
          tabColor: color.t4,
          selectedTabColor: color.main,
          fontFamily: 'Helvetica',
          fontSize: 10,
        },
      },
    }

    Navigation.setRoot({
      root: {
        bottomTabs: bottomTabs,
      },
    })

the logcat info is below:

06-19 14:37:13.826 28452-28452/org.consenlabs.imtoken E/AndroidRuntime: FATAL EXCEPTION: main
    Process: org.consenlabs.imtoken, PID: 28452
    java.lang.NullPointerException: Attempt to write to field 'int android.view.ViewGroup$MarginLayoutParams.bottomMargin' on a null object reference
        at com.reactnativenavigation.presentation.BottomTabsOptionsPresenter.applyDrawBehind(BottomTabsOptionsPresenter.java:56)
        at com.reactnativenavigation.presentation.BottomTabsOptionsPresenter.presentChildOptions(BottomTabsOptionsPresenter.java:41)
        at com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabsController.mergeChildOptions(BottomTabsController.java:82)
        at com.reactnativenavigation.viewcontrollers.StackController.lambda$mergeChildOptions$1$StackController(StackController.java:78)
        at com.reactnativenavigation.viewcontrollers.StackController$$Lambda$1.run(Unknown Source:4)
        at com.reactnativenavigation.viewcontrollers.ViewController.applyOnParentController(ViewController.java:93)
        at com.reactnativenavigation.viewcontrollers.StackController.mergeChildOptions(StackController.java:77)
        at com.reactnativenavigation.viewcontrollers.ComponentViewController.lambda$mergeOptions$0$ComponentViewController(ComponentViewController.java:65)
        at com.reactnativenavigation.viewcontrollers.ComponentViewController$$Lambda$0.run(Unknown Source:6)
        at com.reactnativenavigation.viewcontrollers.ViewController.applyOnParentController(ViewController.java:93)
        at com.reactnativenavigation.viewcontrollers.ComponentViewController.mergeOptions(ComponentViewController.java:65)
        at com.reactnativenavigation.viewcontrollers.Navigator.mergeOptions(Navigator.java:123)
        at com.reactnativenavigation.react.NavigationModule.lambda$mergeOptions$3$NavigationModule(NavigationModule.java:76)
        at com.reactnativenavigation.react.NavigationModule$$Lambda$3.run(Unknown Source:6)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

Environment

ujwal-setlur commented 6 years ago

I have a very similar setup, and it works for me on both iOS and Android. The difference I see is that I am setting the id for the components in the stack...

                bottomTabs: {
                  children: [
                    {
                      stack: {
                        children: [{
                          component: {
                            id: "groups",
                            name: "groups",
                            options: {
                              topBar: {
                                title: {
                                  text: screenLabels.groups
                                }
                              }
                            }
                          }
                        }],
                        options: {
                          bottomTab: {
                            title: tabLabels.groups,
                            icon: require("./assets/images/groups.png")
                          }
                        }
                      }
                    },
                    {
                      stack: {
                        children: [{
                          component: {
                            id: "colors",
                            name: "welcome",
                            options: {
                              topBar: {
                                title: {
                                  text: screenLabels.colors
                                }
                              }
                            }
                          }
                        }],
                        options: {
                          bottomTab: {
                            title: tabLabels.colors,
                            icon: require("./assets/images/colors.png")
                          }
                        }
                      }
                    },
                    {
                      stack: {
                        children: [{
                          component: {
                            id: "items",
                            name: "welcome",
                            options: {
                              topBar: {
                                title: {
                                  text: screenLabels.items
                                }
                              }
                            }
                          }
                        }],
                        options: {
                          bottomTab: {
                            title: tabLabels.items,
                            icon: require("./assets/images/items.png")
                          }
                        }
                      }
                    },
                    {
                      stack: {
                        children: [{
                          component: {
                            id: "match",
                            name: "welcome",
                            options: {
                              topBar: {
                                title: {
                                  text: screenLabels.match
                                }
                              }
                            }
                          }
                        }],
                        options: {
                          bottomTab: {
                            title: tabLabels.match,
                            icon: require("./assets/images/match.png")
                          }
                        }
                      }
                    }
                  ],
                  options: {
                    bottomTabs: {
                      tabColor: "black",
                      selectedTabColor: "#3c6df0",
                      backgroundColor: "white",
                      fontFamily: "Nunito",
                      fontSize: 10
                    }
                  }
                }
sapjax commented 6 years ago

@ujwal-setlur
Thanks, I added the id filed, but not works for me. which version of RNN are you using?

ujwal-setlur commented 6 years ago

0.55.4, the latest

sapjax commented 6 years ago

@ujwal-setlur Sorry, I mean the react-native-navigation version.

ujwal-setlur commented 6 years ago

The latest from npmjs

guyca commented 6 years ago

Hey @sapjax I'm not able to reproduce. Could you PR a failing Detox test?

sapjax commented 6 years ago

@guyca @ujwal-setlur I upgrade to the latest version (2.0.2361), then it works well.

hubertjaruzal commented 6 years ago

I have similar problem using bottomTabs (RNN@alpha) on Android device. App crashes.

hubertjaruzal commented 6 years ago

@sapjax @guyca I noticed that icon property is needed on Android devices.

example:

    const bottomTabs = {
      children: [
        {
          component: {
            name: 'navigation.playground.Comp1',
            options: {
              bottomTab: {
                text: 'Text1',
                icon: require('./iconName1.png'),
              }
            }
          },
        },
        {
          component: {
            name: 'navigation.playground.Comp2',
            options: {
              bottomTab: {
                text: 'Text2',
                icon: require('./iconName2.png'),
              }
            }
          },
        }
      ]
    }
jstansbe commented 6 years ago

@hubertjaruzal how would i use react-native-vector-icons for the icon?

hubertjaruzal commented 6 years ago

@jstansbe

async function getIcon(name) {
  icon = await Icon.getImageSource(name).then(icon => icon);
  return { uri: icon.uri }
} 

This function will return path to the icon. getImageSource return Promise so I used async/await. Your start function should be also async:

async function start() {...}

Inside start() add: iconList = await getIcon('list'); - Where function param is an icon name. Then you can use it in your setRoot eg.

              bottomTab: {
                icon: iconList
              }

This solution worked in iOS simulator, but didn't on android device.

ollija commented 6 years ago

I created a separate issue about the Icon-requirement on Android. https://github.com/wix/react-native-navigation/issues/3903

alexsmartens commented 5 years ago

I'm having the same problem on Android. Has anyone got the navigation working with react-native-vector-icons?

mepritam commented 5 years ago

@hubertjaruzal great. After adding the icon, android started working. Thanks 😄

ivanguimam commented 4 years ago

I same problem:

java.lang.NullPointerException: Attempt to read from field 'int android.view.ViewGroup$MarginLayoutParams.bottomMargin' on a null object reference
        at com.reactnativenavigation.presentation.ComponentPresenterBase.applyBottomInset(ComponentPresenterBase.java:18)
        at com.reactnativenavigation.viewcontrollers.ComponentViewController.applyBottomInset(ComponentViewController.java:106)
        at com.reactnativenavigation.viewcontrollers.-$$Lambda$PdnjwIMOFJug2YGdC1rKp4pGYAA.on(lambda)
        at com.reactnativenavigation.utils.CollectionUtils.forEach(CollectionUtils.java:93)
        at com.reactnativenavigation.utils.CollectionUtils.forEach(CollectionUtils.java:76)
        at com.reactnativenavigation.viewcontrollers.ParentController.applyBottomInset(ParentController.java:175)
        at com.reactnativenavigation.viewcontrollers.-$$Lambda$PdnjwIMOFJug2YGdC1rKp4pGYAA.on(lambda)
        at com.reactnativenavigation.utils.CollectionUtils.forEach(CollectionUtils.java:93)
        at com.reactnativenavigation.utils.CollectionUtils.forEach(CollectionUtils.java:76)
        at com.reactnativenavigation.viewcontrollers.ParentController.applyBottomInset(ParentController.java:175)
        at com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabsController.applyBottomInset(BottomTabsController.java:186)
        at com.reactnativenavigation.viewcontrollers.bottomtabs.-$$Lambda$yeWoV8F6YAMT2qdLVg9HcIP0M2A.run(lambda)
        at com.reactnativenavigation.utils.ObjectUtils.perform(ObjectUtils.java:10)
        at com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabsController.onMeasureChild(BottomTabsController.java:173)
        at com.reactnativenavigation.views.BehaviourDelegate.onMeasureChild(BehaviourDelegate.java:22)
        at com.reactnativenavigation.views.BehaviourDelegate.onMeasureChild(BehaviourDelegate.java:7)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:813)
        at android.view.View.measure(View.java:18804)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
        at android.view.View.measure(View.java:18804)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
        at android.view.View.measure(View.java:18804)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at android.view.View.measure(View.java:18804)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
        at android.view.View.measure(View.java:18804)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
        at android.view.View.measure(View.java:18804)
        at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2112)
        at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1228)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1464)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1119)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6060)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
        at android.view.Choreographer.doCallbacks(Choreographer.java:670)
        at android.view.Choreographer.doFrame(Choreographer.java:606)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
        at android.os.Handler.handleCallback(Handler.java:746)
        at android.os.H

package.json

{
  "dependencies": {
    "@react-native-community/async-storage": "^1.6.2",
    "@react-native-community/geolocation": "^2.0.2",
    "@react-native-firebase/analytics": "^6.0.0",
    "@react-native-firebase/app": "^6.0.0",
    "@react-native-firebase/crashlytics": "^6.0.0",
    "axios": "^0.18.0",
    "eventemitter3": "^3.1.2",
    "formik": "^1.3.2",
    "immutable": "^4.0.0-rc.12",
    "lodash": "^4.17.11",
    "moment": "^2.24.0",
    "numeral": "^2.0.6",
    "react": "16.9.0",
    "react-native": "0.61.1",
    "react-native-action-button": "^2.8.5",
    "react-native-auto-height-image": "^1.0.5",
    "react-native-bottom-action-sheet": "^1.0.2",
    "react-native-camera": "3.6.0",
    "react-native-circular-progress": "^1.0.1",
    "react-native-color-matrix-image-filters": "5.2.0",
    "react-native-config": "^0.11.5",
    "react-native-counter": "git+https://github.com/JEGardner/react-native-counter#a444b60bad6af928372056b456a6d4e15969b64d",
    "react-native-device-info": "^0.24.3",
    "react-native-dropdownalert": "^3.7.1",
    "react-native-fbsdk": "1.0.4",
    "react-native-image-crop-picker": "^0.25.2",
    "react-native-image-header-scroll-view": "^0.10.1",
    "react-native-image-progress": "^1.1.1",
    "react-native-iphone-x-helper": "^1.2.1",
    "react-native-keyboard-aware-scroll-view": "0.9.1",
    "react-native-masked-text": "^1.9.2",
    "react-native-modal-dropdown": "0.6.2",
    "react-native-navigation": "3.2.0-snapshot.524",
    "react-native-onesignal": "3.4.1",
    "react-native-scrollable-tab-view": "https://github.com/jayshooo/react-native-scrollable-tab-view.git#6ac253a078c71b0cf143f3f8bd75aee7b4ddde58",
    "react-native-status-bar-height": "^2.3.1",
    "react-native-svg": "^8.0.8",
    "react-native-video": "5.0.2",
    "react-native-webview": "^7.2.5",
    "react-redux": "^5.1.1",
    "redux": "4.0.1",
    "redux-axios-middleware": "^4.0.0",
    "redux-thunk": "^2.3.0",
    "reduxsauce": "^1.1.0",
    "slugify": "^1.3.4",
    "typesafe-actions": "^4.4.2",
    "yup": "^0.26.6"
  }
}
const bottomTabs =  {
  children: [
    {
      stack: [
        {
          children: [
            {
              component: { name: "HOME_HOME", id: "ID_OTHER", passProps: { navType: "ROOT", tabIndex: 0 } },
            },
            {
              component: { name: "NEWS_NEWS_LIST", id: "NEWS_LIST_COMPONENT_ID", passProps: { navType: "SUB_PAGE", tabIndex: 0 } },
            },
            {
              component: { id: "ID_OTHER", name: "USER_PROFILE_UPDATE" },
            }
          ],
          options: {
            bottomTab: { icon: 8, iconColor: "#B3B3B3", selectedIconColor: "#1A783D", selectedTextColor: "#1A783D" },
          },
        }
      ]
    }
  ],
  id: 'BOTTOM_TAB',
  options: {
    bottomTabs: {
      animate: false,
      currentTabIndex: 0,
      drawBehind: true,
      visible: false,
    }
  }
}

Navigation.setRoot({ root: { bottomTabs } })