微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

React Native填坑之旅--布局篇

代码
https://github.com/future-challenger/petshop/tree/master/client/petshop/src/controller

回头看看RN的填坑之旅系列,发现一路写下来都是我在开发中遇到的问题如何解决的。兴之所至,不问顺序。于是出现一个问题,填坑系列和学习知识的顺序不是很一致。比如今天要说的布局问题。其实在一个app开发之前,就应该有所了解。否则的话每次看到的<View style={{flex: 1}} />代表的是什么呢?上来就是一个疑问。

在这个系列进行到一定程度的时候,我会花时间重新整理全系列的文章,让各位可以按照知识本来学习的顺序循序渐进的学习React Native的知识,避免在开发中遇到不应该遇到的问题。

正文开始。本文主要是介绍基础知识,但是不适用基础的代码。所以,如果你在看的时候有什么问题弄不清楚的话,随时查阅官网。那么问题是什么?三个View放在一个父View里显示出来会是设么样子的?这五个子View每次只要显示一个的话应该如何处理?

首先我们先来一点开胃小菜:

认的情况下NavigationBar的左侧回退按钮看起来是这样的:

图中可见,按钮紧贴上沿。这个时候的布局是这样的:

<TouchableHighlight
        style={{backgroundColor: 'red',width: 50}}
        onPress={() => {
            if (index > 0) {
                navigator.pop();
            }
        }}>
        <Text style={{ marginLeft: 10,backgroundColor: 'yellow' }}>Back</Text> </TouchableHighlight>

如何让NavigationBar的按钮竖直居中呢?不要想在TouchableHighlight添加的样式可以起作用。只有在外层再包裹一层View才可以。并给外层的View设置样式,让其中的内容竖直居中才可以。

<View style={{flex:1,justifyContent: 'center'}}>
        <TouchableHighlight  style={{backgroundColor: 'red',width: 50}} onPress={() => { if (index > 0) { navigator.pop(); } }}> <Text style={{ marginLeft: 10,backgroundColor: 'yellow' }}>Back</Text> </TouchableHighlight> </View>

开始填坑

下面要实现一个效果。我们已经有三个横向排列的,等宽度的View。对应的还有三个按钮,每一个按钮对应一个View。但是,不要三个View都显示出来。每次只显示一个。点一个按钮就显示出对应的View来。

Flex的方向

先来看看制造问题的代码重现:

<View style={{flex: 1,marginTop: 64}}>
    <View style={{flex: 1,backgroundColor: 'red'}}></View> <View style={{flex: 1,backgroundColor: 'orange'}}></View> <View style={{flex: 1,backgroundColor: 'yellow'}}></View> </View>

看起来是这样的:

认的,在一个View里的子View都是竖直依次排列的。

React Native使用FlexBox来实现布局的。FlexBox两个方向,一个column一个row
- column的flexBox方向,是竖直的,从上到下的方向。如上例的图片中截面里红、橙、黄三个颜色的view排列的方向。
- row是横向的,从左到右的方向。

我们来看看flexBox在row方向的样子:

<View style={{flex: 1,flexDirection: 'row',backgroundColor: 'yellow'}}></View> </View>

添加了按钮以后的界面看起来是这样的:

JustifyContent & AlignItems

在flow已经决定了子view排列的方向的时候。还需要进一步的调整子view的时候就会用到justifyContentalignItems

在和flow指定的方向同一方向上调整的时候使用justifyContent。flow指定的方向为主方向。要在次方向上指定子view如何排列就是用alignItems。如果flexDirection指定的是column(竖直方向),那么主方向就是竖直的,次方向就是水平的。

Flex的值

上面介绍了flex的方向,这里来说说flex的值。

在兄弟姐妹关系的View中,如果他们的flex都是1,那么他们评分父view的空间。如果,有一个flex的值是2,那么就是说这个子View的宽(高)是其他的兄弟姐妹的2倍。

在flex为0的时候,View的宽高就完全需要靠自己了。也就是这个view的宽和高需要设置具体的数值。系统不会替你计算。

如果flow为-1,那么View的宽度和高度,由width和height决定。*在空间不够的情况下,view的宽度和高度会缩小到minWidthminHeight

看看我们要实现的效果代码

效果

实现代码

export default class FlexDemo extends React.Component {
  _onPress: (buttonIndex: number) => void;

  constructor(props) {
    super(props);
    this.state = {
      view1Style: {flex: 1,width: 0},// If flex is 1,width does not work.
      view2Style: {flex: 0,view3Style: {flex: 0,width: 0}
    };

    this._onPress = this._onPress.bind(this);
  }

  _onPress(buttonIndex) {
    switch(buttonIndex) {
      case 0:
        this.setState({
          view1Style: {flex: 1,width does not work.
          view2Style: {flex: 0,width: 0}
        });
        break;
      case 1:
        this.setState({
          view1Style: {flex: 0,width does not work.
          view2Style: {flex: 1,width: 0}
        });
        break;
      case 2:
        this.setState({
          view1Style: {flex: 0,view3Style: {flex: 1,width: 0}
        });
        break;
      default:
        this.setState({
          view1Style: {flex: 1,width: 0}
        });
        break;
    }
  }

  render() {
    return (
  <View style={{flex: 1,flexDirection: 'row',marginTop: 64}}> <View key="view1" style={[this.state.view1Style, {backgroundColor: 'red'}]}></View> <View key="view2" style={[this.state.view2Style, {backgroundColor: 'orange'}]}></View> <View key="view3" style={[this.state.view3Style, {backgroundColor: 'yellow'}]}></View> <View style={{ flex: 1,justifyContent: 'space-between',alignItems: 'center',position: 'absolute',height: 50,left:0,right: 0,bottom: 0,backgroundColor: 'black',opacity: 0.6 }}> <View style={{flex: 1,justifyContent:'center'}} key='b1'> <TouchableOpacity  style={styles.button} onPress={()=>this._onPress(0)}> <Text style={styles.buttonText}>1</Text> </TouchableOpacity> </View> <View style={{flex: 1,justifyContent: 'center'}} key='b2'> <TouchableOpacity  style={styles.button} onPress={()=>this._onPress(1)}> <Text style={styles.buttonText}>2</Text> </TouchableOpacity> </View> <View style={{flex: 1,justifyContent: 'center'}} key='b3'> <TouchableOpacity  style={styles.button} onPress={()=>this._onPress(2)}> <Text style={styles.buttonText}>3</Text> </TouchableOpacity> </View> </View> </View> ); } };

实现原理:
如何去改变一个组件的外观布局?自然少不了setState方法。一开始,我们就把这几个子view的布局都放在state里。

在下面的三个按钮的点击事件中,设置不同的state,那么赤、橙和黄三个view就会发生变化。

前面提高flex的值为0的时候widthheight起作用,flex不为0的时候不起作用。这就是核心算法之所在了。在一开始让红色的view的flex为1。其他的view的flex为0,并且宽度也为0

之后每次点击了一个按钮的时候,对应的view的布局设置为flex等于1,其他的view的flex为0。这样就实现了上面的效果

小小的练习

最后留一个练习题,上面的效果对于一个简单的View来说也可以使用conditional render来搞定。那么就请你做一个这样的练习。

最后

上面的讲解都是我遇到的问题的讲解。包含了一些flexBox布局的基础,但是更难理解一下。React Native的布局包括的东西还有很多。后续会在本文或者系列的其他的文章中讲解。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...