样式
在React Native中,仍然是使用JavaScript
来写样式。所有的核心组件都接受名为style
的属性。这些样式名基本上是遵循了web
上的CSS
的命名,只是按照JS的语法要求使用了驼峰命名法,例如将background-color
改为backgroundColor
。style属性
可以是一个普通的JavaScript
对象。实际开发中组件的样式会越来越复杂,建议使用StyleSheet.create
来集中定义组件的样式。比如像下面这样:
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
export default class LotsOfStyles extends Component {
render() {
return (
<View>
<Text style={styles.red}>just red</Text>
<Text style={styles.bigblue}>just bigblue</Text>
<Text style={[styles.bigblue, styles.red]}>bigblue, then red</Text>
<Text style={[styles.red, styles.bigblue]}>red, then bigblue</Text>
</View>
);
}
}
const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
看一下效果图,值得注意的是这个地方
<Text style={[styles.bigblue, styles.red]}>bigblue, then red</Text>
<Text style={[styles.red, styles.bigblue]}>red, then bigblue</Text>
明显可以看出在数组中位置居后的样式对象比居前的优先级更高,即后声明的属性会覆盖先声明的同名属性
高度和宽度
指定宽高
最简单的给组件设定尺寸的方式就是在样式中指定固定的width
和height
。React Native中的尺寸都是无单位的,这样给组件设置尺寸的好处是可以在不同尺寸的屏幕上都显示成一样的大小。
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FixedDimensionsBasics extends Component {
render() {
return (
<View>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 100, height: 100, backgroundColor: 'skyblue'}} />
<View style={{width: 320, height: 150, backgroundColor: 'steelblue'}} />
</View>
);
}
};
弹性(Flex)宽高
上面那种方法,设置了具体的宽、高,那么在任何设备上都是同样的尺寸,不存在适配这么一说。考虑到不同机型的适配问题,使用比例布局的方法则不用担心尺寸的误差。
一般而言我们会使用flex:1
来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了flex:1
,则这些子组件会平分父容器中剩余的空间。如果这些并列的子组件的flex
值不一样,则按比例平分整个屏幕。默认是纵向平分,当然也可以设置成横向平分,在下面的使用Flexbox布局中会有介绍。
比如说我举个官方栗子
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FlexDimensionsBasics extends Component {
render() {
return (
// 试试去掉父View中的`flex: 1`。
// 则父View不再具有尺寸,因此子组件也无法再撑开。
// 然后再用`height: 300`来代替父View的`flex: 1`试试看?
<View style={{flex: 1}}>
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
</View>
);
}
};
子组件能够充满父容器剩余空间必须父容器的尺寸不为 0 ,如果父容器既没有指定width
、height
,同时也没有设定flex:1
,那么子组件将不会显示(即使子组件设置了flex)
。父组件默认设置flex:1(默认充满整个剩余空间)
使用Flexbox布局
我们在React Native中使用flexbox规则
来指定某个组件的子元素的布局。Flexbox
可以在不同屏幕尺寸上提供一致的布局结构。
一般来说,使用flexDirection
、alignItems
和 justifyContent
三个样式属性就已经能满足大多数布局需求。
React Native中的Flexbox
的工作原理和web
上的CSS
基本一致,当然也存在少许差异。首先是默认值不同:flexDirection
的默认值是column
而不是row
,而flex
也只能指定一个数字值。
Flex Direction
在组件的style
中指定flexDirection
可以决定布局的主轴。默认值是竖直轴(column)
方向。
比如说我们把上面例程改成这样(列)row
<View style={{flex: 1,flexDirection: 'row'}}>
<View style={{width: 50,backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
</View>
效果图就会有所变化
Justify Content
在组件的style
中指定justifyContent
可以决定其子元素沿着主轴的排列方式。对应的这些可选项有:flex-start
、center
、flex-end
、space-around
以及space-between
。为了便于理解这些排列方式的效果,我们可以全列出来先看一下,代码还可以再简化,暂时不管了
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FlexDimensionsBasics extends Component {
render() {
return (
<View style={{flex:1, flexDirection:'row'}}>
{/*1*/}
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'space-between',
}}>
<View style={{height: 50, backgroundColor: 'powderblue'}} />
<View style={{height: 50, backgroundColor: 'skyblue'}} />
<View style={{height: 50, backgroundColor: 'steelblue'}} />
</View>
{/*2*/}
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
}}>
<View style={{height: 50, backgroundColor: 'powderblue'}} />
<View style={{height: 50, backgroundColor: 'skyblue'}} />
<View style={{height: 50, backgroundColor: 'steelblue'}} />
</View>
{/*3*/}
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
}}>
<View style={{height: 50, backgroundColor: 'powderblue'}} />
<View style={{height: 50, backgroundColor: 'skyblue'}} />
<View style={{height: 50, backgroundColor: 'steelblue'}} />
</View>
{/*4*/}
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
}}>
<View style={{height: 50, backgroundColor: 'powderblue'}} />
<View style={{height: 50, backgroundColor: 'skyblue'}} />
<View style={{height: 50, backgroundColor: 'steelblue'}} />
</View>
{/*5*/}
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'space-around',
}}>
<View style={{height: 50, backgroundColor: 'powderblue'}} />
<View style={{height: 50, backgroundColor: 'skyblue'}} />
<View style={{height: 50, backgroundColor: 'steelblue'}} />
</View>
</View>
);
}
};
他们的效果分别如下
Align Items
在组件的style
中指定alignItems
可以决定其子元素沿着次轴(与主轴垂直的轴,比如若主轴方向为row,则次轴方向为column)
的排列方式。对应的这些可选项有:flex-start
、center
、flex-end
以及stretch
。
注意:要使stretch
选项生效的话,子元素在次轴方向上不能有固定的尺寸。以下面的代码为例:只有将子元素样式中的width: 50
去掉之后,alignItems: 'stretch'
才能生效。因为stretch
是平铺。此样式和CSS中的align-items
表现一致,默认值为 stretch
。
处理文本输入
TextInput
是一个允许用户输入文本的基础组件。它有一个名为onChangeText
的属性,此属性接受一个函数,而此函数会在文本变化时被调用。另外还有一个名为onSubmitEditing
的属性,会在文本被提交后(用户按下软键盘上的提交键)调用。TextInput
是一个允许用户在应用中通过键盘输入文本的基本组件。
目前从TextInput
里取值唯一的做法:在onChangeText
中用setState
把用户的输入写入到state中,然后在需要取值的地方从this.state
中取出值。
假如我们要实现当用户输入时,实时将其以单词为单位翻译为另一种文字。我们假设这另一种文字来自某个吃货星球,只有一个单词:🍕。所以"Hello there Bob"
将会被翻译为"🍕🍕🍕"。
import React, { Component } from 'react';
import { AppRegistry, Text, TextInput, View } from 'react-native';
export default class PizzaTranslator extends Component {
constructor(props) {
super(props);
//设置当前状态是text 初始值为空
this.state = {text: ''};
}
render() {
return (
<View style={{padding: 10}}>
<TextInput
style={{height: 40}}
//如果没有任何文字输入,会显示此字符串。
placeholder="在此输入文字"
onChangeText={(text) => this.setState({text})}
/>
<Text style={{padding: 10, fontSize: 42}}>
{this.state.text.split(' ').map((word) => word && '🍕').join(' ')}
</Text>
</View>
);
}
}
onChangeText={(text) => this.setState({text})}
当文本框内容变化时调用此回调函数。改变后的文字内容会作为参数传递。使用onChangeText
属性,这个属性的值是一个函数,setState()
方法会通知界面重新渲染,即只要有setState
就会走render
, 里面的参数代表的是构造函数中的state----text
{this.state.text.split(' ').map((word) => word && '🍕').join(' ')}
在JavaScript
中字符串的split()
方法返回的是一个数组,并且这个数组的长度不会为零(即便这个字符串的长度为零)
,数组的map()
方法相当于Java中的for循环
或foreach
,参数是一个函数,返回值类型还是一个数组。
=>
符号,代表一个函数,左边括号中代表的是函数的参数,右边代表的是这个函数的函数体返回的东西,join()
方法是数组的转字符串的一个方法,比如[1,2,3].join('0')
的结果就是字符串102030
上面出现了&&
符号,在这里并不是起到逻辑表达式的作用
a&&b 当a为真时 返回b
&&使用:
1:当做逻辑表达式
2:用于判空 然后得到后者
当下面两条语句同时存在时,如果text
值为空,则会显示提示文字,否则显示text
文字。
value = {this.state.text}
placeholder="在此输入文字"