React-Native + Flex不响应方向更改

时间:2015-04-28 08:46:02

标签: ios flexbox react-native

我正在使用React-Native编写通用iPhone / iPad应用程序。但是当方向改变时,我正在努力正确地渲染我的视图。以下是js文件的源代码:

'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);

这是它在Portrait中呈现的方式(这是正确的): Portrait

然而,当设备旋转时。红色视图不会相应旋转。 Landscape

8 个答案:

答案 0 :(得分:13)

响应原生的方向变化非常简单。本机中的每个视图都有一个名为 onLayout 的侦听器,它会在方向更改时调用。我们只需要实现这一点。最好将维度存储在状态变量中并更新每个方向更改,以便在更改后重新呈现。另外,我们需要重新加载视图以响应方向更改。

enter image description here

 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>
    );
}
}

答案 1 :(得分:12)

最简单的方法是:

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 :(得分:6)

对于更新版本的React Native,方向更改不一定会触发onLayout,但Dimensions提供更直接相关的事件:

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>
        );
    }
}

请注意,此代码适用于应用的根组件。如果在应用程序中更深入地使用它,则需要包含相应的removeEventListener调用。

答案 3 :(得分:3)

您可以使用react-native-orientation来检测并执行方向更改的更改。

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

还使用返回大小(宽度,高度)的Dimension类。

Dimensions.get('window')

使用这些方法玩方向

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
     });

   }

我也使用了它,但它的性能太低了。

希望有帮助...

答案 4 :(得分:0)

行。我找到了答案。需要在我们的viewcontroller中实现以下内容并调用刷新其中的ReactNative视图。

- (无效)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation

答案 5 :(得分:0)

对于使用Exponent的任何人,您只需从exp.json删除orientation密钥。

答案 6 :(得分:0)

onLayoutDimensions.addEventListener在React 16.3中都没有为我们工作。

这是一个flexbox hack,它可以根据方向变化来调整图像大小。 (我们还使用React的不错的但文献记录不多的ImageBackground组件在图像上方获取文本):

      <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
  },
});

imageHeight样式将设置View组件的高度(用户不可见),然后Flexbox将自动将同一行上的图像弯曲为相同高度。因此,您基本上是在间接设置图像的高度。 Flex会确保在方向发生变化时可以弯曲以填充整个容器。

答案 7 :(得分:0)

用户Rajan Twanabashu给出的答案中的Appart,您还可以使用react-native-styleman库非常轻松地处理方向变化:

以下是您如何执行此操作的示例:

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
};