react-native 页面布局-flex布局

  RN中的布局我觉得主要包含这几个部分:像素单位,布局方式,组件,CSS。熟悉这几点后,就是经验的积累,见得多了做的多了布局代码写起来自然就快许多。  

  react native 的页面布局使用的是flex布局,Flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。flex只是一种元素布局方式,所以任何一个元素都可以设定flex,而一个元素设定了flex之后,那么它里面的所有元素都是在这个容器内布局。

  1. Flex:1

  在RN中的flex布局跟web中略有不同,RN中flex只可以指定一个数字, 根据具体数字值来填充展示当前元素,“1”即表示100%撑满当前容器,而该容器内的子元素只能够在该容器内区域布局。

  2. 主次轴

  容器内默认有两根轴,横轴和纵轴,当画一个页面时,首先要确定该页面或者该容器内是采用哪个轴作为主轴布局,其实就是行布局或者列布局。当确定主轴之后,另外一轴自动成为副轴。RN中使用flexDirection来定义当前容器是使用何种布局(column活row),默认为column。justifyContent 和 alignItems 分别制定主轴和次轴的排列方式。

  flexDirection: column;row;

  justifyContent:

    flex-start(默认,起始位置,一般都是左对齐);

    center(居中);

    flex-end(结尾,一般是右对齐);

    space-around;space-between;

  alignItems:

    flex-start(默认,起始位置,一般都是左对齐);

    center(居中);

    flex-end(结尾,一般是右对齐);

    stretch(均匀分布);

  当父容器指定了flex之后(比如1),那么如果子元素的flex也都设置为1,那么这些子元素将会平均分配父容器的尺寸来布局,就像如下代码:  

<View style={{flex:1,flexDirection:'row',backgroundColor:'#ffffff'}}>
        <View style={{flex:1,backgroundColor:'red'}}></View>
        <View style={{flex:1,backgroundColor:'black'}}></View>
        <View style={{flex:1,backgroundColor:'blue'}}></View>
      </View>
   

 

 

flexDirection:'column'      flexDirection:'row'

 

  再举个例子,子元素指定宽高,父容器采用space-between 和 space-around布局,代码如下:

     <View style={{flex:1,borderWidth:2,flexDirection:'column',backgroundColor:'#ffffff',justifyContent:'space-between', alignItems:'center'}}>
        <View style={{height:100,width:100,borderRadius:50,backgroundColor:'red'}}></View>
        <View style={{height:100,width:100,borderRadius:50,backgroundColor:'black'}}></View>
        <View style={{height:100,width:100,borderRadius:50,backgroundColor:'blue'}}></View>
      </View>

 

 

 

 justifyContent:'space-between'  justifyContent:'space-around'

 

  下面实现一个具体的例子,效果如下:

  

  这是一个表单页面,从这个图可以得出:

  1. 外层是主轴按照column排列。行元素撑满一行。

  2. 行元素高度固定,主轴按row排列,次轴的排列应该居中。

  3. 行元素有内衬,有分割线。

  4. 行元素内应该分左右两部分,分别左右对齐。

  根据这几点,我们可以大概写出这样的布局:

class Layout extends Component {
  render() {
    return (
     <View style={{flex:1,backgroundColor:'#dddddd',flexDirection:'column',justifyContent:'center'}}>
      <View style={LayoutStyles.row}>
        <Text style={{flex:1}}>真实姓名</Text>
        <View style={{flex:1,alignItems:'flex-end'}}>
          <Text style={{color:'#999999'}}>John</Text>
        </View>
      </View>
      <View style={LayoutStyles.row}>
        <Text>手机号码</Text>
        <View style={{flex:1,alignItems:'flex-end'}}>
          <Text style={{color:'#999999'}}>13812345678</Text>
        </View>
      </View>
     </View>
    );
  }
}

const LayoutStyles = StyleSheet.create({
  row: {
    backgroundColor:'#ffffff',
    height:47,
    flexDirection:'row',
    alignItems:'center',
    borderBottomWidth:0.5,
    borderBottomColor:'#dddddd',
    paddingHorizontal: 15
  }
});
View Code

这里可以看到, 在“手机号码”这一行内,用两个子元素Text和View分别设置flex:1来撑满行元素,然后设置view的末端对齐。

而“真实姓名”这一行只对view设置了flex:1,也达到了这个效果。

通过给view加上border看一下:

可以看出,如果在一个容器内,如果元素没有设置flex,那么默认会根据该元素的内容自动撑开宽度,而设置了flex:1的元素则会占满剩余的空间。

那么这里给 “真实姓名”这行的右边部分留下较大的空间,因为这里要放一个输入框,留下较大的区域可以方便它点中以获取焦点输入。

borderWidth问题

这样做使用borderWidth:0.5,这种写法在ios上是可以正常显示,但是在部分Android机型上显示异常。这个问题可以使用 StyleSheet.hairlineWidth 来避免这个问题。

这里分割线使用了行元素的下边框来做,其实也可以吧分割线作为一个单独的子元素来绘制,比如:

<View style={{height:1,backgroundColor:'#dddddd'}}></View>

 

分割线问题

跟效果图对比行元素的分割线没有撑满,而是随行内容一样存在内衬。这个问题,如果采用上面的方法把分割线作为子元素,则可以解决。

如果使用边框的话,可以在行元素内再包一层View,外层View设置padding,内层view设置borderBottomWidth即可。

最终代码:

class Layout extends Component {
  render() {
    return (
     <View style={{flex:1,backgroundColor:'#dddddd',flexDirection:'column',justifyContent:'center'}}>
      <View style={LayoutStyles.row}>
        <View style={LayoutStyles.rowContainer}>
          <Text>真实姓名</Text>
          <View style={{flex:1,alignItems:'flex-end',height:47}}>
            <TextInput style={LayoutStyles.inputTextName} underlineColorAndroid={'blue'}
            keyboardType={'default'} placeholder='请输入' placeholderTextColor='#999999'
            defaultValue={'laochan'}
            maxLength={10}
            />
          </View>
        </View>
      </View>
      <View style={LayoutStyles.row}>
        <View style={LayoutStyles.rowContainer}>
          <Text style={{flex:1}}>手机号码</Text>
          <View style={{flex:1,alignItems:'flex-end'}}>
            <Text style={{color:'#999999'}}>13812345678</Text>
          </View>
        </View>
      </View>
     </View>
    );
  }
}

const LayoutStyles = StyleSheet.create({
  row: {
    backgroundColor:'#ffffff',
    height:47,
    paddingHorizontal: 15
  },
  rowContainer: {
    flex: 1,
    flexDirection:'row',
    alignItems:'center',
    borderBottomWidth:StyleSheet.hairlineWidth,
    borderBottomColor:'#dddddd',
  },
  inputTextName: {
    flex:1,
    padding:0,
    fontSize:14,
    color: '#999999',
    textAlign: 'right',
    marginRight: 10
  }
});
View Code

 

 

参考资源:

http://reactnative.cn/docs/0.44/layout-with-flexbox.html#content

布局样式属性:http://reactnative.cn/docs/0.44/layout-props.html

flex布局:http://www.ruanyifeng.com/blog/2015/07/flex-examples.html

  

posted @ 2017-05-10 17:59  老颤  阅读(1383)  评论(0编辑  收藏  举报