我正在开发一个React Native应用程序,以便在iOS和Android(以及Windows,如果可能)上部署为本机应用程序。
问题是我们希望布局根据屏幕尺寸和方向而不同。
我做了一些返回样式对象的函数,并在每个组件渲染的函数上调用,所以我能够在应用程序启动时应用不同的样式,但是如果应用程序初始化后方向(或屏幕的大小)发生了变化,不重新计算也不重新应用。
我已将侦听器添加到顶部渲染,以便更新其在方向更改时的状态(并且它强制渲染应用程序的其余部分),但子组件不会重新渲染(因为实际上它们尚未更改)。
所以,我的问题是:如何根据屏幕大小和方向制作可能完全不同的样式,就像使用CSS媒体查询(即时呈现)一样?
我已经尝试过没有运气的react-native-responsive模块。
谢谢!
解决方案可以在[这里] [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()',因此我们不必担心再次渲染它,所有这些都需要处理。
你可以使用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({
...
});
最后,我已经能够这样做了。不知道它可以带来的性能问题,但它们不应该是一个问题,因为它只需要调整大小或方向更改。
我创建了一个全局控制器,我有一个接收组件(容器,视图)的函数,并为它添加一个事件监听器:
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
)未更新,则不会重新呈现它们,如果我们有一个大的儿童树听它,它可能是一个性能杀戮。
希望它可以帮到某人!
到目前为止,我在这个库中取得了最大的成功: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>
给这个: