React Native 布局浅探

简述

在Web开发中,页面布局基于盒子模型,主要经过定位属性、浮动属性和显示属性实现。而React Native采用的是Flex布局,但也支持盒子模型的margin、padding以及定位属性进行布局。html

flex布局定义

以一张图片来大体了解flex布局的思想
clipboard.pngreact

flex布局实例

对于flex各类布局方式的实现能够参见这篇文章 移动端全兼容的flexbox速成班 这是移动端web flex布局,能够套用思路,只须要将属性改为RN的形式就能够了。web

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

RN中的flex布局

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的基本一致,这里再也不进行演示。iphone

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

Web flex和RN flex几点区别:

1)由于RN里的全部组件都是以flex做为其显示属性,因此不须要再有display:flex的设定
2)主轴默认方向的区别
在Web Flex中,主轴默认方向是水平的,而在RN是垂直的。
3)支持的属性和属性写法的区别ide

布局中一些注意点

1)文本必须写在Text中而非View
2)View最好不要嵌套在Text中布局

RN中的长度单位

默认单位

在RN中全部的尺寸属性都是不带单位的。官网给出的默认单位是dp。
咱们经过Dimensions这个Api来获取iphone6模拟器下的设备宽高:flex

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

获得以下图结果
clipboard.pngui

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

clipboard.png

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

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

1) 屏幕大小

const {devWidth,devHeight} = Dimensions.get('window');

2) dpr

PixelRatio.get()

RN中组件占位问题

组件默认占位大小

在Web布局中,区块以div包裹,文本以span包裹。默认状况下div的宽度为100%屏幕宽度,高为0。span宽高均为0。那么RN中与其用途类似的View和Text组件默认宽高是怎么定义的呢?

作个实验:
1)主轴方向垂直
① Text不做为包裹容器时

<View style={{paddingTop: 18,}}>
        <Text style={styles.bgcolor_1}>A testing text</Text>
        <Text style={[styles.bgcolor_2,{width: 200,}]}>A testing text with width was setted</Text>
        <View style={styles.bgcolor_3}></View>
      </View>

clipboard.png

② Text做为包裹容器时

<View style={{paddingTop: 18,}}>
    <Text>
      <Text style={styles.bgcolor_1}>A testing text</Text>
      <Text style={[styles.bgcolor_2,{width: 200,}]}>A testing text with width was setted</Text>
    </Text>
    //...代码同上
  </View>

clipboard.png

2)主轴方向水平

<View style={{paddingTop: 18,flexDirection: 'row'}}>
        //...代码同上
      </View>

① Text不做为包裹容器时

clipboard.png

② Text做为包裹容器时

clipboard.png

结论:
由上实验可得,若Text无嵌套,它的显示方式同View相似。默认状况下,组件是宽度即为屏幕宽度,高度为自身高度(无内容填充则为0)。若Text中嵌套Text,那么子组件Text的显示方式如同Web中的span。

参考官方文档的定义

<Text>元素在布局上不一样于其它组件:在Text内部的元素再也不使用flexbox布局,而是采用文本布局。这意味着<Text>内部的元素再也不是一个个矩形,而可能会在行末进行折叠。

文本布局一些属性的占位

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

<Text numberOfLines={5} style={styles.textWrapper} >
          <Text style={{fontSize: 20}}>Title</Text>{'\n'}
          <Text>In this example, the nested title and body text will inherit the fontFamily from styles.baseText, but the title provides its own additional styles. The title and body will stack on top of each other on account of the literal newlines, numberOfLines is Used to truncate the text with an elipsis after computing the text layout, including line wrapping, such that the total number of lines does not exceed this number.</Text>
        </Text>

clipboard.png

2) lineHeight的使用方式
在web中为实现文本垂直居中效果咱们会设定与高度值一样的lineHeight。
但因为在Text嵌套时,Text组件的显示方式与span相似。即不支持宽高定义。而且即便设定了lineHeight也没法改变文本的垂直对齐方式。(verticalAlign)

<Text numberOfLines={5} style={styles.textWrapper} >
          <Text style={{fontSize: 20,lineHeight: 50,backgroundColor: 'aliceblue'}}>Title</Text>{'\n'}
          <Text>In this example, the nested title and body text will inherit the fontFamily from styles.baseText, but the title provides its own additional styles. The title and body will stack on top of each other on account of the literal newlines, numberOfLines is Used to truncate the text with an elipsis after computing the text layout, including line wrapping, such that the total number of lines does not exceed this number.</Text>
        </Text>

clipboard.png

咱们看到另外一诡异的问题是它的兄弟Text也被设定了一样的lineHeight值。
因此,开发中为了实现这一效果,咱们可用View将Text进行包裹,在View中设定其justifyContent属性(视实际状况定)

<View style={{height: 50,justifyContent: 'center',backgroundColor: 'aliceblue'}}>
        <Text style={{fontSize: 20}}>Title</Text>
      </View>

clipboard.png

图片布局

1) 默认尺寸

加载静态资源时,图片的尺寸能够加载时当即获得,并正确渲染到布局中。
加载动态资源时,不少要在App中显示的图片并不能在编译的时候得到,这时的图片的默认尺寸为0*0

咱们知道Flex布局中,子组件的宽高值受到父组件的约束。
而因为在加载静态图时会当即将图片原尺寸赋予Image组件,所以即便不设定宽高,它也不受到父组件尺寸的约束。

<View style={{paddingTop: 18}}>
        <Text style={{paddingTop: 5,paddingBottom: 5,backgroundColor: '#a5e0da'}}>React Native</Text>
        <View style={{height: 200}}>
          <Image source={require('./image/react.png')} />
        </View>
      </View>

clipboard.png

加载动态资源时

clipboard.png

所以不管是静态仍是动态图,最好都给它设定一个宽高值。对于动态图,若只设定其中一个值,还能够经过resizeMode来进行调整。
resizeMode提供了三个值

看一段代码,分别修改Image的resizeMode属性

<View>
          <Image style={{height: 100}} resizeMode={'cover'} source={{uri:"http://static.open-open.com/lib/uploadImg/20160412/20160412193341_428.png"}} />
        </View>

cover: 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸(若是容器有padding内衬的话,则相应减去)。译注:这样图片彻底覆盖甚至超出容器,容器中不留任何空白。

clipboard.png

contain: 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸(若是容器有padding内衬的话,则相应减去)。译注:这样图片彻底被包裹在容器中,容器中可能留有空白

clipboard.png

stretch: 拉伸图片且不维持宽高比,直到宽高都恰好填满容器。

clipboard.png

RN中的盒模型布局

对于margin、padding的使用

同Web上的使用方式,但不存在margin塌陷的状况。嵌套的Text不能设置垂直方向上的margin。

绝对定位

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

clipboard.png

相关文章
相关标签/搜索