React Native
React Native 看起來很像 React,只不過其基礎組件是原生組件而非 web 組件。要理解 React Native 應用的基本結構,首先需要了解一些基本的 React 的概念,比如 JSX 語法、組件、state狀態以及props屬性。如果你已經瞭解了 React,那麼還需要掌握一些 React Native 特有的知識,比如原生組件的使用。這篇教程可以供任何基礎的讀者學習,不管你是否有 React 方面的經驗。
TextInput
通過 value 屬性指定文本內容, 通過 onChangeText 屬性監聽文本的變化事件
從TextInput談綁定this傳參數
我們在使用TextInput發現每次輸入完後;輸入的都無效;這是因爲要改變沒有更改數據源
- 使用箭頭函數實現;這樣不會改變this的指向
import React from 'react';
import { View, TextInput, StyleSheet } from 'react-native';
export default class ElseStudy extends React.Component{
constructor(props){
super(props)
this.state = {myText:'Useless Placeholder'}
}
render(){
return (
<View>
<TextInput
value={this.state.myText}
onChangeText={(text)=>this.changeTextHandle(text)}
></TextInput>
</View>
)
}
changeTextHandle(newText){
this.setState({
myText:newText
})
}
}
- 當然代碼少,我們可以不用聲明一個函數,直接寫在
{}
return (
<View>
<TextInput
value={this.state.myText}
onChangeText={(myText)=>this.setState({myText})}
></TextInput>
</View>
)
- 使用bind改變this的指向
render(){
return (
<View>
<TextInput
value={this.state.myText}
onChangeText={this.changeTextHandle.bind(this)}
></TextInput>
</View>
)
}
changeTextHandle(newText){
this.setState({
myText:newText
})
}
ScrollView
- 默認情況下, 超出屏幕的內容是看不到的, 不像瀏覽器環境下會自動添加滾動條
- 如果需要滾動, 可以使用這個組件把要相應的內容包裹起來, 被包裹的內容就會處於滾動條中
- 滾動的過程中,可以通過onScroll綁定回調,每幀最多調用一次回調
import React from 'react';
import { StyleSheet, Text, View,ScrollView } from 'react-native';
export default class ScrollViewStudy extends React.Component{
constructor(props) {
super(props);
this.state = {
list: ["red", "yellow", "pink", "orange", "blue", "skyblue"]
}
}
render(){
return (
<View>
{
this.state.list.map(color => (
<View
key={color}
style={{backgroundColor: color, width: 300, height: 180}}>
<Text>{color}</Text>
</View>
))
}
</View>
)
}
}
我們使用View包裹着每個View組件;發現手機只顯示中間部分的組件;並不能滾動;我們可以使用scrollView進行包裹
<ScrollView>
{
this.state.list.map(color => (
<View
key={color}
style={{backgroundColor: color, width: '100%', height: 180}}>
<Text>{color}</Text>
</View>
))
}
</ScrollView>
ScrollView實現輪播
import React from 'react'
import { StyleSheet, View,ScrollView,Text } from 'react-native';
const Dimensions = require('Dimensions');
const screenSize = Dimensions.get("window");
export default class Lunbotu extends React.Component{
constructor(props){
super(props)
this.state = {
list: ["red", "yellow", "pink", "orange"]
}
}
getList(){
return this.state.list.map((color,i) => (
<View
key={i}
style={[styles.swipeItem, {backgroundColor: color}]}
>
<Text>i</Text>
</View>
))
}
render(){
return (
<ScrollView
horizontal={ true }
pagingEnabled={ true }
showsHorizontalScrollIndicator={ false }
>
{this.getList()}
</ScrollView>
)
}
}
const styles = StyleSheet.create({
swipeItem:{
width: screenSize.width,
height: 200
}
})
- Dimensions可以動態獲取屏幕的寬高,用這個寬高我們可以根據需求自己計算。使用它的時候,主要是因爲我們不能確定父盒子的寬高與屏幕的關係
- horizontal屬性可設置列表水平排列,pagingEnabled屬性能夠讓列表一頁一頁切換,showsHorizontalScrollIndicator屬性控制滾動條顯示隱藏
- 其實我們只是讓每一個子元素(輪播容器swiper-item)水平排列,請求去掉滾動條;然後在滑動一下顯示一頁即可
FastList
高性能的簡單列表組件
使用方法
import React, { Component } from "react";
import { StyleSheet, View, Text, FlatList } from 'react-native';
export default class FlatListTest extends Component {
render() {
return (
<View>
<FlatList
data={[
{key: 'Devin'},
{key: 'Jackson'},
{key: 'James'},
{key: 'Joel'},
{key: 'John'},
{key: 'Jillian'},
{key: 'Jimmy'},
{key: 'Julie'}
]}
renderItem={(e) => <Text style={styles.item}>{e.index + ":" + e.item.key}</Text>}
/>
</View>
);
}
}
const styles = StyleSheet.create({
item: {
padding: 10,
fontSize: 18,
height: 44,
},
});
ActivityIndicator
- 展示一個小圓形的loading
- 通過屬性 animating 控制顯示隱藏, color 設置顏色
- 我們可以用它來做數據的加載等等…
import React, { Component } from "react";
import { StyleSheet, View, Text, ActivityIndicator } from 'react-native';
export default class FlatListTest extends Component {
render(){
return (
<ActivityIndicator
animating={true}
color="green"
size="large" />
)
}
}
觸控系列組件
在需要捕捉用戶點擊操作時,可以使用Touchable開頭的一系列組件。這些組件通過onPress屬性設置點擊事件的處理函數。當在本組件上按下手指並且擡起手指時也沒有移開到組件外時,此函數會被調用。Touchable組件最大的特點是附帶反饋效果。
import React from 'react'
import {
StyleSheet,
View,
Image,
Text,
TouchableHighlight,
TouchableOpacity,
TouchableNativeFeedback
} from 'react-native';
export default class TouchableStudy extends React.Component{
render(){
return (
<View>
<TouchableOpacity
activeOpacity={0.5}
>
<Text style={styles.baseFont}>透明按鈕</Text>
</TouchableOpacity>
<TouchableHighlight
underlayColor="#fal33j"
activeOpacity={0.5}>
<Text style={styles.baseFont}>高亮按鈕</Text>
</TouchableHighlight>
<TouchableNativeFeedback
background={TouchableNativeFeedback.SelectableBackground()}
>
<View style={styles.base}>
<Text style={styles.baseFont}>原生按鈕</Text>
</View>
</TouchableNativeFeedback>
</View>
)
}
}
const styles = StyleSheet.create({
base: {
margin: 10,
width: 300,
height: 100,
borderRadius: 5,
backgroundColor: 'green',
justifyContent: 'center',
},
baseFont: {
color: "orange",
textAlign: "center",
lineHeight: 50
}
})
使用原生狀態渲染反饋效果,比如漣漪,只能放置一個view子組件;效果有三個可選方法:SelectableBackground、SelectableBackgroundBorderless、Ripple(color)
Alter
import React from 'react'
import {
Alert,
Button,
} from 'react-native';
export default class AlertStudy extends React.Component{
alertHandle(){
Alert.alert(
'Alert Title',
'My Alert Msg',
[
{text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{ cancelable: false }
)
}
render(){
return(
<Button title="點我彈框" onPress={()=>this.alertHandle()}></Button>
)
}
}
看界面一下子就能知道它的各個含義: 配置一個按鈕是確定,兩個按鈕是取消與確定,三個按鈕是稍後再試、取消與確定
Dimensions
const Dimensions = require('Dimensions');
const screenSize = Dimensions.get("window");
const styles = StyleSheet.create({
container: {
width: screenSize.width,
height: screenSize.height
}
});
本模塊用於獲取設備屏幕的寬高。儘管尺寸信息立即就可用,但它可能會在將來被修改(譬如設備的方向改變),所以基於這些常量的渲染邏輯和樣式應當每次render之後都調用此函數,而不是將對應的值保存下來。
Picker
本組件可以在iOS和Android上渲染原生的選擇器(Picker)
import React from 'react'
import {View,Text,StyleSheet,Picker} from 'react-native'
export default class Products extends React.Component{
constructor(props) {
super(props);
this.state = {
language:'react',
pickerOptions:[
{
id:1,
value:'vue'
},
{
id:2,
value:'react'
},
{
id:3,
value:'angular'
}
]
}
}
render(){
return (
<View style={styles.container}>
<Text>個人信息頁面</Text>
<Picker
selectedValue={this.state.language}
style={{ height: 50, width: 200,backgroundColor:'hotpink',marginVertical:20 }}
onValueChange={(itemValue, itemIndex) => this.setState({language: itemValue})}>
{
this.state.pickerOptions.map((item)=>{
return <Picker.Item label={item.value} value={item.value} key={item.id} />
})
}
</Picker>
</View>
)
}
}
const styles = StyleSheet.create({
container:{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
Slider
用於選擇一個範圍值的組件,一個滑動塊。
- 引入我們的滑塊和所需要的Alert方法
import {View,Text,StyleSheet,Picker,Slider,Alert} from 'react-native'
- 在render生命鉤子裏面渲染該組件
<Slider
style={styles.slider}
maximumValue={100}
minimumValue={0}
minimumTrackTintColor='hotpink'
step={1}
maximumTrackTintColor='red'
onSlidingComplete={this.completeHandler}
>
</Slider>
- 樣式
const styles = StyleSheet.create({
slider:{
width: 300
}
})
- 方法
completeHandler= (val)=>{
Alert.alert(
this.state.language+'基礎分爲',
val+'分',
[
{text: 'Ask me later'},
{text: 'Cancel'},
{text: 'OK'},
],
{ cancelable: false }
)
}
- onSlidingComplete效果:用戶鬆開滑塊的時候調用此回調,無論值是否變化。回調值爲當前值。
樣式
StyleSheet
- 所有RN中的樣式都必須用這個Api創建
- 所有樣式名稱都必須是駝峯命名
- RN中所有的組件默認display屬性都是flex,而且主軸方向是column
- 每個元素可以通過數組設置多種樣式,如果遇到相同的樣式,後面樣式的優先級大於前面
RN的盒子模型
- 在RN中的元素同樣擁有盒子模型:寬高、內邊距、邊框、外邊距。
- 需要注意在RN中的樣式大小不需要單位,同時沒有css的複合樣式,比如border、background、font,在RN中border寬度、顏色、圓角等樣式需要一個一個設置,background和font也一樣。
- 關於padding與margin,在css中可以賦予多個值來設置四邊不一樣的大小,在RN中只能給定一個值,指定相同的大小,如果四邊大小不一樣,就需要按照方向一個一個設置。同時RN也提供了paddingHorizontal、marginHorizontal、paddingVertical、marginVertical同時設置左右和上下兩個方向的值。
- 另外補充一下,在設置字體時,Android內建的有這麼幾個: normal、serif、monospace
import React, { Component } from "react";
import { StyleSheet, View, Text } from 'react-native';
export default class LayoutStudy extends React.Component{
render(){
return (
<View style={styles.container}>
<View style={styles.box}>
<Text>內容</Text>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
width: 300,
height: 300,
backgroundColor: "blue"
},
box:{
width: 200,
height: 200,
backgroundColor: "red",
paddingHorizontal: 50,
paddingVertical: 50,
borderWidth: 30,
borderColor: "yellow",
margin: 30
}
})
RN的伸縮佈局
- ReactNative中組件默認採用flex彈性佈局,使用flex可以使其在可利用的空間中動態地擴張或收縮。
- ReactNative中的flex工作原理和web上的CSS基本一致,當然也存在少許差異。首先是默認值不同:flexDirection的默認值是column而不是row,也就是元素縱向排列;而flex也只能指定一個數字值
import React, { Component } from "react";
import { StyleSheet, View, Text } from 'react-native';
export default class FlexLayout extends Component{
render(){
return (
<View>
<View>
<View><Text>123</Text></View>
<View><Text>456</Text></View>
</View>
{/* 改爲橫向排列 */}
<View style={styles.row}>
<View><Text>123</Text></View>
<View><Text>456</Text></View>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
row:{
flexDirection: 'row'
}
})
fetch
React Native 提供了和 web 標準一致的Fetch API,用於滿足開發者訪問網絡的需求。如果你之前使用過XMLHttpRequest(即俗稱的 ajax)或是其他的網絡 API,那麼 Fetch 用起來將會相當容易上手。這篇文檔只會列出 Fetch 的基本用法,並不會講述太多細節,你可以使用你喜歡的搜索引擎去搜索fetch api關鍵字以瞭解更多信息。
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
發送請求獲取數據
import React, { Component } from "react";
import { View, Text } from 'react-native';
export default class AjaxStudy extends Component{
render(){
return (
<View>
<Text>fetch的使用</Text>
</View>
)
}
componentWillMount(){
fetch('http://www.liulongbin.top:3005/api/getprodlist')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
})
.catch((error) => {
console.error(error);
});
}
}
第三方插件
react-native-swiper
這是一個可實現典型的輪播效果或翻頁效果插件,該插件只提供了一個組件Swiper,全部功能由該組件提供。該插件在內部對android與ios系統提供了不同的實現方式,如果是android系統才採用ViewPagerAndroid組件實現,ios系統則採用ScrollView實現。
- 需要注意,Swiper組件的高度依賴與父元素,所以在使用時嵌套一個View標籤控制Swiper展示高度
- 另外該庫的源碼使用了一個叫
Arial
的字體,模擬器中可以沒有這個字體導致報錯,可以修改爲normal、serif、monospace
中的任意一個字體,或者刪除該樣式也可以。
github react-native-swiper
安裝:yarn add react-native-swiper -S
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
import Swiper from 'react-native-swiper';
export default class SwiperTest extends Component {
render(){
let height = this.props.height || 200;
return (
<View style={[styles.wrapper, {height: height}]}>
{/* showsButtons控制左右箭頭顯示,autoplay控制自動輪播 */}
<Swiper showsButtons={true} autoplay={true}>
<View style={[styles.item, styles.item1]}>
<Text style={styles.text}>Banner one</Text>
</View>
<View style={[styles.item, styles.item2]}>
<Text style={styles.text}>Banner two</Text>
</View>
<View style={[styles.item, styles.item3]}>
<Text style={styles.text}>Banner three</Text>
</View>
</Swiper>
</View>
);
}
}
const styles = StyleSheet.create({
wrapper: {
marginTop: 24
},
item: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
item1: {
backgroundColor: '#9DD6EB',
},
item2: {
backgroundColor: '#97CAE5',
},
item3: {
backgroundColor: '#92BBD9',
},
text: {
color: 'red',
fontSize: 30,
fontWeight: 'bold',
}
});
react-navigation(更)
在 web 瀏覽器中, 你可以使用 (
<a>
) 標籤作爲錨點,鏈接到不同的頁面。 當用戶單擊某個鏈接時, 該 URL 就會被推送到瀏覽器歷史記錄堆棧。 當用戶點擊返回按鈕時, 瀏覽器會從歷史堆棧頂部刪除正在訪問的頁面, 因此當前頁現在就成了以前訪問過的頁面。 React Native沒有像Web瀏覽器那樣的內置全局歷史堆棧的想法 – 這就是 React Navigation 存在的意義
- 通常我們開發的App是由多個頁面構成的,那麼我們就需要一種或多種方式去管理這些頁面,在Web開發中,比較常見的管理方式有:Tab欄單頁嵌多內容,或者路由管理多頁面切換。
- react-navigation便是實現這種需求的RN插件,同時它還是官方推薦使用的第三方導航插件,可實現單頁多內容切換,也可以實現路由跳轉。
- react-navigation提供了幾種不同類型或者效果的導航組件,每個組件都由對應的工廠函數來創建,這些工廠函數在調用時通常都需要兩個參數,第一個參數統一爲路由配置對象,第二個參數則是一個個性化的配置對象,不同組件的配置項存在差異。
使用
# 安裝兩套包
yarn add react-navigation
yarn add react-native-gesture-handler