React Native:方向变化时应用不同的样式
React Native: Different styles applied on orientation change
我正在开发一个 React Native 应用程序,将作为本机应用程序部署在 iOS 和 Android(以及 Windows,如果可能的话)。
问题是我们希望布局根据屏幕尺寸和方向不同。
我制作了一些 return 样式对象 的函数,并在每个组件渲染函数上调用,因此我能够在应用程序启动时应用不同的样式,但如果方向(或屏幕大小)在应用程序初始化后发生变化,则不会重新计算或重新应用它们。
我已将侦听器添加到顶部渲染,以便它在方向更改时更新其状态(并强制渲染应用程序的其余部分),但子组件不会重新渲染(因为,事实上,他们没有被改变).
所以,我的问题是:我怎样才能根据屏幕尺寸和方向使完全不同的样式,就像 CSS 媒体查询(即时呈现)一样?
我已经尝试过 react-native-responsive 模块,但没有成功。
谢谢!
我终于做到了。不知道它可能带来的性能问题,但它们应该不是问题,因为它只在调整大小或方向更改时调用。
我制作了一个全局控制器,其中有一个函数可以接收组件(容器、视图)并向其添加事件侦听器:
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
}
});
}
有了这个,当方向发生变化或 window 调整大小时,我强制重新渲染组件。
然后,在每个组件构造函数上:
import ScreenMetrics from './globalFunctionContainer';
export default class UserList extends Component {
constructor(props){
super(props);
this.state = {};
ScreenMetrics.bindScreenDimensionsUpdate(this);
}
}
这样,每次 window 调整大小或方向更改时都会重新呈现。
你应该注意,然而,这必须应用于我们想要监听方向变化的每个组件,因为如果 parent 容器更新但children 的 state
(或 props
)不更新,它们不会被重新渲染,所以 它可能是一个性能杀手 如果我们有一棵大 children 树在听它。
希望对大家有所帮助!
您可以使用 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({
...
});
如果使用 Hooks。可以参考这个解决方案:
应用程序的方向从纵向到横向,反之亦然是一项听起来很容易的任务,但当方向改变时必须改变视图时,在 React Native 中可能会很棘手。换句话说,可以通过考虑这两个步骤来实现为两个方向定义不同的视图。
从 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()' 这样我们就不用再担心渲染了,一切都搞定了。
到目前为止,我使用这个库取得了最大的成功:https://github.com/axilis/react-native-responsive-layout
它可以满足您的要求以及更多。简单的组件实现几乎没有像上面一些更复杂的答案那样的逻辑。我的项目通过 RNW 使用 Phone、平板电脑、 和网络 - 并且实现完美无缺。此外,在调整浏览器大小时,它是真正响应式的,而不仅仅是在初始渲染时 - 完美处理 phone 方向变化。
示例代码(将任何组件作为块的子项):
<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>
给这个:
我已经为我的 expo SDK36 项目编写了一个 HoC 解决方案,它支持方向更改并根据 ScreenOrientation.Orientation
值传递 props.orientation
。
import React, { Component } from 'react';
import { ScreenOrientation } from 'expo';
export default function withOrientation(Component) {
class DetectOrientation extends React.Component {
constructor(props) {
super(props);
this.state = {
orientation: '',
};
this.listener = this.listener.bind(this);
}
UNSAFE_componentWillMount() {
this.subscription = ScreenOrientation.addOrientationChangeListener(this.listener);
}
componentWillUnmount() {
ScreenOrientation.removeOrientationChangeListener(this.subscription);
}
listener(changeEvent) {
const { orientationInfo } = changeEvent;
this.setState({
orientation: orientationInfo.orientation.split('_')[0],
});
}
async componentDidMount() {
await this.detectOrientation();
}
async detectOrientation() {
const { orientation } = await ScreenOrientation.getOrientationAsync();
this.setState({
orientation: orientation.split('_')[0],
});
}
render() {
return (
<Component
{...this.props}
{...this.state}
onLayout={this.detectOrientation}
/>
);
}
}
return (props) => <DetectOrientation {...props} />;
}
为了实现更高性能的集成,我将以下内容用作我的每个反应导航屏幕的超类:
export default class BaseScreen extends Component {
constructor(props) {
super(props)
const { height, width } = Dimensions.get('screen')
// use this to avoid setState errors on unmount
this._isMounted = false
this.state = {
screen: {
orientation: width < height,
height: height,
width: width
}
}
}
componentDidMount() {
this._isMounted = true
Dimensions.addEventListener('change', () => this.updateScreen())
}
componentWillUnmount() {
this._isMounted = false
Dimensions.removeEventListener('change', () => this.updateScreen())
}
updateScreen = () => {
const { height, width } = Dimensions.get('screen')
if (this._isMounted) {
this.setState({
screen: {
orientation: width < height,
width: width, height: height
}
})
}
}
将任何根组件设置为从此组件扩展,然后将屏幕状态从继承的根组件传递给您的 leaf/dumb 组件。
此外,为避免增加性能开销,请更改样式对象而不是向组合中添加更多组件:
const TextObject = ({ title }) => (
<View style={[styles.main, screen.orientation ? styles.column : styles.row]}>
<Text style={[styles.text, screen.width > 600 ? {fontSize: 14} : null ]}>{title}</Text>
</View>
)
const styles = StyleSheet.create({
column: {
flexDirection: 'column'
},
row: {
flexDirection: 'row'
},
main: {
justifyContent: 'flex-start'
},
text: {
fontSize: 10
}
}
我希望这对以后的任何人都有帮助,您会发现它在开销方面非常理想。
我制作了一个超轻组件来解决这个问题。
https://www.npmjs.com/package/rn-orientation-view
组件在方向改变时重新呈现它的内容。
例如,您可以传递 landscapeStyles 和 portraitStyles 以不同方式显示这些方向。
适用于 iOS 和 Android。
它易于使用。看看吧。
我遇到了同样的问题。方向改变后布局没有改变。
然后我明白了一个简单的想法——布局应该取决于应该在渲染函数中计算的屏幕宽度,即
getScreen = () => {
return Dimensions.get('screen');
}
render () {
return (
<View style={{ width: this.getScreen().width }>
// your code
</View>
);
}
在这种情况下,将在渲染时计算宽度。
这是@Mridul Tripathi 作为可重用钩子的回答:
// useOrientation.tsx
import {useEffect, useState} from 'react';
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;
};
/**
* A React Hook which updates when the orientation changes
* @returns whether the user is in 'PORTRAIT' or 'LANDSCAPE'
*/
export function useOrientation(): 'PORTRAIT' | 'LANDSCAPE' {
// State to hold the connection status
const [orientation, setOrientation] = useState<'PORTRAIT' | 'LANDSCAPE'>(
isPortrait() ? 'PORTRAIT' : 'LANDSCAPE',
);
useEffect(() => {
const callback = () => setOrientation(isPortrait() ? 'PORTRAIT' : 'LANDSCAPE');
Dimensions.addEventListener('change', callback);
return () => {
Dimensions.removeEventListener('change', callback);
};
}, []);
return orientation;
}
然后您可以使用它:
import {useOrientation} from './useOrientation';
export const MyScreen = () => {
const orientation = useOrientation();
return (
<View style={{color: orientation === 'PORTRAIT' ? 'red' : 'blue'}} />
);
}
React Native 也有 useWindowDimensions
钩子,returns 设备的宽度和高度。
这样,您可以通过比较宽度和高度轻松检查设备是 'Portrait' 还是 'Landscape'。
查看更多 here
** 我将此逻辑用于横向和纵向逻辑。**
** 如果我首先在横向启动我的应用程序,我将获得设备的真实高度。并相应地管理 header 的高度。**
const [deviceOrientation, setDeviceOrientation] = useState(
Dimensions.get('window').width < Dimensions.get('window').height
? 'portrait'
: 'landscape'
);
const [deviceHeight, setDeviceHeight] = useState(
Dimensions.get('window').width < Dimensions.get('window').height
? Dimensions.get('window').height
: Dimensions.get('window').width
);
useEffect(() => {
const setDeviceHeightAsOrientation = () => {
if (Dimensions.get('window').width < Dimensions.get('window').height) {
setDeviceHeight(Dimensions.get('window').height);
} else {
setDeviceHeight(Dimensions.get('window').width);
}
};
Dimensions.addEventListener('change', setDeviceHeightAsOrientation);
return () => {
//cleanup work
Dimensions.removeEventListener('change', setDeviceHeightAsOrientation);
};
});
useEffect(() => {
const deviceOrientation = () => {
if (Dimensions.get('window').width < Dimensions.get('window').height) {
setDeviceOrientation('portrait');
} else {
setDeviceOrientation('landscape');
}
};
Dimensions.addEventListener('change', deviceOrientation);
return () => {
//cleanup work
Dimensions.removeEventListener('change', deviceOrientation);
};
});
console.log(deviceHeight);
if (deviceOrientation === 'landscape') {
return (
<View style={[styles.header, { height: 60, paddingTop: 10 }]}>
<TitleText>{props.title}</TitleText>
</View>
);
} else {
return (
<View
style={[
styles.header,
{
height: deviceHeight >= 812 ? 90 : 60,
paddingTop: deviceHeight >= 812 ? 36 : 10
}
]}>
<TitleText>{props.title}</TitleText>
</View>
);
}
我正在使用 styled-components
,这就是我 re-render UI 方向改变的方式。
import React, { useState } from 'react';
import { View } from 'react-native';
import { ThemeProvider } from 'styled-components';
import appTheme from 'constants/appTheme';
const App = () => {
// Re-Layout on orientation change
const [theme, setTheme] = useState(appTheme.getTheme());
const onLayout = () => {
setTheme(appTheme.getTheme());
}
return (
<ThemeProvider theme={theme}>
<View onLayout={onLayout}/>
{/* Components */}
</ThemeProvider>
);
}
export default App;
即使您没有使用 styled-components
,您也可以创建状态并将其更新到 onLayout
到 re-render UI。
这是我的解决方案:
const CheckOrient = () => {
console.log('screenHeight:' + Dimensions.get('screen').height + ', screenWidth: ' + Dimensions.get('screen').width);
}
return ( <
View onLayout = {
() => CheckOrient()
} >
............
<
/View>
纯成分案例的注意事项。 @mridul-tripathi 答案工作正常,但如果使用纯组件,那么可能只有 parent/top-level 组件对方向变化做出反应是不够的。您还需要在方向更改时单独更新纯组件。
我正在开发一个 React Native 应用程序,将作为本机应用程序部署在 iOS 和 Android(以及 Windows,如果可能的话)。
问题是我们希望布局根据屏幕尺寸和方向不同。
我制作了一些 return 样式对象 的函数,并在每个组件渲染函数上调用,因此我能够在应用程序启动时应用不同的样式,但如果方向(或屏幕大小)在应用程序初始化后发生变化,则不会重新计算或重新应用它们。
我已将侦听器添加到顶部渲染,以便它在方向更改时更新其状态(并强制渲染应用程序的其余部分),但子组件不会重新渲染(因为,事实上,他们没有被改变).
所以,我的问题是:我怎样才能根据屏幕尺寸和方向使完全不同的样式,就像 CSS 媒体查询(即时呈现)一样?
我已经尝试过 react-native-responsive 模块,但没有成功。
谢谢!
我终于做到了。不知道它可能带来的性能问题,但它们应该不是问题,因为它只在调整大小或方向更改时调用。
我制作了一个全局控制器,其中有一个函数可以接收组件(容器、视图)并向其添加事件侦听器:
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
}
});
}
有了这个,当方向发生变化或 window 调整大小时,我强制重新渲染组件。
然后,在每个组件构造函数上:
import ScreenMetrics from './globalFunctionContainer';
export default class UserList extends Component {
constructor(props){
super(props);
this.state = {};
ScreenMetrics.bindScreenDimensionsUpdate(this);
}
}
这样,每次 window 调整大小或方向更改时都会重新呈现。
你应该注意,然而,这必须应用于我们想要监听方向变化的每个组件,因为如果 parent 容器更新但children 的 state
(或 props
)不更新,它们不会被重新渲染,所以 它可能是一个性能杀手 如果我们有一棵大 children 树在听它。
希望对大家有所帮助!
您可以使用 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({
...
});
如果使用 Hooks。可以参考这个解决方案:
应用程序的方向从纵向到横向,反之亦然是一项听起来很容易的任务,但当方向改变时必须改变视图时,在 React Native 中可能会很棘手。换句话说,可以通过考虑这两个步骤来实现为两个方向定义不同的视图。
从 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()' 这样我们就不用再担心渲染了,一切都搞定了。
到目前为止,我使用这个库取得了最大的成功:https://github.com/axilis/react-native-responsive-layout 它可以满足您的要求以及更多。简单的组件实现几乎没有像上面一些更复杂的答案那样的逻辑。我的项目通过 RNW 使用 Phone、平板电脑、 和网络 - 并且实现完美无缺。此外,在调整浏览器大小时,它是真正响应式的,而不仅仅是在初始渲染时 - 完美处理 phone 方向变化。
示例代码(将任何组件作为块的子项):
<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>
给这个:
我已经为我的 expo SDK36 项目编写了一个 HoC 解决方案,它支持方向更改并根据 ScreenOrientation.Orientation
值传递 props.orientation
。
import React, { Component } from 'react';
import { ScreenOrientation } from 'expo';
export default function withOrientation(Component) {
class DetectOrientation extends React.Component {
constructor(props) {
super(props);
this.state = {
orientation: '',
};
this.listener = this.listener.bind(this);
}
UNSAFE_componentWillMount() {
this.subscription = ScreenOrientation.addOrientationChangeListener(this.listener);
}
componentWillUnmount() {
ScreenOrientation.removeOrientationChangeListener(this.subscription);
}
listener(changeEvent) {
const { orientationInfo } = changeEvent;
this.setState({
orientation: orientationInfo.orientation.split('_')[0],
});
}
async componentDidMount() {
await this.detectOrientation();
}
async detectOrientation() {
const { orientation } = await ScreenOrientation.getOrientationAsync();
this.setState({
orientation: orientation.split('_')[0],
});
}
render() {
return (
<Component
{...this.props}
{...this.state}
onLayout={this.detectOrientation}
/>
);
}
}
return (props) => <DetectOrientation {...props} />;
}
为了实现更高性能的集成,我将以下内容用作我的每个反应导航屏幕的超类:
export default class BaseScreen extends Component {
constructor(props) {
super(props)
const { height, width } = Dimensions.get('screen')
// use this to avoid setState errors on unmount
this._isMounted = false
this.state = {
screen: {
orientation: width < height,
height: height,
width: width
}
}
}
componentDidMount() {
this._isMounted = true
Dimensions.addEventListener('change', () => this.updateScreen())
}
componentWillUnmount() {
this._isMounted = false
Dimensions.removeEventListener('change', () => this.updateScreen())
}
updateScreen = () => {
const { height, width } = Dimensions.get('screen')
if (this._isMounted) {
this.setState({
screen: {
orientation: width < height,
width: width, height: height
}
})
}
}
将任何根组件设置为从此组件扩展,然后将屏幕状态从继承的根组件传递给您的 leaf/dumb 组件。
此外,为避免增加性能开销,请更改样式对象而不是向组合中添加更多组件:
const TextObject = ({ title }) => (
<View style={[styles.main, screen.orientation ? styles.column : styles.row]}>
<Text style={[styles.text, screen.width > 600 ? {fontSize: 14} : null ]}>{title}</Text>
</View>
)
const styles = StyleSheet.create({
column: {
flexDirection: 'column'
},
row: {
flexDirection: 'row'
},
main: {
justifyContent: 'flex-start'
},
text: {
fontSize: 10
}
}
我希望这对以后的任何人都有帮助,您会发现它在开销方面非常理想。
我制作了一个超轻组件来解决这个问题。 https://www.npmjs.com/package/rn-orientation-view
组件在方向改变时重新呈现它的内容。 例如,您可以传递 landscapeStyles 和 portraitStyles 以不同方式显示这些方向。 适用于 iOS 和 Android。 它易于使用。看看吧。
我遇到了同样的问题。方向改变后布局没有改变。 然后我明白了一个简单的想法——布局应该取决于应该在渲染函数中计算的屏幕宽度,即
getScreen = () => {
return Dimensions.get('screen');
}
render () {
return (
<View style={{ width: this.getScreen().width }>
// your code
</View>
);
}
在这种情况下,将在渲染时计算宽度。
这是@Mridul Tripathi 作为可重用钩子的回答:
// useOrientation.tsx
import {useEffect, useState} from 'react';
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;
};
/**
* A React Hook which updates when the orientation changes
* @returns whether the user is in 'PORTRAIT' or 'LANDSCAPE'
*/
export function useOrientation(): 'PORTRAIT' | 'LANDSCAPE' {
// State to hold the connection status
const [orientation, setOrientation] = useState<'PORTRAIT' | 'LANDSCAPE'>(
isPortrait() ? 'PORTRAIT' : 'LANDSCAPE',
);
useEffect(() => {
const callback = () => setOrientation(isPortrait() ? 'PORTRAIT' : 'LANDSCAPE');
Dimensions.addEventListener('change', callback);
return () => {
Dimensions.removeEventListener('change', callback);
};
}, []);
return orientation;
}
然后您可以使用它:
import {useOrientation} from './useOrientation';
export const MyScreen = () => {
const orientation = useOrientation();
return (
<View style={{color: orientation === 'PORTRAIT' ? 'red' : 'blue'}} />
);
}
React Native 也有 useWindowDimensions
钩子,returns 设备的宽度和高度。
这样,您可以通过比较宽度和高度轻松检查设备是 'Portrait' 还是 'Landscape'。
查看更多 here
** 我将此逻辑用于横向和纵向逻辑。** ** 如果我首先在横向启动我的应用程序,我将获得设备的真实高度。并相应地管理 header 的高度。**
const [deviceOrientation, setDeviceOrientation] = useState( Dimensions.get('window').width < Dimensions.get('window').height ? 'portrait' : 'landscape' ); const [deviceHeight, setDeviceHeight] = useState( Dimensions.get('window').width < Dimensions.get('window').height ? Dimensions.get('window').height : Dimensions.get('window').width ); useEffect(() => { const setDeviceHeightAsOrientation = () => { if (Dimensions.get('window').width < Dimensions.get('window').height) { setDeviceHeight(Dimensions.get('window').height); } else { setDeviceHeight(Dimensions.get('window').width); } }; Dimensions.addEventListener('change', setDeviceHeightAsOrientation); return () => { //cleanup work Dimensions.removeEventListener('change', setDeviceHeightAsOrientation); }; }); useEffect(() => { const deviceOrientation = () => { if (Dimensions.get('window').width < Dimensions.get('window').height) { setDeviceOrientation('portrait'); } else { setDeviceOrientation('landscape'); } }; Dimensions.addEventListener('change', deviceOrientation); return () => { //cleanup work Dimensions.removeEventListener('change', deviceOrientation); }; }); console.log(deviceHeight); if (deviceOrientation === 'landscape') { return ( <View style={[styles.header, { height: 60, paddingTop: 10 }]}> <TitleText>{props.title}</TitleText> </View> ); } else { return ( <View style={[ styles.header, { height: deviceHeight >= 812 ? 90 : 60, paddingTop: deviceHeight >= 812 ? 36 : 10 } ]}> <TitleText>{props.title}</TitleText> </View> ); }
我正在使用 styled-components
,这就是我 re-render UI 方向改变的方式。
import React, { useState } from 'react';
import { View } from 'react-native';
import { ThemeProvider } from 'styled-components';
import appTheme from 'constants/appTheme';
const App = () => {
// Re-Layout on orientation change
const [theme, setTheme] = useState(appTheme.getTheme());
const onLayout = () => {
setTheme(appTheme.getTheme());
}
return (
<ThemeProvider theme={theme}>
<View onLayout={onLayout}/>
{/* Components */}
</ThemeProvider>
);
}
export default App;
即使您没有使用 styled-components
,您也可以创建状态并将其更新到 onLayout
到 re-render UI。
这是我的解决方案:
const CheckOrient = () => {
console.log('screenHeight:' + Dimensions.get('screen').height + ', screenWidth: ' + Dimensions.get('screen').width);
}
return ( <
View onLayout = {
() => CheckOrient()
} >
............
<
/View>
纯成分案例的注意事项。 @mridul-tripathi 答案工作正常,但如果使用纯组件,那么可能只有 parent/top-level 组件对方向变化做出反应是不够的。您还需要在方向更改时单独更新纯组件。