React-Native + Flex not responding to orientation change

混江龙づ霸主 提交于 2020-06-09 16:50:12

问题


I am writing a Universal iPhone/iPad application using React-Native. However I am struggling to render my view correctly when the orientation changes. Following is the source code for js file:

'use strict';
    var React = require('react-native');

    var {
      Text,
      View
    } = React;

    var CardView = require('./CardView');

    var styles = React.StyleSheet.create({
      container:{
        flex:1,
        backgroundColor: 'red'
      }
    });

    class MySimpleApp extends React.Component {
      render() {
         return <View style={styles.container}/>;
      }
    }

    React.AppRegistry.registerComponent('SimpleApp', () => MySimpleApp);

This is how it renders in Portrait (which is correct): Portrait

However when the device is rotated. The red view does not rotate accordingly. Landscape


回答1:


The simplest way is:

import React, { Component } from 'react';
import { Dimensions, View, Text } from 'react-native';

export default class Home extends Component {
  constructor(props) {
    super(props);

    this.state = {
      width: Dimensions.get('window').width,
      height: Dimensions.get('window').height,
    }

    this.onLayout = this.onLayout.bind(this);

  }

  onLayout(e) {
    this.setState({
      width: Dimensions.get('window').width,
      height: Dimensions.get('window').height,
    });
  }

  render() {
    return(
      <View 
        onLayout={this.onLayout}
        style={{width: this.state.width}}
      >
        <Text>Layout width: {this.state.width}</Text>
      </View>
    );
  }
}



回答2:


It pretty simple to respond orientation change in react native. Every view in react native have a listener called onLayout which get invoked upon orientation change. We just need to implement this. It's better to store dimension in state variable and update on each orientation change so that re-rendering happens after change. Other wise we need to reload the view to respond the orientation change.

 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));
    return (
        <View
            style={{ backgroundColor: "red", flex: 1 }}
            onLayout={this._onLayout}
        >
            <View
                style={{
                    backgroundColor: "green",
                    height: this.state.layout.height - 10,
                    width: this.state.layout.width - 10,
                    margin: 5
                }}
            />
        </View>
    );
}
}



回答3:


For more recent versions of React Native, orientation change doesn't necessarily trigger onLayout, but Dimensions provides a more directly relevant event:

class App extends Component {
    constructor() {
        super();
        this.state = {
            width: Dimensions.get('window').width,
            height: Dimensions.get('window').height,
        };
        Dimensions.addEventListener("change", (e) => {
            this.setState(e.window);
        });
    }
    render() {
        return (            
            <View
                style={{
                    width: this.state.width,
                    height: this.state.height,
                }}
            >
            </View>
        );
    }
}

Note that this code is for the root component of an app. If using it deeper within the app, you will need to include a corresponding removeEventListener call.




回答4:


You can use react-native-orientation to detect and perform changes on orientation change.

var Orientation = require('react-native-orientation');

Also use Dimension class which return size(width, height).

Dimensions.get('window')

Use these methods to play with orientations

componentDidMount() {
    Orientation.lockToPortrait(); //this will lock the view to Portrait
    //Orientation.lockToLandscape(); //this will lock the view to Landscape
    //Orientation.unlockAllOrientations(); //this will unlock the view to all Orientations
    // self = this;
    console.log('componentDidMount');
    Orientation.addOrientationListener(this._orientationDidChange);
  }

  componentWillUnmount() {
    console.log('componentWillUnmount');
    Orientation.getOrientation((err,orientation)=> {
        console.log("Current Device Orientation: ", orientation);
    });
    Orientation.removeOrientationListener(this._orientationDidChange);
  }

  _orientationDidChange(orientation) {

    console.log('Orientation changed to '+orientation);
    console.log(self);

     if (orientation == 'LANDSCAPE') {
       //do something with landscape layout
       screenWidth=Dimensions.get('window').width;
       console.log('screenWidth:'+screenWidth);
     } else {
       //do something with portrait layout
       screenWidth=Dimensions.get('window').width;
       console.log('screenWidth:'+screenWidth);

     }

     self.setState({
       screenWidth:screenWidth
     });

   }

I also used this but It's performance is too low.

Hope that helps...




回答5:


Neither onLayout or Dimensions.addEventListener worked for us in React 16.3.

Here's a flexbox hack which made the image resize on change of orientation. (We also used React's nice but poorly documented ImageBackground component to get text on top of the image):

      <View style={styles.container}>
        <View style={styles.imageRowWithResizeHack}>
          <ImageBackground
            style={styles.imageContainer}
            imageStyle={styles.thumbnailImg}
            source={{ uri: thumbnailUrl }}
          >
            <View style={styles.imageText}>
              <Text style={styles.partnerName}>{partnerName}</Text>
              <Text style={styles.title}>{title.toUpperCase()}</Text>
            </View>
          </ImageBackground>
          <View style={styles.imageHeight} />
        </View>
      </View>


const styles = StyleSheet.create({
  container: {
    position: 'relative',
    flex: 1
  },
  imageRowWithResizeHack: {
    flex: 1,
    flexDirection: 'row'
  },
  imageContainer: {
    flex: 1
  },
  imageHeight: {
    height: 200
  },
  thumbnailImg: {
    resizeMode: 'cover'
  },
  imageText: {
    position: 'absolute',
    top: 30,
    left: TEXT_PADDING_LEFT
  },
  partnerName: {
    fontWeight: '800',
    fontSize: 20,
    color: PARTNER_NAME_COLOR
  },
  title: {
    color: COLOR_PRIMARY_TEXT,
    fontSize: 90,
    fontWeight: '700',
    marginTop: 10,
    marginBottom: 20
  },
});

The imageHeight style will set the height of the View component (which is invisible to the user), and Flexbox will then automatically flex the image on the same row to be of the same height. So you're basically setting the height of the image in an indirect manner. Flex will ensure it flexes to fill the entire container on orientation change.




回答6:


OK. I found an answer to this. Need to implement the following in our viewcontroller and call refresh our ReactNative view inside it.

-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation




回答7:


For anyone using Exponent you just need to remove the orientation key from your exp.json.




回答8:


Appart from the answer given by user Rajan Twanabashu you can also use the react-native-styleman library to handle orientation change very easily:

Here is an example of how you would do that:

import { withStyles } from 'react-native-styleman';

const styles = () => ({       
    container: {
        // your common styles here for container node.
        flex: 1,
        // lets write a media query to change background color automatically based on the device's orientation 
        '@media': [
          {
             orientation: 'landscape', // for landscape
             styles: {                 // apply following styles
                // these styles would be applied when the device is in landscape 
                // mode.
                 backgroundColor: 'green'
                 //.... more landscape related styles here...
             }
          },
          {
             orientation: 'portrait', // for portrait
             styles: {                // apply folllowing styles
                // these styles would be applied when the device is in portrait 
                // mode.
                 backgroundColor: 'red'
                 //.... more protrait related styles here...
             }
          }
        ]
    }
});

let Component = ({ styles })=>(
    <View style={styles.container}>
        <Text>Some Text</Text>
    </View>
);

// use `withStyles` Higher order Component.
Component = withStyles(styles)(Component);

export {
  Component
};


来源:https://stackoverflow.com/questions/29914572/react-native-flex-not-responding-to-orientation-change

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!