ReactNative之参照具体示例来看RN中的FlexBox布局

今天是重阳节,祝大家节日快乐,今天继续更新RN相关的博客。上篇博客《ReactNative之从HelloWorld中看环境搭建、组件封装、Props及State》中我们通过一个HelloWorld的一个示例介绍了RN的环境搭建、组件封装、Props以及States。经过这么多天,今天我们继续来看RN的东西,本篇博客是关于RN的Flex布局的,也就是说是关于RN中控件放哪儿的一篇博客。在RN中使用的是Flex布局,如果你之前接触过Web前端的话对FlexBox布局并不陌生,但是如果你之前没做过Web开发的话,也不影响看今天的博客。本篇博客也是RN开发的基础,算是比较重要的。

RN中控件的布局方式与Web前端开发中的div+css的盒式布局是极为相似的。本篇博客就来详细的讲解一下RN中的FlexBox布局,中文名“弹性布局”。RN中的FlexBox布局和CSS中的FlexBox大体相同,也是通过一些属性来控制控件的位置、大小以及各个控件之间的关系。在FlexBox中分为 容器属性(flexDirection、flexWrap、alignItems、justifyContent、alignContent)和 元素属性(flex、alignSelf、margin、padding、border、width、height等等)。顾名思义,容器属性是用来添加到 父组件上来控制子组件的位置的属性,而 元素属性则是添加到子组件本身控制本身的一种属性。稍后会详细介绍。

接下来我们将根据具代码来详细的介绍常用的几种FlexBox布局的属性,。根据常用性,下方会依次介绍RN中的Flex布局中的flex、flexDirection、justifyContent、alignContent、flexWrap、AlignItem、AlignSelf这些常用的属性。本篇博客所涉及的Demo会上传到博客最后方的github链接中。

先入为主,下方这个gif中所有的内容就是我们今天要结束的东西,全是关于Flex布局的。

  

 

 

一、Flex

首先我们先来看一下flex的使用方式,flex属性接收的是一个number类型的值, 该值表示弹性布局的比例系数。具体的我们还要看一下下方关于Flex的一个Demo。

下方就是flex的具体使用方式,其中的flexValue是一个number类型的值。

接下来我们来看一下flex具体的一个示例。我们通过点击来修改中间的flex的值来观察flex对每个view的影响:

  • 三个黑块中的初始的flex值为1, 所以三个黑色方块会平分屏幕。
  • 每点击一次,中间的黑块的flex数增加1,然后我们就看到中间黑块会增大,三个黑块的比例变成了1 :  2 : 1。每次点击都会有变化。 

  ReactNative之参照具体示例来看RN中的FlexBox布局_第1张图片

 

最后我们来简单的看一下该效果的实现,代码如下。

  • 首先我们来看一下item的实现,Item即对应着每个黑块。这个item方法有个名为 flexValue的参数,该参数用来接收设置的flex的值。所以在item中我们将flexValue指定给了View的flex属性。
  • 然后我们在看一下render中的实现。在 Render中,我们添加了一个View来容纳item(黑块),View中三个item就对应着上述的三个黑块。中间的item的flex的值是从Status中获取的,下方会介绍到。
  • 最后我们在看一个 ClickView这个方法,该方法会在点击View时执行,执行该方法时,我们为 Status存储的flexValue自增了1。也就是说没点击 1 次中间的item的flex就会增加1。所以我们最终看到的效果是没点击一次,中间的黑块会增大。

  ReactNative之参照具体示例来看RN中的FlexBox布局_第2张图片

下方是上述示例的完整代码:

 1 // flex
 2 import { Component } from "react";
 3 import { TouchableOpacity, View, Text } from "react-native";
 4 import React from "react";
 5 
 6 type FlexStateType = {
 7   flexValue: number
 8 }
 9 export default class FlexTestComponent extends Component<null, FlexStateType> {
10   flexValue = 1;
11   constructor(props) {
12     super(props);
13     this.state = {
14       flexValue: this.flexValue
15     };
16   }
17 
18   clickView = () => {
19     this.flexValue ++;
20     this.setState({flexValue: this.flexValue})
21   };
22 
23   item = (flexValue: number) => {
24     return (
25       
26         flex = {flexValue}
27       
28     );
29   };
30 
31   render () {
32     const {
33       flexValue
34     } = this.state;
35     return (
36       this.clickView}>
37         
38           {this.item(1)}
39           {this.item(flexValue)}
40           {this.item(1)}
41         
42       
43     );
44   }
45 }
View Code

 

 

 

