React Native 布局浅探

简述

在Web开发中,页面布局基于盒子模型,主要通过定位属性、浮动属性和显示属性实现。以div作为容器将页面分成一个个小区块,再根据一定的方式在页面进行排布。但是对于较为复杂的布局或者手持设备来说,上述几种方式实现起来十分繁琐。于是W3C引入了一种新型的布局方式Flex布局。React Native就是采用了这种方式,但它不是完整的web Flex布局。

通过一张图来大致了解flex的布局方式。

flex布局的基本思想是通过flex容器来伸缩控制子项目的宽度和高度。子项目在主轴上依次排列,在侧轴上填满flex容器的可用空间。

再看看Web flex和RN flex几点区别:
1、因为RN里的所有组件都是以flex作为其显示属性,所以不需要再有display:flex的设定
2、主轴默认方向的区别
在Web Flex中,主轴默认方向是水平的,而在RN是垂直的。
3、支持的属性和属性写法的区别
① RN支持的Flex属性有:

flex、flexDirection、flexWrap、justfyContent、alignItems、alignSelf

② 使用过RN的同行都应该知道在RN中属性的写法是驼峰法。即如对于用「-」作为单词连接符的属性,都需将其转换成驼峰法。如font-size需写成fontSize。(这里不再赘述)

React Native布局中的默认设定

了解RN的一些默认设定对于我们快速实现布局会有很大的帮助。

1、RN中的长度单位

Web中我们一般使用px或者%来定义元素的尺寸,而在RN中所有的尺寸属性都是不带单位的。那么它的默认单位是什么呢?
我们通过Dimensions这个Api来获取iphone6模拟器下的设备宽高:

console.log('width:'+Dimensions.get('window').width+',height:'+Dimensions.get('window').height);

得到如下图结果

来看看不同iphone下的一些尺寸数值

不难发现我们这里获得的宽高正与逻辑分辨率pt对应。所以,对于常规的设计图,pt和px的转换规律是pt=px/2。

2、取得屏幕大小和设备像素比

1) 屏幕大小 > const {devWidth,devHeight} = Dimensions.get('window');
2) dpr > PixelRatio.get()

3、RN中组件的默认占位大小和继承性

在Web布局中,一个块级元素的默认宽度是100%屏幕大小,高度为0。一个行内元素默认宽高都为0。由于RN中组件的默认显示方式为flex,所以此处猜测在RN中是没有行内元素和块级元素这一概念的。所有的组件都按flex布局进行默认尺寸的渲染。即子项目在主轴上依次排列,在侧轴上填满flex容器的可用空间。

做个实验:

① 默认主轴方向即垂直方向时
此处定义了两个Text,一个View组件。没有为父组件View设定flex:1

② 主轴方向为水平时
同样定义两个Text和一个View并且只为第一个Text设定了高度(侧轴方向尺寸)。同时为父组件View设定了flex:1

将父组件View的flex:1删去,加入一张按其默认尺寸大小渲染的图片

通过上述例子可以看出默认情况下(未对最外层View进行flex设定且主轴为默认方向)组件是宽度即为屏幕宽度,高度为自身的高度。当主轴为水平时,子组件在垂直方向填满父组件可用空间,若父组件可用空间尺寸未定义,则其自身高度尺寸进行渲染,如果未定义其自身高度,则每个子组件在垂直方向的尺寸都将拉伸至与高度值最大的那个子组件同等大小。

再通过两个Demo验证RN的继承性

① 定义父组件View在宽度为300

② 定义父组件View高度为200

对于View和Text这类包裹性组件来说,子组件的宽高值受到父组件的约束,也再次验证了flex布局的思想:子项目在主轴上依次排列,在侧轴上填满flex容器的可用空间。
但我在上面的测试中加入了一个Image组件。不难发现Image并不受到父组件View的约束。而是按其默认尺寸进行渲染,所以在引用图片时最好给其设定一个理想的宽高值,或者改变它的resizeMode属性。这个稍后还会提到。

React Native布局试例

1、RN flex属性

1)用在flex容器上的属性
① 子项目的排列方向(也就提到很多次的定义主轴):flexDirection: column(default) | row
② 子项目的换行方式(就是超出flex容器跨度时换不换行=。=怎么换):flexWrap: nowrap(default) | wrap
③ 子项目的对齐方式:
justifyContent: flex-start | flex-end | center | space-between | space-around(主轴)
alignItems: flex-start | flex-end | center | stretch(default)(侧轴)
上面属性的用法和效果都跟Web flex的基本一致,这里我就不进行演示了。

2)用在flex子项上的属性
单个子项在侧轴上的排列方式: alignItems: auto | flex-start | flex-end | center | stretch

2、图片布局方式

1) 默认尺寸
上面简单提到过,图片默认是不受到父组件的宽高束缚的。在Web中,如果我们定义了一个图片并不为它设定宽高,那么默认大小是0*0。带来的问题是在图片的加载渲染的过程中,很可能因图片的宽高变化给其周围元素造成布局跳动。
而RN避免了这种方式。在加载静态资源时,图片的尺寸可以加载时立即得到,并正确渲染到布局中。而加载动态资源时,很多要在App中显示的图片并不能在编译的时候获得,又或者有时候需要动态载入来减少打包后的二进制文件的大小。这些时候,与静态资源不同的是,你需要手动指定图片的尺寸。

2) 自适应的图片布局方式
很多时候,图片按照其实际尺寸渲染并不是我们想要的,比如对于某一些banner图,我们希望其宽度可以自适应容器的宽度,高度按比例进行缩放。
对于静态图片我们需要将宽高设定在图片上
对于动态图我们只需要指定其高度并调整resizeMode属性。(因为动态图默认是0*0大小..上述加载机制遗留问题)

3、文本布局

1) numberOfLines占位问题
一些博文上提到的就算设置了numberOfLines定义最多显示文本行数,隐藏的文本还是存在占位空间。目前这一问题已经修复,可以放心使用。

2) lineHeight的使用方式
在Web中,对于单行文本,为了使它在垂直方向上居中,我们一般会为它设定一个与高度相同的line-height值。那么在RN中呢?
实际上我们发现并不行。

为了实现这一效果,我们可用View将Text进行包裹,在View中设定其justifyContent属性(视实际情况定)

    文本

4、对于margin、padding的使用

同Web上的使用方式,inline元素margin垂直方向不可用,且不存在margin塌陷的情况。

5、绝对定位

RN中元素默认的定位方式是relative,并且只有「relative和absolute两种定位方式」。如果为组件加上position:absolute,它将会以inline的方式渲染在页面上。并且脱离正常文档流。也就是视觉上会被后面的组件覆盖,但不能通过zIndex方式调整。

终于写完了。。好累(:з」∠)

关键字:flex, 组件, 默认, view

版权声明

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部