React-native-router-flux: Navbar appears at bottom in RNv0.23

Created on 7 Apr 2016  路  25Comments  路  Source: aksonov/react-native-router-flux

Version

  • react-native-router-flux v3.2.2
  • react-native v0.23.0

    Expected behaviour

The nav bar should appear at the top of the screen.

Actual behaviour

The nav bar appears at the bottom of the screen.

Steps to reproduce

  1. Specify a scene with a navigation bar
  2. Run the app (iOS & Android)

    Notes

This also occurs in RNv0.24-rc2, but was not present in RNv0.22.

Most helpful comment

Well... at least it's a funny bug 馃槃

All 25 comments

I also see this warning after upgrading from 0.22 to 0.23 :
screen shot 2016-04-07 at 19 55 17

but i'm not sure it's related to this bug

Having several other issues in RNv0.23 most router navigation is inconsistent, swipe back is broken. I don't think official support is ready yet

Well... at least it's a funny bug 馃槃

PR would be welcome to make it work with 0.23

A quick fix : add position: absolute; top:0; left:0; to the custom NavBar

Edit : and a width too

Same bug here, and position: absolute makes my NavBar component disappear.

try to set a width

Thx @sylvainbaronnet, it works. But it's obviously less than optimal as it forces us to display each scene in position: absolute with a top value to avoid hiding content under the navBar.

Sure a proper fix is required.

Instead of a position: absolute to all your scene you can just set a marginTop

In the meanwhile here is a temporary solution I'm using in an app I'm working on, hope it can help (when the issue will be fixed just remove the row commented with // TO-DO in Toolbar.js and it should work):

router.js

import React, { Platform, StyleSheet } from 'react-native'
import { Scene, Router, Modal, NavBar } from 'react-native-router-flux'
import MyScreen from './containers/MyScreen'
import Toolbar from './components/Toolbar'
import Colors from './theme/colors'
import Metrics from './theme/metrics'

const IS_ANDROID = Platform.OS === 'android'

export default () => {
  return (
    <Router>
      <Scene key='modal' component={Modal}>
        <Scene key='root'>
          <Scene
            titleStyle={styles.titleStyle}
            sceneStyle={styles.sceneStyle}
            key='myScreen'
            component={MyScreen}
            title='Museums'
            type='replace'
            navBar={IS_ANDROID ? Toolbar : NavBar}
            hideNavbar={IS_ANDROID}
          />
        </Scene>
      </Scene>
    </Router>
  )
}

const styles = StyleSheet.create({
  navigationBarStyle: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: Colors.PRIMARY
  },
  titleStyle: {
    color: 'white'
  },
  sceneStyle: {
    flex: 1,
    paddingTop: Metrics.NAVBAR_HEIGHT,
    backgroundColor: 'white'
  }
})

Toolbar.js (used only on Android)

import React, { StyleSheet } from 'react-native'
import Colors from '../theme/colors'
import Metrics from '../theme/metrics'
import Icon from 'react-native-vector-icons/Ionicons'

export default ({ title }) =>
  <Icon.ToolbarAndroid
    actions={[]}
    navIconName='android-arrow-back'
    style={styles.toolbar}
    titleColor='white'
    title={title}
  />

const styles = StyleSheet.create({
  toolbar: {
    backgroundColor: Colors.PRIMARY,
    height: Metrics.NAVBAR_HEIGHT,
    position: 'absolute', top: 0, left: 0, width: Metrics.DEVICE_WIDTH // TO-DO
  }
})

metrics.js

import { Dimensions, Platform } from 'react-native'

const IS_ANDROID = Platform.OS === 'android'
const { height, width } = Dimensions.get('window')

export default {
  DEVICE_HEIGHT: height,
  DEVICE_WIDTH: width,
  NAVBAR_HEIGHT: IS_ANDROID ? 54 : 64
}

The workaround with position: absolute doesn't work anymore :(. Is there any other solution?

What version are you using? It is still working for me on "react-native-router-flux": "^3.24.0",

@mmazzarolo I am using "react-native-router-flux": "^3.24.0" as well. Tried with both RN 23 & 24, neither worked.

@donnguyen, that's weird! Did you already try setting this:

position: 'absolute', top: 0, left: 0, width: Metrics.DEVICE_WIDTH

On the toolbar like in my example? (Make sure to give it a width)

@mmazzarolo this is great solution and works partially but the problem in my case is that the toolbar doesn't adapt when screen rotates .. :/

