React Native基础入门之初步使用Flexbox布局


Posted in Javascript onJuly 02, 2018

前言

在上篇中,笔者分享了部分安装并调试React Native应用过程里的一点经验,如果还没有看过的同学请点击《React Native基础&入门教程:调试React Native应用的一小步》。

在本篇里,让我们一起来了解一下,什么是Flexbox布局,以及如何使用。

一、长度的单位

在开始任何布局之前,让我们来首先需要知道,在写React Native组件样式时,长度的不带单位的,它表示“与设备像素密度无关的逻辑像素点”。

这个怎么理解呢?

我们知道,屏幕上一个发光的最小点,对应着一个pixel(像素)点。

假设下面三个矩形,代表三个屏幕大小一样的设备,但是,它们拥有的分辨率(resolution)不同:

React Native基础入门之初步使用Flexbox布局

图1.相同尺寸的设备 不同的分辨率

图上的每一个小格子,其实就代表了一个像素(pixel)。可以看到,一个像素点的大小,在这个三个物理尺寸一样但拥有不同分辨率的设备上,是不一样的。

如果我们以像素为单位来设置一个界面元素的大小,比如说2px的高度,那么这2px的长度上面的设备中就会是下面这个样子:

React Native基础入门之初步使用Flexbox布局

图2.不同分辨率下的2px实际高度

它们真实显示出的长度是不一样的。

我们想要一种长度单位,在同样物理尺寸大小的屏幕上(不论分辨率谁高谁低,只要物理尺寸大小一样即可),1个单位的长度所代表的物理尺寸是一样的。这种单位就应该是独立于分辨率的,把它起一个名字叫做 density-independent pixels,简称dp。这其实就是Android系统中所使用的长度单位。

举例来说,2dp宽,2dp高的内容,在不同分辨率但屏幕尺寸一样的设备上所显示出的物理大小是一样的。(一个题外话:有些Android开发者建议所有可点击的按钮,宽高都不应该少于48dp。)

React Native基础入门之初步使用Flexbox布局

图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>

显示如下:

React Native基础入门之初步使用Flexbox布局

图4. 当前手机的屏幕信息

它反映出,当前手机屏幕的宽度占据360个单位,高度占据640个单位。像素比例是3,实际上这就是一个 1080 * 1920 像素的手机。其中1080 = width * pixelRadio, 1920 = height * pixelRatio

二、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个属性设置在容器上。

  • alignItems 指定item在侧轴上的对齐方式
  • alignContent 指定item在多条轴上的对齐方式
  • flexDirection 指定主轴方向
  • flexWrap 指定item在主轴方向如何换行
  • flexFlow flexDirection属性和flexWrap属性的简写形式
  • justifyContent 指定item在主轴上的分布方式

2.Flex Item

容器做直接包裹的元素。所谓弹性盒布局,通常想要布局的东西就是它们。

以下6个属性设置在项目上。

  • alignSelf 每个item可以单独设置对齐方式 覆盖Flex Container给设置的alignItems
  • order 指定item排列顺序 数字越小越靠前
  • flexGrow 指定item的拉伸比例
  • flexShrink 指定item的压缩比例
  • flexBasis 指定item在分配多余空间之前,占主轴的大小
  • flex 其实是 flexGrow flexShrink flexBasis的简写

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'
},

React Native基础入门之初步使用Flexbox布局

图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'
}

React Native基础入门之初步使用Flexbox布局

图6. 默认的flex

justify-content设置items在主轴方向的如何分布,比如,如果我们加上justifyContent: 'space-between'

defaultFlex: {
height: 300,
backgroundColor: '#ffe289',
display: 'flex',
justifyContent: 'space-between'
}

items就沿主轴分开了。

React Native基础入门之初步使用Flexbox布局

图7. justifyContent: 'space-between'

如果我们设置alignItems: 'center',项目就沿侧轴(这里就是水平轴)居中了。注意这两个属性是可以同时起作用的。

React Native基础入门之初步使用Flexbox布局

图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',
},

React Native基础入门之初步使用Flexbox布局

图9. 按比例分布

需要注意的是,如果父容器的尺寸为零(即没有设置宽高,或者没有设定flex),即使子组件如果使用了flex,也是无法显示的。

所以这里最外层的使用了flex布局的,flex:1,表示让它占据了垂直的整个空间。

三、小小实战演练

让我们来简单使用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',
}

React Native基础入门之初步使用Flexbox布局

图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'
}

React Native基础入门之初步使用Flexbox布局

图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'
},

React Native基础入门之初步使用Flexbox布局

图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
}

