React Native:在方向更改时应用不同的样式

问题描述 投票:6回答:4

我正在开发一个React Native应用程序,以便在iOS和Android(以及Windows,如果可能)上部署为本机应用程序。

问题是我们希望布局根据屏幕尺寸和方向而不同。

我做了一些返回样式对象的函数,并在每个组件渲染的函数上调用,所以我能够在应用程序启动时应用不同的样式,但是如果应用程序初始化后方向(或屏幕的大小)发生了变化,不重新计算也不重新应用。

我已将侦听器添加到顶部渲染,以便更新其在方向更改时的状态(并且它强制渲染应用程序的其余部分),但子组件不会重新渲染(因为实际上它们尚未更改)。

所以,我的问题是:如何根据屏幕大小和方向制作可能完全不同的样式,就像使用CSS媒体查询(即时呈现)一样?

我已经尝试过没有运气的react-native-responsive模块。

谢谢!

css reactjs screen-orientation react-native
4个回答
16
投票

解决方案可以在[这里] [1]找到。

应用程序从纵向到横向的方向反之亦然是一项听起来很容易的任务,但是当方向发生变化时必须更改视图时,本机的反应可能会很棘手。换句话说,通过考虑这两个步骤可以实现为两个方向定义的不同视图。

从React Native导入维度

import { Dimensions } from 'react-native';

识别当前方向并相应地渲染视图

/**
 * Returns true if the screen is in portrait mode
 */
const isPortrait = () => {
    const dim = Dimensions.get('screen');
    return dim.height >= dim.width;
};

/**
 * Returns true of the screen is in landscape mode
 */
const isLandscape = () => {
    const dim = Dimensions.get('screen');
    return dim.width >= dim.height;
};

要知道何时更改方向以相应地更改视图

// Event Listener for orientation changes
    Dimensions.addEventListener('change', () => {
        this.setState({
            orientation: Platform.isPortrait() ? 'portrait' : 'landscape'
        });
    });

组装所有件

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

export default class App extends React.Component {
  constructor() {
    super();

    /**
    * Returns true if the screen is in portrait mode
    */
    const isPortrait = () => {
      const dim = Dimensions.get('screen');
      return dim.height >= dim.width;
    };

    this.state = {
      orientation: isPortrait() ? 'portrait' : 'landscape'
    };

    // Event Listener for orientation changes
    Dimensions.addEventListener('change', () => {
      this.setState({
        orientation: isPortrait() ? 'portrait' : 'landscape'
      });
    });

  }

  render() {
    if (this.state.orientation === 'portrait') {
      return (
          //Render View to be displayed in portrait mode
       );
    }
    else {
      return (
        //Render View to be displayed in landscape mode
      );
    }

  }
}

由于为查找方向更改而定义的事件使用此命令'this.setState()',此方法会自动再次调用'render()',因此我们不必担心再次渲染它,所有这些都需要处理。


9
投票

你可以使用onLayout道具:

export default class Test extends Component {

  constructor(props) {
    super(props);
    this.state = {
      screen: Dimensions.get('window'),
    };
  }

  getOrientation(){
    if (this.state.screen.width > this.state.screen.height) {
      return 'LANDSCAPE';
    }else {
      return 'PORTRAIT';
    }
  }

  getStyle(){
    if (this.getOrientation() === 'LANDSCAPE') {
      return landscapeStyles;
    } else {
      return portraitStyles;
    }
  }
  onLayout(){
    this.setState({screen: Dimensions.get('window')});
  }

  render() {
    return (
      <View style={this.getStyle().container} onLayout = {this.onLayout.bind(this)}>

      </View>
      );
    }
  }
}

const portraitStyles = StyleSheet.create({
 ...
});

const landscapeStyles = StyleSheet.create({
  ...
});

3
投票

最后,我已经能够这样做了。不知道它可以带来的性能问题,但它们不应该是一个问题,因为它只需要调整大小或方向更改。

我创建了一个全局控制器,我有一个接收组件(容器,视图)的函数,并为它添加一个事件监听器:

const getScreenInfo = () => {
    const dim = Dimensions.get('window');
    return dim;
}    

const bindScreenDimensionsUpdate = (component) => {
    Dimensions.addEventListener('change', () => {
        try{
            component.setState({
                orientation: isPortrait() ? 'portrait' : 'landscape',
                screenWidth: getScreenInfo().width,
                screenHeight: getScreenInfo().height
            });
        }catch(e){
            // Fail silently
        }
    });
}

有了这个,我强制在方向改变或窗口大小调整时重新渲染组件。

然后,在每个组件构造函数上:

import ScreenMetrics from './globalFunctionContainer';

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

    this.state = {};

    ScreenMetrics.bindScreenDimensionsUpdate(this);
  }
}

这样,每当窗口调整大小或方向改变时,它就会被重新渲染。

但是,您应该注意,这必须应用于我们想要监听方向更改的每个组件,因为如果父容器已更新但子级的state(或props)未更新,则不会重新呈现它们,如果我们有一个大的儿童树听它,它可能是一个性能杀戮。

希望它可以帮到某人!


0
投票

到目前为止,我在这个库中取得了最大的成功:https://github.com/axilis/react-native-responsive-layout它可以满足您的要求以及更多。简单的组件实现,几乎没有任何逻辑,如上面的一些更复杂的答案。我的项目是通过RNW使用手机,平板电脑和网络 - 实施完美无瑕。此外,在调整浏览器大小时,它真正具有响应能力,而不仅仅是初始渲染 - 处理手机方向变化完美无瑕。

示例代码(将任何组件作为块的子代):

<Grid>
  <Section> {/* Light blue */}
    <Block xsSize="1/1" smSize="1/2" />
    <Block xsSize="1/1" smSize="1/2" />
    <Block xsSize="1/1" smSize="1/2" /> 
  </Section>
  <Section> {/* Dark blue */}
    <Block size="1/1" smSize="1/2" />
    <Block size="1/1" smSize="1/2" />
    <Block size="1/1" smSize="1/2" />
    <Block size="1/1" smSize="1/2" />
    <Block size="1/1" smSize="1/2" />
  </Section>
</Grid>

给这个:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.