二、FlexDirection

看完flex属性,接下来我们来看一下flexDirection属性。该属性在FlexBox布局中也是一个尤为重要而且比较常用的一个属性。flexDirection主要是用来控制子元素的布局方向的,主要分为横向布局和纵向布局,默认是纵向布局(column)。下方是flexDirection的属性值和使用方式。

属性值:

flexDirection?: "row" | "column" | "row-reverse" | "column-reverse";

用法示例:

flexDirection的属性值主要有以下几个:

  • row : '行',该值表示子元素 自左向右横向排列, 。如下图的row, 先放的子元素1,如果有子元素2的话,会放到子元素1的右边,依次类推的横向布局。
  • row-reverse: '逆向的行',这个与row相反,该属性表示 自右向左横向排列。具体参见下图中的row-reverse。
  • column:'列',该属性值表示子元素 自上而下纵向排列,具体参见下方的column。
  • column-reverse: '逆向的列',这个与column相反,该属性则表示 自下而上的纵向排列,具体参见下方的column-reverse。

  

 

因该部分的demo对应的代码比较简单,介绍如下:

  • 首先我们封装了一个名为 FlexDirectionTestView的视图,该视图对应着上述展示 1 2 3的视图。该视图对外留了一个属性,用来接收 flexDirection。外边传入什么flexDirection的值,1 2 3这三个子视图就按什么排列。
  • FlexDirectionTestComponent组件中,我们就调用了 FlexDirectionTestView这个视图,传入了不同的flexDirection属性,从而这个 1 2 3 子元素就会按照我们要求的样式去展示。

  ReactNative之参照具体示例来看RN中的FlexBox布局_第3张图片

完整代码示例:

 1 // flexDirection
 2 import React, { Component } from 'react'
 3 import { FlexStyle, StyleSheet, Text, View } from 'react-native'
 4 
 5 export default  function FlexDirectionTestComponent () {
 6   return (
 7     
 8       
 9         
10         
11       
12 
13       
14         
15         
16       
17     
18   )
19 }
20 
21 type FlexDirectionProps = {
22   value?: FlexStyle
23 }
24 
25 class FlexDirectionTestView extends Component {
26   render () {
27     return (
28       this.props.value.flexDirection }]}>
29         
30         
31         
32       
33     )
34   }
35 }
36 
37 type SubViewProps = {
38   value: string
39 }
40 class SubView extends Component {
41   render () {
42     return(
43       
44          {this.props.value} 
45       
46     )
47   }
48 }
49 
50 const myStyle = StyleSheet.create({
51   subViewStyle: {
52     margin: 10,
53     borderRadius: 25,
54     width: 25,
55     height: 25,
56     backgroundColor: 'red',
57     justifyContent: 'center',
58     alignItems: 'center'
59   },
60   flexDirectionProps: {
61     backgroundColor: 'gray',
62     margin: 5
63   }
64 });
View Code

 

 

 

三、JustifyContent

今天这篇博客的干货还是比较足的,接下来我们来看一下第三个比较重要的属性justifyContent。该属性也是比较常用的,通常被用来控制子元素的左右方向的布局,这个与上面的flexDirection不同,justifyContent会控制整体子元素左右方向上的一个约束关系。下方是justifyContent的属性值和使用方式

属性值:

justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly"

用法示例:

