React Native学习之ViewPagerAndroid做引导页
实战:使用ViewPagerAndroid
实现引导页
涉及的知识点:
- 组件如何联动
- 符合ES6的标准写法
- 组件的封装,非常灵活
- Navigator路由的用法
index.android.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
Image,
TouchableOpacity,
ViewPagerAndroid,
Navigator,
View
} from 'react-native';
import LikeCount from './LikeCount.js'; //导入“喜欢数”组件
import Button from './Button.js'; //导入“自定义的按钮”组件
import HomeUI from './HomeUI.js'; //导入“首页”组件
const PAGES = 5;
const BGCOLOR = ['#fdc08e', '#fff6b9', '#99d1b7', '#dde5fe', '#f79273'];
const IMAGE_URIS = [
'http://apod.nasa.gov/apod/image/1410/20141008tleBaldridge001h990.jpg',
'http://apod.nasa.gov/apod/image/1409/volcanicpillar_vetter_960.jpg',
'http://apod.nasa.gov/apod/image/1409/m27_snyder_960.jpg',
'http://apod.nasa.gov/apod/image/1409/PupAmulti_rot0.jpg',
'https://www.baidu.com/img/bd_logo1.png',
];
//进度条组件
class ProgressBar extends Component {
constructor(props) {
super(props);
}
render() {
//当前位置+偏移量
var fractionalPosition = (this.props.progress.position + this.props.progress.offset);
var progressBarSize = (fractionalPosition / (PAGES - 1)) * this.props.size;
return(
//进度条使用2个View实现,通过宽度表示进度
//progressBarSize当前的进度
//this.props.size进度条的总长度
<View style={[styles.progressBarContainer, {width: this.props.size}]}>
<View style={[styles.progressBar, {width: progressBarSize}]}/>
</View>
);
}
}
class WelcomeUI extends Component {
//欢迎页面,使用Viewpager实现
//null is not an object 解决办法:初始化的时候要用constructor 而不是getInitialState
//当前使用 ES6 作为标准编程规范
//React Native 组件中必须使用构造函数初始化 state
//用构造函数来替代之前的 Initial实例化
constructor(props) {
super(props);
this.state = {
page: 0,
animationsAreEnabled: true, //动画是否开启
progress: {
position: 0,
offset: 0,
},
};
}
//See React on ES6+
onPageSelected = (e)=>{
//这个回调会在页面切换完成后(当用户在页面间滑动)调用
//回调参数中的event.nativeEvent对象
this.setState({page: e.nativeEvent.position});
}
onPageScroll = (e)=>{
//当在页间切换时(不论是由于动画还是由于用户在页间滑动/拖拽)执行。
//回调参数中的event.nativeEvent对象会包含如下数据:
//position: 从左数起第一个当前可见的页面的下标
//offset: 一个在[0,1)(大于等于0,小于1)之间的范围,代表当前页面切换的状态。值x表示现在"position"所表示的页有(1 - x)的部分可见,而下一页有x的部分可见。
this.setState({progress:e.nativeEvent});
}
move(delta) {
var page = this.state.page + delta;
this.go(page);
}
go(page) {
if(this.state.animationsAreEnabled) {
this.viewPager.setPage(page);
} else {
this.viewPager.setPageWithoutAnimation(page);
}
//刷新
this.setState({page});
}
onClick = ()=>{
//alert('点击');
const { navigator } = this.props;
//为什么这里可以取得 props.navigator?请看上文:
//<Component {...route.params} navigator={navigator} />
//这里传递了navigator作为props
if(navigator) {
navigator.push({
name: 'HomeUI',
component: HomeUI,
})
}
}
render() {
const thunbsUp = '\uD83D\uDC4D';
var pages=[];
for(var i=0; i<PAGES; i++) {
var pageStyle = {
backgroundColor: BGCOLOR[i % BGCOLOR.length],
alignItems: 'center',
padding: 20,
};
if (i < PAGES-1) {
//前面几个Viewpage
//collapsable: 如果一个View只用于布局它的子组件,则它可能会为了优化而从原生布局树中移除。
//把此属性设为false可以禁用这个优化,以确保对应视图在原生结构中存在。
pages.push(
<View key={i} style={pageStyle} collapsable={false}>
<Image
style={styles.image}
source={{uri: IMAGE_URIS[i % BGCOLOR.length]}}
/>
<LikeCount />
</View>
);
} else {
//最后一个viewpage 加了一个按钮
pages.push(
<View key={i} style={pageStyle} collapsable={false}>
<Image
style={styles.image}
source={{uri: IMAGE_URIS[i % BGCOLOR.length]}}
/>
<LikeCount />
<TouchableOpacity onPress={this.onClick} style={styles.startupButton}>
<Text style={styles.likesText}> {thunbsUp + '启动首页'} </Text>
</TouchableOpacity>
</View>
);
}
}
var { page, animationsAreEnabled } = this.state;
//等效于
//var page = this.state.page;
//var animationsAreEnabled = this.state.animationsAreEnabled;
return (
<View style={styles.container}>
<ViewPagerAndroid
style={styles.viewPager}
initialPage={0}
onPageScroll={this.onPageScroll}
onPageSelected={this.onPageSelected}
ref={viewPager => { this.viewPager = viewPager; }}
>
{pages}
</ViewPagerAndroid>
<View style={styles.buttons}>
{ animationsAreEnabled ?
<Button
text="Turn off animations"
enabled={true}
onPress={() => this.setState({animationsAreEnabled: false})}
/> :
<Button
text="Turn animations back on"
enabled={true}
onPress={() => this.setState({animationsAreEnabled: true})}
/>
}
</View>
<View style={styles.buttons}>
<Button text="Start" enabled={page > 0} onPress={() => this.go(0)}/>
<Button text="Prev" enabled={page > 0} onPress={() => this.move(-1)}/>
<Text style={styles.buttonText}>页:{page + 1} / {PAGES}</Text>
<ProgressBar size={100} progress={this.state.progress}/>
<Button text="Next" enabled={page < PAGES - 1} onPress={() => this.move(1)}/>
<Button text="Last" enabled={page < PAGES - 1} onPress={() => this.go(PAGES - 1)}/>
</View>
</View>
);
}
}
class RNAPP extends Component {
render() {
let defaultName='WelcomeUI';
let defaultComponent=WelcomeUI;
return (
<Navigator
initialRoute={{ name: defaultName, component: defaultComponent }}
//配置场景
configureScene={
(route) => {
//页面之间跳转的动画,具体值可以查看源代码: node_modules/react-native/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js
return Navigator.SceneConfigs.FloatFromRight;
}
}
renderScene={
(route, navigator) => {
let Component = route.component;
return <Component {...route.params} navigator={navigator} />
}
}
/>
);
}
}
const styles = StyleSheet.create({
buttons: {
flexDirection: 'row',
height: 30,
backgroundColor: 'black',
alignItems: 'center',
justifyContent: 'space-between',
},
container: {
flex: 1,
backgroundColor: 'white',
},
image: {
width: 300,
height: 200,
padding: 20,
},
startupButton:{
backgroundColor: 'rgba(0, 0, 0, 0.1)',
borderColor: '#333333',
borderWidth: 1,
borderRadius: 5,
margin: 8,
padding: 8,
},
progressBarContainer: {
height: 10,
margin: 10,
borderColor: '#eeeeee',
borderWidth: 2,
},
progressBar: {
alignSelf: 'flex-start',
flex: 1,
backgroundColor: '#ff0000',
},
viewPager: {
flex: 1,
},
buttonText: {
color: 'white',
},
});
AppRegistry.registerComponent('RNAPP', () => RNAPP);
LikeCount.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TouchableOpacity,
View
} from 'react-native';
//点赞数组件,ES6语法
export default class LikeCount extends Component {
constructor(props){
super(props);
this.state={
likes:0,
};
}
onClick = ()=>{
this.setState({likes: this.state.likes + 1});
}
render() {
//点赞的小图标,emoji表情,使用unicode编码
const thunbsUp='\uD83D\uDC4D';
return (
<View style={styles.likeContainer}>
<TouchableOpacity onPress={this.onClick} style={styles.likeButton}>
<Text style={styles.likesText}>{thunbsUp+'Like'}</Text>
</TouchableOpacity>
<Text style={styles.likesText}>{this.state.likes+'个喜欢数'}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
likeButton: {
backgroundColor: 'rgba(0, 0, 0, 0.1)',
borderColor: '#333333',
borderWidth: 1,
borderRadius: 5,
flex: 1,
margin: 8,
padding: 8,
},
likeContainer: {
flexDirection: 'row',
},
likesText: {
flex: 1,
fontSize: 18,
alignSelf: 'center',
},
});
Button.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TouchableWithoutFeedback,
View
} from 'react-native';
//开始 前进 后退 最后 开启/关闭动画 5个按钮的通用写法
export default class Button extends Component {
constructor(props) {
super(props);
}
_handlePress = ()=>{
if (this.props.enabled && this.props.onPress) {
//按钮可用,没有变灰,则启用按钮的onPress()方法
this.props.onPress();
}
}
render() {
//这个View有2个样式,第二个样式是用来覆盖的(加了背景颜色和透明度)
return(
<TouchableWithoutFeedback onPress={this._handlePress}>
<View style={[styles.button, this.props.enabled ? {} : styles.buttonDisabled]}>
<Text style={styles.buttonText}>{this.props.text}</Text>
</View>
</TouchableWithoutFeedback>
);
}
}
const styles = StyleSheet.create({
button: {
flex: 1,
width: 0,
margin: 5,
borderColor: 'gray',
borderWidth: 1,
backgroundColor: 'gray',
},
buttonDisabled: {
backgroundColor: 'black',
opacity: 0.5,
},
buttonText: {
color: 'white',
},
});
Button.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
export default class HomeUI extends Component {
goBack() {
const { navigator } = this.props;
if(navigator) {
//很熟悉吧,入栈出栈~ 把当前的页面pop掉,即可返回上一个页面
navigator.pop();
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome} onPress={this.goBack.bind(this)}>
Welcome to React Native!{'\n'}
</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Double tap R on your keyboard to reload,{'\n'}
Shake or press menu button for dev menu{'\n'}
Powered by rnapp.cc
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/02/25/react-native-learning-viewpagerandroid-as-guide-page/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
THE END
0
二维码
打赏
海报
React Native学习之ViewPagerAndroid做引导页
实战:使用ViewPagerAndroid实现引导页
涉及的知识点:
组件如何联动
符合ES6的标准写法
组件的封装,非常灵活
Navigator路由的用法
index.android.js
/**
……
文章目录
关闭
共有 0 条评论