首頁  >  文章  >  web前端  >  React Native使用Flexbox佈局的介紹

React Native使用Flexbox佈局的介紹

不言
不言原創
2018-07-03 17:58:161632瀏覽

React中引入了flexbox概念,flexbox是屬於web前端領域CSS的一種佈局方案,以下這篇文章主要給大家介紹了關於React Native基礎入門之初步使用Flexbox佈局的相關資料,文中透過範例程式碼介紹的非常詳細,需要的朋友可以參考下

#前言

在上篇中,筆者分享了部分安裝並調試React Native應用過程裡的一點經驗,如果還沒看過的同學請點擊《React Native基礎&入門教學:調試React Native應用的一小步》。

在本篇裡,讓我們一起來了解一下,什麼是Flexbox佈局,以及如何使用。

一、長度的單位

在開始任何佈局之前,讓我們來首先需要知道,在寫React Native元件樣式時,長度的不含單位的,它表示「與設備像素密度無關的邏輯像素點」。

這個怎麼理解呢?

我們知道,螢幕上一個發光的最小點,對應著一個pixel(像素)點。

假設下面三個矩形,代表三個螢幕大小一樣的設備,但是,它們擁有的解析度(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

二、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: &#39;#ffe289&#39;,
flexDirection: &#39;row&#39;
},
rowReverse: {
flexDirection: &#39;row-reverse&#39;
},
column: {
backgroundColor: &#39;#ffe289&#39;,
flexDirection: &#39;column&#39;
},
columnReverse: {
flexDirection: &#39;column-reverse&#39;
},

图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: &#39;#ffe289&#39;,
display: &#39;flex&#39;
}

图6. 默认的flex

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

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

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: &#39;orange&#39;,
},
flex2: {
flexGrow: 2,
backgroundColor: &#39;lightblue&#39;,
},
flex3: {
flexGrow: 3,
backgroundColor: &#39;green&#39;,
},

图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: &#39;orange&#39;,
},
body: {
flexGrow: 1,
backgroundColor: &#39;lightblue&#39;,
},
footer: {
height: 60,
backgroundColor: &#39;green&#39;,
}

图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: &#39;orange&#39;,
flexDirection: &#39;row&#39;,
alignItems: &#39;center&#39;
},
back: {
color: &#39;white&#39;,
marginLeft: 15
},
title: {
flexGrow: 1,
fontSize: 20,
color: &#39;white&#39;,
textAlign: &#39;center&#39;
},
exit: {
marginRight: 20,
fontSize: 20,
color: &#39;white&#39;
}

图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: &#39;green&#39;,
flexDirection: &#39;row&#39;,
alignItems: &#39;center&#39;
},
menu: {
flexGrow: 1,
textAlign: &#39;center&#39;,
borderColor: &#39;white&#39;,
borderLeftWidth: 1,
color: &#39;white&#39;
},
firstMenu: {
flexGrow: 1,
textAlign: &#39;center&#39;,
color: &#39;white&#39;
},

图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: &#39;lightblue&#39;,
},
inputRow: {
flexDirection: &#39;row&#39;,
alignItems: &#39;center&#39;,
marginLeft: 10,
marginRight: 10
},
textInput: {
flex: 1
},
btn: {
minWidth: 60
}

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

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

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

希望这是个不错的开始。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

基于React和Redux的SSR的实现方法

echarts同一页面中四个图表切换的js数据交互方法

以上是React Native使用Flexbox佈局的介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn