React-Native + Flex не реагирует на изменение ориентации

Я пишу приложение Universal iPhone/iPad, использующее React-Native. Однако я стараюсь правильно отображать свое мнение, когда меняется ориентация. Ниже приведен исходный код файла 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

Ответ 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>
    );
  }
}

Ответ 2

Довольно просто реагировать на изменение ориентации в реагировать на родную. У каждого представления в реагировать на натив есть слушатель по имени 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>
    );
}
}

Ответ 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.

Ответ 4

Вы можете использовать реакцию-native-ориентацию для обнаружения и выполнения изменений в изменении ориентации.

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

OK. Я нашел ответ на этот вопрос. Необходимо выполнить следующее в нашем диспетчере view и вызвать обновление нашего представления ReactNative внутри него.

- (недействительными) didRotateFromInterfaceOrientation: (UIInterfaceOrientation) fromInterfaceOrientation

Ответ 6

Для тех, кто использует Exponent, вам просто нужно удалить orientation от вашего exp.json.

Ответ 7

Ни onLayout, ни Dimensions.addEventListener не работали для нас в Реакте 16.3.

Вот хак с флексбоксом, который изменил размер изображения при смене ориентации. (Мы также использовали красивый, но плохо документированный компонент ImageBackground React, чтобы получить текст поверх изображения):

      <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 устанавливает высоту компонента "Вид" (который невидим для пользователя), а затем Flexbox автоматически сгибает изображение в той же строке, чтобы оно имело ту же высоту. Таким образом, вы в основном устанавливаете высоту изображения косвенным образом. Flex гарантирует, что он изгибается, чтобы заполнить весь контейнер при изменении ориентации.

Ответ 8

Придерживаясь ответа, данного пользователем Rajan Twanabashu, вы также можете использовать библиотеку Reaction-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 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
};