【问题标题】:React-Native + Flex not responding to orientation changeReact-Native + Flex 不响应方向变化
【发布时间】:2015-07-07 00:25:25
【问题描述】:

我正在使用 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);

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

但是当设备旋转时。红色视图不会相应旋转。

【问题讨论】:

    标签: ios flexbox react-native


    【解决方案1】:

    最简单的方法是:

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

    【讨论】:

    • 我会向大家推荐这个
    • 谢谢,我没有意识到您需要将 onLayout 作为道具传递给视图...认为它更像是 componentWillMount 等,=)
    • 或者您可以查看 react-native-styleman 库,它为您提供媒体查询,让您只需在样式中处理此问题,而无需手动处理事件。
    【解决方案2】:

    在 react native 中响应方向变化非常简单。 react native 中的每个视图都有一个名为 onLayout 的侦听器,它在方向更改时被调用。我们只需要实现它。最好将维度存储在状态变量中并在每个方向更改时更新,以便在更改后重新渲染。否则我们需要重新加载视图以响应方向变化。

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

    【讨论】:

    • 我试过这个,但似乎没有用。 onLayout 函数在应用启动时被触发,但旋转模拟器并没有重新触发该事件。
    • 我尝试使用 _onLayout 但它发送的布局无效。它显示宽度为 1024,高度为 1024。
    • eventSize: {"width":1024,"x":0,"height":1024,"y":0} width: 768, height: 1024 onLayout 显示错误数据。实际上视图在横向仍然显示纵向数据和事件显示错误数据
    【解决方案3】:

    对于 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 调用。

    【讨论】:

    • 是的,这正是我正在发生的事情。为此需要使用 Dimension。
    • 对于 2020 年 3 月创建的新 RN 项目,我还必须将 android:screenOrientation="fullSensor" 添加到 android/app/src/main/AndroidManifest.xml
    【解决方案4】:

    您可以使用 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
         });
    
       }
    

    这个我也用过,但是性能太低了。

    希望对您有所帮助...

    【讨论】:

      【解决方案5】:

      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 将确保它在方向更改时弯曲以填充整个容器。

      【讨论】:

        【解决方案6】:

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

        -(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation

        【讨论】:

        • 您能解释一下吗?
        【解决方案7】:

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

        【讨论】:

        • 我们没有exp.json
        【解决方案8】:

        根据用户Rajan Twanabashu 给出的答案,您还可以使用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
        };
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-05-20
          • 2016-11-19
          • 1970-01-01
          • 2015-08-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多