React Native基础入门之初步使用Flexbox布局

flex布局的一个常用实践是,部分内容固定宽高,让剩下的内容自适应。

像上面这样,我们给Button有一个最小宽度,且TextInput的flexGrow为1,这样的做法可以实现,TextInput总是占满剩下的宽度,且可伸缩。

看了上面的例子,是否觉得在React Native中使用Flexbox布局也挺简单呢?

希望这是个不错的开始。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
js parseInt(&quot;08&quot;)未指定进位制问题
Jun 19 Javascript
JQuery弹出炫丽对话框的同时让背景变灰色
May 22 Javascript
跟我学习javascript的浮点数精度
Nov 16 Javascript
原生javascript实现自动更新的时间日期
Feb 12 Javascript
jQuery简单实现上下,左右滑动的方法
Jun 01 Javascript
Angular JS数据的双向绑定详解及实例
Dec 31 Javascript
基于vue2.0+vuex+localStorage开发的本地记事本示例
Feb 28 Javascript
前端自动化开发之Node.js的环境搭建教程
Apr 01 Javascript
React 子组件向父组件传值的方法
Jul 24 Javascript
Webpack之tree-starking 解析
Sep 11 Javascript
Javascript异步执行不按顺序解决方案
Apr 30 Javascript
react使用CSS实现react动画功能示例
May 18 Javascript
JavaScript设计模式之构造函数模式实例教程
Jul 02 #Javascript
vue-router 源码实现前端路由的两种方式
Jul 02 #Javascript
React Native基础入门之调试React Native应用的一小步
Jul 02 #Javascript
vue-router 源码之实现一个简单的 vue-router
Jul 02 #Javascript
JavaScript设计模式之单例模式简单实例教程
Jul 02 #Javascript
JavaScript设计模式之建造者模式实例教程
Jul 02 #Javascript
JS实现的JSON序列化操作简单示例
Jul 02 #Javascript
You might like
PHP header函数分析详解
2011/08/06 PHP
浅析php中jsonp的跨域实例
2013/06/21 PHP
php微信公众开发之获取周边酒店信息的方法
2014/12/22 PHP
PHP获取客户端及服务器端IP的封装类
2016/07/21 PHP
php getcwd与dirname(__FILE__)区别详解
2016/09/24 PHP
php使用自定义函数实现汉字分割替换功能示例
2017/01/30 PHP
PHP实现数据库的增删查改功能及完整代码
2018/04/18 PHP
jQuery 页面 Mask实现代码
2010/01/09 Javascript
JQuery中的ready函数冲突的解决方法
2010/05/17 Javascript
artDialog双击会关闭对话框的修改过程分享
2013/08/05 Javascript
JS实现鼠标单击与双击事件共存
2014/03/08 Javascript
JavaScript检测弹出窗口是否已经关闭的方法
2015/03/24 Javascript
jQuery实现简单的文件上传进度条效果
2020/03/26 Javascript
JavaScript获取对象在页面中位置坐标的方法
2016/02/03 Javascript
angular使用post、get向后台传参的问题实例
2017/05/27 Javascript
关于JavaScript的单双引号嵌套问题
2017/08/20 Javascript
JS+Canvas绘制动态时钟效果
2017/11/10 Javascript
js判断输入框不能为空格或null值的实现方法
2018/03/02 Javascript
vue填坑之webpack run build 静态资源找不到的解决方法
2018/09/03 Javascript
可能被忽略的一些JavaScript数组方法细节
2019/02/28 Javascript
python 利用pyttsx3文字转语音过程详解
2019/09/25 Python
Python实现Kerberos用户的增删改查操作
2020/12/14 Python
SheIn俄罗斯:时尚女装网上商店
2017/02/28 全球购物
印度尼西亚电子产品购物网站:Kliknklik
2018/06/05 全球购物
匡威俄罗斯官网:Converse俄罗斯
2020/05/09 全球购物
Ibatis中如何提高SQL Map的性能
2013/05/11 面试题
const和static readonly区别
2013/05/20 面试题
大学生简历中个人的自我评价
2013/10/06 职场文书
科室工作的个人自我评价
2013/10/30 职场文书
初一科学教学反思
2014/01/27 职场文书
医德医风自我评价2015
2015/03/03 职场文书
通用员工手册范本
2015/05/14 职场文书
看上去很美观后感
2015/06/10 职场文书
2016大学生形势与政策心得体会
2016/01/12 职场文书
2016年妇联“6﹒26国际禁毒日”宣传活动总结
2016/04/05 职场文书
SQL Server中交叉联接的用法详解
2021/04/22 SQL Server