具体的还得看下方这个GIF图,该图中就列举了justifyContent所有的属性值,并且展示了每个属性值的不同表现形式,接下来详细的介绍一下每个属性值的作用。

  • flex-start: 该属性值的功能是让所有 子元素靠左对齐,如下方点击flex-start的布局形式。
  • center: 则表示子元素在 左右方向上居中展示,如下方点击Center按钮对应的布局形式。
  • flex-end: 这个与flex-start相反,flex-end则表示 子元素靠右对齐,对应着下方点击flex-end按钮的布局形式。
  • space-between:从字面意思上不难看出,该属性值对应的是左右 间距平分于子元素中间的布局方式,设置该属性值后,左右边上是子元素是紧贴父View的左右边距的,间距平分与子元素中间。
  • space-around: 该属性也是比较好理解的,就是 左右间距环绕在子元素周围,从下方点击space-around的效果不难看出,设置该属性后,每个元素的左右边距是一致的,环绕在子元素之间。
  • space-evenly: 该属性值的意思是 子元素的左右间距均分,这个间距包括子元素与子元素的间距,还包括子元素与父元素的间距。

  ReactNative之参照具体示例来看RN中的FlexBox布局_第4张图片

 

介绍完上述属性,我们来简单的看一下该示例的实现代码,从上述操作来看本部分的Demo会相对复杂一些。首先来看一下上述按钮区域对应的代码片段:

  • 首先我们定义了一个 OperaView来容纳所有的点击的View,在该View中调用了我们自定义的customButton组件。
  • customButton组件接收一个参数,这个参数对应的就是justifyContent的属性值。每次点击该按钮,就会把按钮对应的属性值写入Status中。
  • 方法ClickView即为CustomButton点击时对应执行的方法。

  ReactNative之参照具体示例来看RN中的FlexBox布局_第5张图片

 

看完按钮区域的代码,接下来我们就来看一下布局区域的代码:

  • 首先来看一下Item,下方的 item函数返回的就是布局区域的每个方框,每个方框的高度相同,宽度由参数决定。
  • 然后在看一下 resultDisplayView, 该View函数对应的就是按钮下方的布局区域,该View的 JustifyContent属性的值是直接从state中获取的。
  • 最后就来看一下render中了,在 render中分别调用了按钮区和布局区两块的内容。

  ReactNative之参照具体示例来看RN中的FlexBox布局_第6张图片

 

完整代码如下:

 1 // justifyContent
 2 import { Component } from "react";
 3 import { Text, TouchableOpacity, View } from "react-native";
 4 import React from "react";
 5 
 6 type JustifyContentType = "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly";
 7 type JustifyContentCompontStateType = {
 8   justifyContentValue: JustifyContentType
 9 }
10 export default class JustifyContentTestComponent extends Component<null, JustifyContentCompontStateType> {
11   constructor(props) {
12     super(props);
13     this.state = {
14       justifyContentValue: 'flex-start'
15     };
16   }
17 
18   clickView = (value: JustifyContentType) => () => {
19     this.setState({ justifyContentValue: value});
20   };
21 
22   customButton = (title: JustifyContentType) => {
23     return (
24       this.clickView(title)}>
25         
26           {title}
27         
28       
29     );
30   };
31 
32   operaView = () => {
33     return (
34       {{
35         height: 90,
36         width: '100%',
37         justifyContent: 'center',
38         alignItems: 'center',
39         flexDirection:'row',
40         flexWrap:'wrap'}}>
41         {this.customButton('flex-start')}
42         {this.customButton('flex-end')}
43         {this.customButton('center')}
44         {this.customButton('space-between')}
45         {this.customButton('space-around')}
46         {this.customButton('space-evenly')}
47       
48     );
49   };
50 
51   item = (width: number) => {
52     return (
53       
54     );
55   };
56 
57   resultDisplayView = () => {
58     const {
59       justifyContentValue
60     } = this.state;
61     return (
62       
63         {this.item(60)}
64         {this.item(100)}
65         {this.item(30)}
66         {this.item(80)}
67         {this.item(100)}
68         {this.item(90)}
69         {this.item(30)}
70         {this.item(80)}
71       
72     );
73   };
74 
75   render () {
76     return (
77       
78         {this.operaView()}
79         {this.resultDisplayView()}
80       
81     );
82   }
83 }
View Code

 

 

 

