在上篇中,笔者分享了部分安装并调试React Native应用过程里的一点经验,若是尚未看过的同窗请点击《React Native基础&入门教程:调试React Native应用的一小步》。php
在本篇里,让咱们一块儿来了解一下,什么是Flexbox布局,以及如何使用。html
1、长度的单位前端
在开始任何布局以前,让咱们来首先须要知道,在写React Native组件样式时,长度的不带单位的,它表示“与设备像素密度无关的逻辑像素点”。react
这个怎么理解呢?web
咱们知道,屏幕上一个发光的最小点,对应着一个pixel(像素)点。react-native
假设下面三个矩形,表明三个屏幕大小同样的设备,可是,它们拥有的分辨率(resolution)不一样:浏览器
图1.相同尺寸的设备 不一样的分辨率框架
图上的每个小格子,其实就表明了一个像素(pixel)。能够看到,一个像素点的大小,在这个三个物理尺寸同样但拥有不一样分辨率的设备上,是不同的。布局
若是咱们以像素为单位来设置一个界面元素的大小,好比说2px的高度,那么这2px的长度上面的设备中就会是下面这个样子:学习
图2.不一样分辨率下的2px实际高度
它们真实显示出的长度是不同的。
咱们想要一种长度单位,在一样物理尺寸大小的屏幕上(不论分辨率谁高谁低,只要物理尺寸大小同样便可),1个单位的长度所表明的物理尺寸是同样的。这种单位就应该是独立于分辨率的,把它起一个名字叫作 density-independent pixels,简称dp。这其实就是Android系统中所使用的长度单位。
举例来讲,2dp宽,2dp高的内容,在不一样分辨率但屏幕尺寸同样的设备上所显示出的物理大小是同样的。(一个题外话:有些Android开发者建议全部可点击的按钮,宽高都不该该少于48dp。)
图3. 2dp * 2dp大小的内容 在一样尺寸的屏幕中所占据的物理大小一致
Android中字体大小使用另一个单位,叫作scale independent pixels,简称sp。这个单位和dp很相似,不过它一般是用在对字体大小的设置中。经过它设置的字体,能够根据系统字体大小的变化而变化。
pixel与dp存在一个公式:px = dp * (dpi/160)。
dpi表示dot per inch,是每英寸上的像素点,它也有个本身的计算公式,具体这里就不展开了。只须要知道咱们之因此要使用一个独立于设备分辨率的单位,主要是为了让应用在不一样分辨率的设备中,看起来一致。
在RN中,一样也拥有一个相似于dp的长度单位。若是咱们想知道本身的屏幕以这种长度的计量下是多少单位,能够经过引入react-native包中的Dimensions拿到,同时还能够查看本机的像素比例是多少。
import { Text, View, Dimensions, PixelRatio } from 'react-native'; const { height, width } = Dimensions.get('window'); const pxRatio = PixelRatio.get();
<View style={styles.container}> <Text style={styles.welcome}> {`width: ${width}, height: ${height}`} </Text> <Text style={styles.welcome}> {`pixel radio: ${pxRatio}`} </Text> </View>
显示以下:
图4. 当前手机的屏幕信息
它反映出,当前手机屏幕的宽度占据360个单位,高度占据640个单位。像素比例是3,实际上这就是一个 1080 * 1920 像素的手机。其中1080 = width * pixelRadio, 1920 = height * pixelRatio
2、Flexbox布局
Flexbox布局,也就是弹性盒模型布局。也许有Android开发经验的朋友还对LinearLayout,RelativeLayout,FrameLayout等布局方法记忆犹新,可是对于更了解CSS的Web开发者而言,使用flexbox布局确定会让他感觉到更加顺手的开发体验。
RN中的flexbox布局,其实源于CSS中的flexbox(弹性盒子)布局规范。其实它在CSS中还处于Last Call Working Draft(最终征求意见稿)阶段,可是主流浏览器对它都有了良好的支持。在RN中,几乎彻底借鉴了其中的布局语义,同时更没有浏览器兼容的烦恼,用起来是很方便的。RN中只是把CSS的属性用camelCase写法代替连字符写法。后面还还会看到,默认的flex方向也不一样。
理解弹性盒模型布局,首先要知道四个最基本的概念:Flex Container(容器),Flex Item(项),Flex Direction(方向)和Axis(轴)。
1.Flex Container
就是包裹内容的容器,须要把它的display设置为‘flex’(或者'inline-flex')。
如下6个属性设置在容器上。
2.Flex Item
容器作直接包裹的元素。所谓弹性盒布局,一般想要布局的东西就是它们。
如下6个属性设置在项目上。
3.Flex Direction and Axis
在弹性盒子中,项目默认沿着main axis(主轴)排列,和主轴垂直的轴叫作cross axis,叫作侧轴,或者交叉轴。
在盒子中,排列项目又四个方向:水平的正反两个,垂直的正反两个。
结构代码:
<View> <View style={styles.row}> <Text style={styles.item}>1</Text> <Text style={styles.item}>2</Text> <Text style={styles.item}>3</Text> </View> <View style={styles.rowReverse}> <Text style={styles.item}>1</Text> <Text style={styles.item}>2</Text> <Text style={styles.item}>3</Text> </View> <View style={styles.column}> <Text style={styles.item}>1</Text> <Text style={styles.item}>2</Text> <Text style={styles.item}>3</Text> </View> <View style={styles.columnReverse}> <Text style={styles.item}>1</Text> <Text style={styles.item}>2</Text> <Text style={styles.item}>3</Text> </View> </View>
样式代码:
row: { backgroundColor: '#ffe289', flexDirection: 'row' }, rowReverse: { flexDirection: 'row-reverse' }, column: { backgroundColor: '#ffe289', flexDirection: 'column' }, columnReverse: { flexDirection: 'column-reverse' },
图5. flexDirection
因为网上关于flex布局讲解的资源挺丰富的,读者能够参考最后给出的链接,或者自行上网搜索,CSS中的和RN是相通的。
这里主要分享我的在学习过程当中,以为容易引发混淆的两个小点。
首先,justify-content和align-content这两个属性,可能比较容易搞错它们做用的方向。
其中,justify-content是设置items沿着主轴上是如何分布的。align-content是设置items沿着侧轴如何对齐的。
仍是拿以前的例子,默认状况下,flex的方向是column(这个与移动端与web页面不一样,在web页面用CSS设置flex布局,默认的fiex-direction是row,即水平从左往右)。
在移动端,主轴默认是垂直方向,从上往下。让咱们把它的高度设置高一点,放3个item在里面:
结构代码:
<View> <View style={styles.defaultFlex}> <Text style={styles.item}>1</Text> <Text style={styles.item}>2</Text> <Text style={styles.item}>3</Text> </View> </View>
样式代码:
defaultFlex: { height: 300, backgroundColor: '#ffe289', display: 'flex' }
图6. 默认的flex
justify-content设置items在主轴方向的如何分布,好比,若是咱们加上justifyContent: 'space-between'
defaultFlex: { height: 300, backgroundColor: '#ffe289', display: 'flex', justifyContent: 'space-between' }
items就沿主轴分开了。
图7. justifyContent: 'space-between'
若是咱们设置alignItems: 'center',项目就沿侧轴(这里就是水平轴)居中了。注意这两个属性是能够同时起做用的。
图8. justifyContent: 'space-between' 以及 alignItems: 'center'
而后,值得指出的是,flex这个属性,实际上是flexGrow, flexShrink, flexBasis(对应的CSS属性flex-grow, flex-shrink和flex-basis)三个属性的结合。
咱们一般在移动端看到的flex:1这个设置,实际上是对flex-grow的设置。后者的默认值为0。使用把flex-grow设置为正整数的方法,可让item按比例分布,或者在其余item为固定大小时撑满剩余的盒子空间,就仿佛具备弹性同样。
结构代码:
<View style={styles.container}> <View style={styles.flex1}></View> <View style={styles.flex2}></View> <View style={styles.flex3}></View> </View>
样式代码:
container: { flex: 1 }, flex1: { // height: 99, flexGrow: 1, backgroundColor: 'orange', }, flex2: { flexGrow: 2, backgroundColor: 'lightblue', }, flex3: { flexGrow: 3, backgroundColor: 'green', },
图9. 按比例分布
须要注意的是,若是父容器的尺寸为零(即没有设置宽高,或者没有设定flex),即便子组件若是使用了flex,也是没法显示的。
因此这里最外层的使用了flex布局的,flex:1,表示让它占据了垂直的整个空间。
3、小小实战演练
让咱们来简单使用flex布局,对以前的例子稍加调整,实现一个头部,底部固定高度,中间内容占满剩下的屏幕的布局:
第一步,调整结构:
<View style={styles.container}> <View style={styles.header}></View> <View style={styles.body}></View> <View style={styles.footer}></View> </View>
调整样式:
container: { flex: 1 }, header: { height: 60, backgroundColor: 'orange', }, body: { flexGrow: 1, backgroundColor: 'lightblue', }, footer: { height: 60, backgroundColor: 'green', }
图10. 有头尾的布局
第二部,给header添加标题。
咱们让头部的分红3部分,左边模拟一个返回按钮,中间显示标题文字,右边模拟一把小叉:
<View style={styles.header}> <Text style={styles.back}>返回</Text> <Text style={styles.title}>这是一个标题</Text> <Text style={styles.exit}>×</Text> </View>
须要把header的flexDirection设置为水平方向:
header: { height: 60, backgroundColor: 'orange', flexDirection: 'row', alignItems: 'center' }, back: { color: 'white', marginLeft: 15 }, title: { flexGrow: 1, fontSize: 20, color: 'white', textAlign: 'center' }, exit: { marginRight: 20, fontSize: 20, color: 'white' }
图11. header有了标题
第三步,咱们能够把footer三等分,模拟成菜单的样子:
<View style={styles.footer}> <Text style={styles.firstMenu}>添加</Text> <Text style={styles.menu}>删除</Text> <Text style={styles.menu}>修改</Text> </View>
添加样式:
footer: { height: 60, backgroundColor: 'green', flexDirection: 'row', alignItems: 'center' }, menu: { flexGrow: 1, textAlign: 'center', borderColor: 'white', borderLeftWidth: 1, color: 'white' }, firstMenu: { flexGrow: 1, textAlign: 'center', color: 'white' },
图12. footer三等分 模拟菜单
最后,让咱们在body里也填入几个带按钮的输入框。
引入TextInput和Button组件,而后把它们分三组放入body中,
<View style={styles.body}> <View style={styles.inputRow}> <TextInput style={styles.textInput}></TextInput> <Button style={styles.btn} onPress={() => {}} title="肯定"></Button> </View> <View style={styles.inputRow}> <TextInput style={styles.textInput}></TextInput> <Button style={styles.btn} onPress={() => {}} title="很是肯定"></Button> </View> <View style={styles.inputRow}> <TextInput style={styles.textInput}></TextInput> <Button style={styles.btn} onPress={() => {}} title="肯定必定以及确定"></Button> </View> </View>
添加样式:
body: { flexGrow: 1, backgroundColor: 'lightblue', }, inputRow: { flexDirection: 'row', alignItems: 'center', marginLeft: 10, marginRight: 10 }, textInput: { flex: 1 }, btn: { minWidth: 60 }
flex布局的一个经常使用实践是,部份内容固定宽高,让剩下的内容自适应。
像上面这样,咱们给Button有一个最小宽度,且TextInput的flexGrow为1,这样的作法能够实现,TextInput老是占满剩下的宽度,且可伸缩。
看了上面的例子,是否以为在React Native中使用Flexbox布局也挺简单呢?
但愿这是个不错的开始。
移动端应用开发利器:
SpreadJS纯前端表格控件、WijmoJS纯前端控件集为您的移动应用带来更加灵活的操做体验和更佳美观的外观风格,欢迎下载。
扩展阅读: