Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Adaptive Layout with React Native

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?

like image 432
Daniel Lahyani Avatar asked Dec 07 '25 23:12

Daniel Lahyani


2 Answers

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.

enter image description here

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.

  1. onLayout get invoked upon orientation change.
  2. upon changing state value, view will render again.
like image 178
Rajan Twanabashu Avatar answered Dec 09 '25 14:12

Rajan Twanabashu


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.

like image 42
Javache Avatar answered Dec 09 '25 13:12

Javache