四、AlignContent

接下来来看一下AlignContent这个属性及其相关的属性值。该属性与上面的JustifyContent属性的功能差不多,JustifyContent负责左右方向的子元素之间的关系,而AlignContent则负责上下方向上的子元素之间的布局。下方是AlignContent的相关属性值和使用方式:

属性值:

alignContent?:"flex-start" | "flex-end" | "center" | "stretch" | "space-between" | "space-around"

用法示例:

 

按照上述的思路,我们还是通过一个Demo来看一下每个属性值的具体的作用。下方就是本部分对应的Demo,每个按钮对应着AlignContent的一个属性值,点击相关按钮后,下方的子元素就会按照点击的按钮进行设置。下方是具体介绍:

  • flex-start: 子元素顶部对齐,点击下方的flex-start按钮会看到所有子元素向上对齐了。
  • center: 上下方向上居中,也就是说设置该属性,子元素会在上下方向上进行居中展示。
  • flex-end: 该属性与flex-start相反, 设置该属性, 子元素会位于父元素的底部展示
  • space-between:间隔填充, 子元素的上下间距位于子元素中间
  • space-around: 即间隔环绕在子元素的上下,与JustifyContent的 space-around类似。
  • stretch:拉伸,该属性只有在子元素的高度没有设置的情况下适用,该情况下会自适应高度,以至填满父视图,具体如下所示:

  ReactNative之参照具体示例来看RN中的FlexBox布局_第7张图片

 

代码和之前的Demo的实现思路差不多,在此就不做过多赘述了,下方是该部分的完整示例:

 1 // alignItem
 2 import { FlexAlignType, Text, TouchableOpacity, View } from "react-native";
 3 import { Component } from "react";
 4 import React from "react";
 5 
 6 type AlignContentType = "flex-start" | "flex-end" | "center" | "stretch" | "space-between" | "space-around";
 7 
 8 type AlignContentTestCompontStateType = {
 9   alignContentValue: AlignContentType
10 }
11 export default class AlignContentTestComponent extends Component<null, AlignContentTestCompontStateType> {
12   constructor(props) {
13     super(props);
14     this.state = {
15       alignContentValue: 'flex-start'
16     };
17   }
18 
19   clickView = (title: AlignContentType) => () => {
20     this.setState({ alignContentValue: title});
21   };
22 
23   customButton = (title: AlignContentType) => {
24     return (
25       this.clickView(title)}>
26         
27           {title}
28         
29       
30     );
31   };
32 
33   operaView = () => {
34     return (
35       {{
36         height: '40%',
37         width: '100%',
38         justifyContent: 'center',
39         alignItems: 'center',
40         flexDirection:'row',
41         flexWrap:'wrap'}}>
42         {this.customButton('flex-start')}
43         {this.customButton('center')}
44         {this.customButton('flex-end')}
45         {this.customButton('space-between')}
46         {this.customButton('space-around')}
47         {this.customButton('stretch')}
48       
49     );
50   };
51 
52   item = (width: number, height: number) => {
53     return (
54       
55     );
56   };
57 
58   resultDisplayView = () => {
59     const {
60       alignContentValue
61     } = this.state;
62 
63     let height = 30;
64     if (alignContentValue === 'stretch') {
65       height = -1;
66     }
67     return (
68       
69         {this.item(50, height)}
70         {this.item(80, height)}
71         {this.item(30, height)}
72         {this.item(60, height)}
73         {this.item(50, height)}
74         {this.item(100, height)}
75         {this.item(30, height)}
76         {this.item(50, height)}
77         {this.item(80, height)}
78         {this.item(30, height)}
79       
80     );
81   };
82 
83   render () {
84     return (
85       
86         {this.operaView()}
87         {this.resultDisplayView()}
88       
89     );
90   }
91 }
AlignContent

 

 

 

五、flexWrap