@miqmago
Ouch, you're right, I'm forcing a vertical layout on my current project.
You might be able to update the toolbar on layout changes but it might be a little too much effort when the best option is just to wait for a fix (or even better... directly sending a pull request if you're able to fix it).

@mmazzarolo I would be very happy to contribute if I could, unfortunatelly it's my 4rth day with react-native and although it's exciting, I'm still lost in very basic things! :)

@miqmago Don't worry I wasn't taunting you, I'm not able to help either... but the fix might not come soon in my opinion because there are many other prorities right now (this module exploded after RN0.23 unfortunately :crying_cat_face:)

@mmazzarolo yes weird, below are screenshots when I haven't applied position: 'absolute', top: 0, left: 0, width: Metrics.DEVICE_WIDTH and when I have. Looks funny? 馃槃

simulator screen shot apr 23 2016 6 32 10 am
simulator screen shot apr 23 2016 6 32 25 am

I thought the problem was only with the Android toolbar, not with the iOS one... but I guess you're using a custom toolbar for iOS, right?
Can you post you code?

:sweat_smile: if it helps, I've managed to change the width with react-native-orientation plugin:

import Orientation from 'react-native-orientation';
...

const styles = StyleSheet.create({
    toolbar: {
        backgroundColor: Colors.PRIMARY,
        height: Metrics.NAVBAR_HEIGHT,
        position: 'absolute', top: 0, left: 0, // TO-DO
    },
});

export default class extends Component {
    constructor(props) {
        super(props);
        this.state = {};
        this.refreshToolbarWidth(Orientation.getInitialOrientation());
    }

    componentDidMount() {
        Orientation.addOrientationListener(this._orientationDidChange.bind(this));
    }

    _orientationDidChange(orientation) {
        this.refreshToolbarWidth(orientation);
        this.forceUpdate();
    }

    refreshToolbarWidth(orientation) {
        const { height, width } = Dimensions.get('window');
        this.state.initialOrientation = this.state.initialOrientation || orientation;
        if (this.state.initialOrientation === 'LANDSCAPE') {
            this.state.toolbarWidth = orientation === 'LANDSCAPE' ? width : height;
        } else {
            this.state.toolbarWidth = orientation === 'LANDSCAPE' ? height : width;
        }
    }

    render() {
        const title = this.props.getTitle(this.props.navigationState);
        const subTitle = this.props.getTitle(this.props.navigationState.children[this.props.navigationState.index]);
        return (
            <IonIcons.ToolbarAndroid
                title={title}
                subtitle={subTitle}
                navIconName="android-menu"
                actions={[
                    { title: 'Settings', iconName: 'gear-a', iconSize: 30, show: 'always' },
                    { title: 'Follow me on Twitter', iconName: 'social-twitter', iconColor: '#4099FF', show: 'ifRoom' },
                ]}
                style={[styles.toolbar, { width: this.state.toolbarWidth }]}
                titleColor={TextColors.primaryLighText.textShadowColor}
                subtitleColor={TextColors.secondaryLighText.textShadowColor}
                overflowIconName="more"
                />
        );
    }
}

489

This bug is still here because we need to set with to device width with custom toolbar like Icon.ToolbarAndroid like so:

{
  height:56
, position:'absolute'
, top:0
, left:0
, width: Dimensions.get('window').width
}

I tried to change the parent component and set alignItems to stretch according to the following comment: https://github.com/facebook/react-native/issues/2957#issuecomment-142664501
but it got complex pretty fast.

I could maybe dig deeper and pr this but I'm not sure. Locking screen orientation on app start as a workaround for now.

<activity
    ...
    android:screenOrientation="nosensor"
>

This is a little bit crazy. I was implementing custom navBar component and was kind of surprised to see it at the bottom of the page. I tried some stuff advised here and in other resources, but none of them helped, so I started to digging the source code of this and dependent libraries. After 2 hours of mind-blowing work, I ran against this piece of code on https://github.com/aksonov/react-native-experimental-navigation/blob/master/NavigationAnimatedView.js#L165

    return (
      <View
        onLayout={this._onLayout}
        style={this.props.style}>
        <View style={styles.scenes} key="scenes">
          {scenes}
        </View>
        {overlay} <-- renders navBar
      </View>
    );

I kind of felt some dirty stuff here, as navBar component is rendered after the scenes, so when I moved {overlay} above the View rendering the scenes, my custom navBar component finally got to the top.
I am new to react-native and do not understand how everything works here and I can't think this is a right way, so I decided to put it here. I hope somebody would open PR, if this is the correct solution for the problem.

I got round this with the following:

toolbar: { height: 56, elevation: 4, position: 'absolute', top:0, left:0, right:0 },

Hope it helps someone.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

booboothefool picture booboothefool  路  3Comments

GCour picture GCour  路  3Comments

willmcclellan picture willmcclellan  路  3Comments

VictorK1902 picture VictorK1902  路  3Comments

maphongba008 picture maphongba008  路  3Comments