第三方插件
react-native-swiper
这是一个可实现典型的轮播效果或翻页效果插件,该插件只提供了一个组件Swiper,全部功能由该组件提供。该插件在内部对android与ios系统提供了不同的实现方式,如果是android系统才采用ViewPagerAndroid组件实现,ios系统则采用ScrollView实现。
- github
- 安装:
yarn add react-native-swiper -S
使用范例
需要注意,Swiper组件的高度依赖与父元素,所以在使用时嵌套一个View标签控制Swiper展示高度。
另外该库的源码使用了一个叫Arial的字体,模拟器中可以没有这个字体导致报错,可以修改为normal、serif、monospace中的任意一个字体,或者删除该样式也可以。
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',
}
});
测试
- 修改
App.js根组件 - 导入
轮播图组件并使用测试
import SwiperTest from './components/SwiperTest';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<SwiperTest></SwiperTest>
<Text>轮播图组件测试</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
}
});
scrollView实现轮播图
利用scrollView的属性,可以很容易的实现一个简易的轮播图效果。
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
Image,
ScrollView
} from 'react-native';
const Dimensions = require('Dimensions');
const { width:screenWidth, height:screenHeight } = Dimensions.get("window");
export default class ScrollViewTest extends Component {
constructor(props) {
super(props);
this.state = {
currentPage: 0,
timer: null
}
}
autoSwipe() {
this.state.timer = setInterval(() => {
// 更新currentPage
this.setState((oldVal) => {
let currentPage = this.state.currentPage + 1;
currentPage = currentPage > (this.props.imgList.length-1) ? 0: currentPage;
return { currentPage };
});
console.log(this.state.timer)
// 更新视图
this.refs.scrollView.scrollTo({x: this.state.currentPage * screenWidth});
}, 2000);
}
startAutoSwipe() {
this.autoSwipe();
}
stopAutoSwipe() {
clearInterval(this.state.timer);
}
componentDidMount() {
this.autoSwipe();
}
componentWillUnmount() {
clearInterval(this.state.timer);
}
render() {
return (
<ScrollView
ref="scrollView" style={[styles.swipe]}
horizontal={true} pagingEnabled={true} showsHorizontalScrollIndicator={false}
onTouchStart={this.stopAutoSwipe.bind(this)} onTouchEnd={(e)=>{this.stopAutoSwipe.bind(this)}}>
{
this.props.imgList.map((v, i) => {
return (
<View key={`key${i}`} style={[styles.swipeItem]}>
<Image style={[styles.swipeImg]} source={{uri: v}}></Image>
</View>
)
})
}
</ScrollView>
);
}
}
const styles = StyleSheet.create({
swipe: {
marginTop: 24,
width: screenWidth,
height: screenHeight
},
swipeItem: {
width: screenWidth,
height: 100
},
swipeImg: {
flex: 1
}
});
react-navigation
通常我们开发的App是由多个页面构成的,那么我们就需要一种或多种方式去管理这些页面,在Web开发中,比较常见的管理方式有:Tab栏单页嵌多内容,或者路由管理多页面切换。
react-navigation便是实现这种需求的RN插件,同时它还是官方推荐使用的第三方导航插件,可实现单页多内容切换,也可以实现路由跳转。
react-navigation提供了几种不同类型或者效果的导航组件,每个组件都由对应的工厂函数来创建,这些工厂函数在调用时通常都需要两个参数,第一个参数统一为路由配置对象,第二个参数则是一个个性化的配置对象,不同组件的配置项存在差异。
- [官网]reactnavigation.org/
- [github]github.com/react-navig…
createBottomTabNavigator
这个工厂函数可以创建一个最基本的Tab栏切换组件,通常Tab栏可切换的项是有限的,不会太多,所有大部分情况下我们会把Tab栏整体看作一个页面,管理了不同内容,或者称为子页页可以。
基本使用
import React, { Component } from "react";
import { StyleSheet, View, Text, Image } from 'react-native';
import { createBottomTabNavigator } from 'react-navigation';
const Home = () => {
return (
<View style={styles.container}>
<Text>Home</Text>
</View>
);
}
const MovieList = () => {
return (
<View style={styles.container}>
<Text>MovieList</Text>
</View>
);
}
const MovieDetail = () => {
return (
<View style={styles.container}>
<Text>MovieDetail</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});
export default createBottomTabNavigator(
// 路由配置,key值会作为tabBar的label显示
{
Home,
MovieList,
MovieDetail,
}
);
路由配置
export default createBottomTabNavigator(
// 路由配置
{
Home: {
// 组件
screen: Home,
// 回调需要返回一个导航器配置对象
navigationOptions: ({navigation, navigationOptions}) => {
return {
// 导航条中的提示文本
tabBarLabel: "首页",
// 导航条中的icon,选中与不选中状态显示不同icon
tabBarIcon: ({focused}) => {
if (focused) {
return (
<Image
style={{width: 16, height: 16}}
source={require('../public/img/12.jpg')}/>
);
} else {
return (
<Image
style={{width: 16, height: 16}}
source={require('../public/img/56.jpg')}/>
);
}
}
}
}
},
MovieList: {
screen: MovieList,
navigationOptions: ({navigation, navigationOptions}) => {
return { "tabBarLabel": "电影列表" }
}
},
MovieDetail: {
screen: MovieList,
navigationOptions: ({navigation, navigationOptions}) => {
return { "tabBarLabel": "电影详情" }
}
}
}
);
静态属性配置导航选项
在配置路由时,不同页面的导航选项还可以在组件内部通过navigationOptions静态属性来配置。
import React, { Component } from "react";
import {
StyleSheet,
View,
Text,
Image
} from 'react-native';
export default class Home extends Component {
// 可选的配置
static navigationOptions = {
tabBarLabel: "首页",
tabBarIcon: ({focused}) => {
if (focused) {
return (
<Image style={styles.tabBarIcon} source={require('../public/img/12.jpg')}/>
);
} else {
return (
<Image style={styles.tabBarIcon} source={require('../public/img/12.jpg')}/>
);
}
}
}
render() {
return (
<View style={styles.container}>
<Text>Home</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
tabBarIcon: {
width: 16,
height: 16,
}
});
BottomTabNavigator个性配置
export default createBottomTabNavigator(
// 路由配置
{
...
},
// BottomTabNavigator配置对象
{
// 默认页
initialRouteName: 'Home',
// 导航条配置
tabBarOptions: {
// label选中与不选中颜色
activeTintColor: 'aqua',
inactiveTintColor: 'black',
// label样式
labelStyle: {
fontSize: 12,
marginTop: 1,
},
// tabBar样式
style: {
backgroundColor: 'purple',
borderTopWidth: 1,
borderTopColor: '#ccc',
paddingVertical: 1,
height: 40
},
// 是否显示icon
showIcon: true
}
}
);
createMaterialTopTabNavigator
这个tab导航组件提供了动画切换效果,可以把createBottomTabNavigator改成createMaterialTopTabNavigator即可看到效果差异,同时提供了更多的配置。
// MaterialTopTabNavigator配置对象
{
// 默认页
initialRouteName: 'MovieList',
// tabBar位置,可以设为top
tabBarPosition: 'bottom',
// 动画开关
animationEnabled: true,
swipeEnabled: true,
tabBarOptions: {
activeTintColor: 'aqua',
inactiveTintColor: 'black',
// 是否显示icon,如果显示icon就不会显示文字
showIcon: false,
// 设置tabBar样式
style: {
backgroundColor: 'purple',
borderTopWidth: 1,
borderTopColor: '#ccc',
paddingVertical: 1,
height: 40
},
// 设置label样式
labelStyle: {
fontSize: 12,
marginTop: 1,
}
},
backBehavior: 'initialRoute',
lazy: true,
}
createStackNavigator
这个堆栈式导航组件与其他组件有大不同,因为它内部记录你的页面浏览过程,并可以向浏览器那样前进后退,实现路由控制。
Home组件,可以跳到列表页
import React, { Component } from 'react';
import { StyleSheet, View, Text, Button, Image, ScrollView } from 'react-native';
import Dimensions from 'Dimensions';
export default class Home extends Component {
render() {
return (
<View style={[{backgroundColor: 'purple'}, styles.item]}>
<Text>首页</Text>
{/* push方法需要一个路由配置时的key,然后进行页面跳转,同时页面入栈 */}
<Button title="跳转到列表页" onPress={()=>{console.log(this.props.navigation.push('List'))}}></Button>
</View>
)
}
}
const styles = StyleSheet.create({
item: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});
List组件,可以跳到首页
import React, { Component } from 'react';
import { StyleSheet, View, Text, Button, Image, ScrollView } from 'react-native';
import Dimensions from 'Dimensions';
export default class List extends Component {
render() {
return (
<View style={[{backgroundColor: 'purple'}, styles.item]}>
<Text>列表</Text>
{/* 调用pop方法出栈返回上一页 */}
<Button title="返回到首页" onPress={()=>{console.log(this.props.navigation.pop())}}></Button>
</View>
)
}
}
const styles = StyleSheet.create({
item: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});
StackNavigator组件使用
import React, { Component } from 'react';
import { StyleSheet, View, Text, Button, Image, ScrollView } from 'react-native';
import Dimensions from 'Dimensions';
import Home from '../stackPage/Home';
import List from '../stackPage/List';
import { createStackNavigator } from 'react-navigation';
export default createStackNavigator(
{
Home: {
screen: Home,
navigationOptions: ({navigation, navigationOptions}) => {
return {
// 两个都可以设置标题,下面的优化级更高
title: '首页标题',
headerTitle: '首页',
}
}
},
List: {
screen: Home,
navigationOptions: ({navigation, navigationOptions}) => {
return {
headerTitle: '列表页',
}
}
},
},
// 个性化的配置对象
{
initialRouteName: "Home",
}
);
路由控制
实际上所有的导航组件都式可以进行路由跳转的,区别是只有stackNavigation才会存储页面浏览记录,拥有栈相关的操作方法,比如push、pop等。
参数传递
准备两个页面,首页提供一个输入框,输入值后跳转到另一页进行展示
stack导航组件的重绘
Tab导航组件的重绘
tab组件导航演示
Home组件
import React, { Component } from "react";
import {
StyleSheet,
View,
Text,
Image,
Button
} from 'react-native';
export default class Home extends Component {
render() {
console.log('首页渲染');
return (
<View style={styles.container}>
<Text>Home</Text>
<Button
title="跳转到列表页"
onPress={()=>{this.props.navigation.navigate('MovieList')}}>
</Button>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
tabBarIcon: {
width: 16,
height: 16,
}
});
MovieList组件
import React, { Component } from "react";
import {
StyleSheet,
View,
Text,
Button
} from 'react-native';
export default class MovieList extends Component {
render() {
console.log('列表页渲染');
return (
<View style={styles.container}>
<Text>MovieDetail</Text>
<Button
title="跳转到详情页"
onPress={()=>{this.props.navigation.navigate('MovieDetail')}}>
</Button>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});
MovieDetail组件
import React, { Component } from "react";
import {
StyleSheet,
View,
Text,
Button
} from 'react-native';
export default class MovieDetail extends Component {
render() {
console.log('详情页渲染');
return (
<View style={styles.container}>
<Text>MovieDetail</Text>
<Button
title="返回到首页"
onPress={()=>{this.props.navigation.goBack()}}>
</Button>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});
Tab导航组件
import React, { Component } from "react";
import { StyleSheet, View, Image } from 'react-native';
import { createMaterialTopTabNavigator } from 'react-navigation';
import Home from './Home';
import MovieList from './MovieList';
import MovieDetail from './MovieDetail';
export default createMaterialTopTabNavigator(
{
Home,
MovieList,
MovieDetail,
}
);
react-native-vector-icons
[github]github.com/oblador/rea…
react-native-image-picker
该组件可以调用摄像头进行拍照,因为RN默认没有提供摄像头API,所以使用该插件需要修改原生项目进行配置,同时修改原生项目后需要重新打包安装
- github
- 安装
npm install react-native-image-picker@latest
原生配置
修改android/build.gradle文件
buildscript {
...
dependencies {
classpath 'com.android.tools.build:gradle:2.2.+' // <- USE 2.2.+ version
}
...
}
修改android/gradle/wrapper/gradle-wrapper.properties文件
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
修改android/app/build.gradle
dependencies {
compile project(':react-native-image-picker')
}
修改AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
修改MainApplication.java
import com.imagepicker.ImagePickerPackage;
public class MainApplication extends Application implements ReactApplication {
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new ImagePickerPackage(),
// OR if you want to customize dialog style
new ImagePickerPackage(R.style.my_dialog_style)
);
}
}
前端使用
// 第1步:
import ImagePicker from 'react-native-image-picker'
//底部弹出框选项
var photoOptions = {
title: '请选择',
cancelButtonTitle: '取消',
takePhotoButtonTitle: '拍照',
chooseFromLibraryButtonTitle: '选择相册',
quality: 0.75,
allowsEditing: true,
noData: false,
storageOptions: {
skipBackup: true,
path: 'images'
}
}
constructor(props) {
super(props);
this.state = {
imgURL: ''
}
}
<Button title="拍照" onPress={this.cameraAction}></Button>
<Image source={{uri: this.state.imgURL}} style={{width: 200, height: 200}}></Image>
cameraAction = () => {
ImagePicker.showImagePicker(photoOptions, (response) => {
console.log('response' + response);
this.setState({
imgURL: response.uri
});
if (response.didCancel) {
return
}
})
}
打包
退出之前调试的App,重新运行react-native run-android进行打包部署,打包时会下载一些jar包,需要耐心等待。