web-dev-qa-db-ja.com

React Native:向きの変更に適用されるさまざまなスタイル

IOSでネイティブアプリケーションとしてデプロイされるReact Nativeアプリケーションを開発しています。Android(およびWindows、可能なら)。

問題は、画面のサイズと向きによって異なるレイアウトにすることです

stylesオブジェクトを返す関数をいくつか作成しました。すべてのコンポーネントレンダリングの関数で呼び出されるため、アプリケーションの起動時に異なるスタイルを適用できます。ただし、アプリの初期化後に向き(または画面のサイズ)が変更された場合、それらは再計算も再適用もされません。

レンダリングされた上部にリスナーを追加して、方向の変更時に状態を更新します(そして、アプリケーションの残りの部分を強制的にレンダリングします)が、サブコンポーネントは再レンダリングされません(実際、それらは変更されていません)。

だから、私の質問は次のとおりです:完全に異なるスタイルを持つようにするにはどうすればよいですかCSS Media Queries(オンザフライでレンダリングされます)と同様に、画面サイズと向きに基づきますか?

私はすでに試してみました react-native-responsive 運のないモジュール

ありがとうございました!

10
Unapedra

最後に、私はそうすることができました。それが運ぶことができるパフォーマンスの問題を知らないが、それはサイズ変更またはオリエンテーションの変更でのみ呼び出されるので、それらは問題ではないはずです。

コンポーネント(コンテナ、ビュー)を受け取り、それにイベントリスナーを追加する関数を持つグローバルコントローラーを作成しました。

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)の子は更新されず、再レンダリングされません。したがって、それをリッスンしている大きな子ツリーがある場合はパフォーマンスの低下になる可能性がありますです。

それが誰かを助けることを願っています!

3
Unapedra

解決策は[こちら] [1]にあります。

ポートレートからランドスケープ、またはその逆へのアプリの向きは簡単に聞こえますが、向きが変わったときにビューを変更する必要がある場合、ネイティブに反応するのは難しいかもしれません。言い換えると、これらの2つのステップを検討することで、2つの方向に異なるビューを定義することができます。

寸法のインポート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()」を呼び出すため、再度レンダリングすることを心配する必要はありません。すべて面倒を見てくれます。

19
Mridul Tripathi

onLayout propを使用できます:

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({
  ...
});
9
Adrian

私はこれまでのところ、このライブラリで最も成功しました: https://github.com/axilis/react-native-responsive-layout それはあなたが求めていることをしますなどなど。上記のより複雑な回答のようなロジックをほとんど持たないシンプルなコンポーネントの実装。私のプロジェクトは、電話、タブレット、、およびRNWを介したWebを使用しており、実装は完璧です。さらに、ブラウザーのサイズを変更するとき、最初のレンダリングだけでなく、真に応答性があります-電話の向きの変更は完璧に処理されます。

サンプルコード(コンポーネントをブロックの子として配置):

<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

0
Steven H