接下来看一下flexWrap这个属性,该属性负责折行的。例如当一个View没有设置flexWrap属性时,子元素又是横排的情况时,会在一行上一直往后排,并不会折行。如果想折行的话,那么就得使用这个flexWrap属性了,下方是flexWrap属性的相关值和用法:

属性值:

flexWrap?:"wrap" | "nowrap" | "wrap-reverse"

用法示例:

 

 

flexWrap的属性值比较少,也比较好理解,下方就进行简单的描述:

  • wrap: 折行,设置该属性意味着一行放不下时会自动换到下一行进行展示。
  • nowrap: 不这行,默认值,超出屏幕后也一直往一行后边叠加。
  • wrap-reverse: 逆向折行,这个虽然在查看类型的时候有这个选项,但是实测是不可用的,可忽略

下方就是flexWrap所对应的Demo, 该Demo中的View就设置了flexWrap的属性为wrap的值,没点击一次我们就随机的往后边添加一个随机宽度的子View。从下方gif中不难看出,当最后一个View放不下时会自动的换到下一行进行展示。具体如下所示:

  

 该示例的完整代码:

 1 // flexWrap
 2 import { Component } from "react";
 3 import { TouchableOpacity, View } from "react-native";
 4 import React from "react";
 5 
 6 type FlexWrapTestComponentStateType = {
 7   allViews: Array
 8 }
 9 export default class FlexWrapTestComponent extends Component<null, FlexWrapTestComponentStateType> {
10   constructor(props) {
11     super(props);
12     this.state = {
13       allViews : [this.item()]
14     };
15   }
16 
17   clickView = () => {
18     let items = this.state.allViews;
19     items.push(this.item());
20     this.setState({allViews: items});
21   };
22 
23   item = () => {
24     let randomWidth = Math.random() * 100 + 10;
25     return (
26       
27     );
28   };
29 
30   render () {
31     return (
32       this.clickView}>
33         
34           {this.state.allViews}
35         
36       
37     );
38   }
39 }
FlexWrap

 

  

 

六、AlignItem

该属性也是比较常用的,用来定义子元素在交叉轴上的对齐方式。也就是说,子元素是横向排列的,那么该属性就约定纵轴方向上的对齐方式。AlignItem属性的属性值也没几个,也比较好理解,下方是AlignItem对应的熟悉值和使用方式:

属性值:

type FlexAlignType = "flex-start" | "flex-end" | "center" | "stretch" | "baseline";

用法示例:

 

  

下方就是真的AlignItem实现的一个Demo, 我们将根据下方的Demo来具体的看一下AlignItem所对应的每个属性值的作用,具体如下所示:

  • flex-start: 首先还是来看一下flex-start, 下方我们的子元素是横向排列的,所以设置flex-start时,就意味着, 子元素在纵轴开始的位置对齐,也就是顶部对齐。
  • center: 也是以横向排列的子元素为例,当设置alignItem为Center时,表示 交叉轴方向上居中对齐,具体在该Demo中表现的是上下方向上居中对齐。
  • flex-end: 这个与flex-start相反,表示以 交叉轴的尾部对齐
  • baseline: 这个就比较有意思了,设置该属性值就意味着子元素以子元素中的 文字的基线对齐

  ReactNative之参照具体示例来看RN中的FlexBox布局_第8张图片

