Iv'e been working with react-native for a couple of weeks now and I have reached a point where I need to support both orientations. Allegedly flex-box should do its magic and automatically adapt the layout to the new screen size. However flex-box does not handle the changes as I would wish it were, I am not saying it does not do what is supposed to do I am saying I am just not happy with it.
To be more concrete, I found this example online which basically describes the problem I am trying to solve (only they do it with native views and auto-layout). I want to achieve layout changes on device rotation (or more generally on size changes) similar to those applied to that "mini Instagram" example I linked.
How can I do that with react-native and flex-box? Should I use different components for different screen sizes or is there a proper way to achieve that?
There's not much work to do to achieve this with react native. Here I have tried to demonstrate similar visual layout as you have asked.

We just need to listen for onLayout event of view that gets invoke whenever there is a change in orientation.
By comparing the height and width from Dimension.get('window') we can figure out the whether the device is in portrait or landscape mode. Here's the simple code for this
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Image,
Dimensions
} from 'react-native';
var {height, width} = Dimensions.get('window');
export default class Com extends Component{
constructor(){
console.log('constructor');
super();
this.state = {
layout:{
height:height,
width:width,
}
};
}
_onLayout = event => {
console.log('------------------------------------------------' + JSON.stringify(event.nativeEvent.layout));
this.setState({
layout:{
height:event.nativeEvent.layout.height,
width:event.nativeEvent.layout.width,
}
});
}
render(){
console.log(JSON.stringify(this.props));
var imagel = this.props.list[0].src;
var landscapeView =
<View style={{marginTop:20, flexDirection:'row'}}>
<Image source={require('./flower.jpg')} style={{height:this.state.layout.height-50, width:this.state.layout.width/2}}/>
<View>
<Text style={{backgroundColor:'gray', margin:5}}> header this is landscape view </Text>
<Text style={{backgroundColor:'gray',margin:5}}> footer this is portrait view </Text>
</View>
</View>
var portraitView = <View style={{marginTop:20}}>
<Text style={{backgroundColor:'gray', margin:5}}> header this is landscape view </Text>
<Image source={require('./flower.jpg')} style={{height:200, width:this.state.layout.width}}/>
<Text style={{backgroundColor:'gray',margin:5}}> footer this is portrait view </Text>
</View>
var cview =null;
if (this.state.layout.height>this.state.layout.width) {
cview = portraitView
}else{
cview = landscapeView;
}
return(
<View style={{backgroundColor:'red', flex:1}} onLayout={this._onLayout}>
{cview}
</View>
);
}
}
What's happening here is we are listening to event onLayout which are triggered when there is a orientation change. Then we have state variable which hold the actual height and width of the screen to reflect the orientation change. we are using this state height and width for view design.
Two things is happening here.
I don't think RN sends any rotation events from native to JS currently, but you will get a layout callback, so you can update your layout metrics in response to that. e.g.:
getInitialState(): {
return {isPortrait: true}; // You could use Dimensions to get this right initially?
},
render(): {
// return a different layout depending on this.state.isPortrait
return <View onLayout={this.onLayout} />
},
onLayout(e): {
var isPortrait = e.nativeEvent.layout.height > e.nativeEvent.layout.width;
if (isPortrait != this.state.isPortrait) {
this.setState({isPortrait});
}
}
Note: since JS view updates and layout all happen asynchronously, it will be hard to match the timing of the actual device rotation change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With