该示例完整代码如下:

 1 // alignItem
 2 import { FlexAlignType, Text, TouchableOpacity, View } from "react-native";
 3 import { Component } from "react";
 4 import React from "react";
 5 
 6 type AlignItemTestCompontStateType = {
 7   alignItemValue: FlexAlignType
 8 }
 9 export default class AlignItemTestComponent extends Component<null, AlignItemTestCompontStateType> {
10   constructor(props) {
11     super(props);
12     this.state = {
13       alignItemValue: 'flex-start'
14     };
15   }
16 
17   clickView = (title: FlexAlignType) => () => {
18     this.setState({ alignItemValue: title});
19   };
20 
21   customButton = (title: FlexAlignType) => {
22     return (
23       this.clickView(title)}>
24         
25           {title}
26         
27       
28     );
29   };
30 
31   operaView = () => {
32     return (
33       34       }}>
35         {this.customButton('flex-start')}
36         {this.customButton('center')}
37         {this.customButton('flex-end')}
38         {this.customButton('stretch')}
39         {this.customButton('baseline')}
40       
41     );
42   };
43 
44   item = (height: number, fontSize: number) => {
45     return (
46       
47          {fontSize} 
48       
49     );
50   };
51 
52   resultDisplayView = () => {
53     const {
54       alignItemValue
55     } = this.state;
56 
57     let heights = [100, 150, 80];
58     if (alignItemValue === 'stretch') {
59       heights = [-1, -1, -1];
60     }
61     return (
62       
63         {this.item(heights[0], 10)}
64         {this.item(heights[1], 20)}
65         {this.item(heights[2], 30)}
66       
67     );
68   };
69 
70   render () {
71     return (
72       
73         {this.operaView()}
74         {this.resultDisplayView()}
75       
76     );
77   }
78 }
AlignItem

 

 

 

七、AlignSelf

最后我们来看一下这个AlignSelf属性,该属性是元素属性,主要设置在子元素上,用来控制单个子元素在父元素的交叉轴的位置。AlignSelf的作用方式与AlignItem差不多,只不过一个作用于父元素,一个是作用于子元素。下方是AlignSelf的属性值和用法示例:

属性值:

type FlexAlignType = "flex-start" | "flex-end" | "center" | "stretch" | "baseline";
type AlignSelfType = "auto" | FlexAlignType; 

用法示例:

 
   
 

 

最后我们仍然通过一个Demo来看一下AlignSelf的表现形式。在下方Demo中我们依次为右边中间的黑块设置的AlignSelf属性。每个属性的值的意思可参见AlignItem的属性值,只不过这些属性值是作用于子元素的。具体关于AlignSelf的内容就不做过多赘述了。

  ReactNative之参照具体示例来看RN中的FlexBox布局_第9张图片

该部分Demo完整示例:

 1 // alignSelf
 2 import { FlexAlignType, Text, TouchableOpacity, View } from "react-native";
 3 import { Component } from "react";
 4 import React from "react";
 5 
 6 type AlignSelfTestCompontStateType = {
 7   alignItemValue: FlexAlignType
 8 }
 9 export default class AlignSelfTestComponent extends Component<null, AlignSelfTestCompontStateType> {
10   constructor(props) {
11     super(props);
12     this.state = {
13       alignItemValue: 'flex-start'
14     };
15   }
16 
17   clickView = (title: FlexAlignType) => () => {
18     this.setState({ alignItemValue: title});
19   };
20 
21   customButton = (title: FlexAlignType) => {
22     return (
23       this.clickView(title)}>
24         
25           {title}
26         
27       
28     );
29   };
30 
31   operaView = () => {
32     return (
33       34       }}>
35         {this.customButton('flex-start')}
36         {this.customButton('center')}
37         {this.customButton('flex-end')}
38         {this.customButton('stretch')}
39       
40     );
41   };
42 
43   resultDisplayView = () => {
44     const {
45       alignItemValue
46     } = this.state;
47 
48     let height = 80;
49     if (alignItemValue === 'stretch') {
50       height = -1
51     }
52     return (
53       
54         
55         
56         
57       
58     );
59   };
60 
61   render () {
62     return (
63       
64         {this.operaView()}
65         {this.resultDisplayView()}
66       
67     );
68   }
69 }
AlignSelf

 

 

经过本篇博客的详细介绍想必对FlexBox有了更详细的了解,掌握了上述属性后,在RN中写布局应该就不是什么难事儿了。当然本篇博客值介绍了FlexBox布局比较核心的部分,想什么Margin、Padding等等这些属性比较简单,就不做过多赘述了。本篇博客所涉及的所有Demo会在github上给出,下方会给出相关链接。

下篇博客会集中根据具体示例来聊一下RN中常用的动画。

 github地址:https://github.com/lizelu/ReactNativeTestDemo

你可能感兴趣的:(javascript,前端,ViewUI)