效果
small.gif
代码
入口
'use strict';
import React, {
Component
} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button,
PixelRatio,
ViewPagerAndroid,
Image,
TouchableOpacity,
} from 'react-native';
import {
createStackNavigator
} from 'react-navigation';
import CustomButton from './CustomButton';
import ProgressBar from './ProgressBar';
import Likes from './Likes';
import HomeUi from './HomeUi';
//页面数量
const PAGES = 5;
//背景颜色
const PAGE_BG_COLORS = ['#fdc08e', '#fff6b9', '#99d1b7', '#dde5fe', '#f79273'];
//图片地址
const PAGE_IMAGES = [
'http://img06.tooopen.com/images/20161121/tooopen_sy_187362418112.jpg',
'http://a.hiphotos.baidu.com/image/h%3D300/sign=4f5477ac8f26cffc762ab9b289014a7d/b3fb43166d224f4ad8b5722604f790529822d1d3.jpg',
'http://a.hiphotos.baidu.com/image/h%3D300/sign=10b374237f0e0cf3bff748fb3a47f23d/adaf2edda3cc7cd90df1ede83401213fb80e9127.jpg',
'http://e.hiphotos.baidu.com/image/h%3D300/sign=8562b2c234dbb6fd3a5be3263925aba6/8ad4b31c8701a18b536e1476932f07082838fe06.jpg',
'http://a.hiphotos.baidu.com/image/h%3D300/sign=fbe3d9666ed9f2d33f1122ef99ed8a53/3bf33a87e950352a464bc38f5f43fbf2b2118b0b.jpg'
];
class WelcomeUi extends Component {
constructor(props) {
super(props);
//定义属性
this.state = {
//当前页面
page: 0,
animationsAreEnabled: true, //动画是否开启
//进度条使用 position当前页面 offset偏移量
progress: {
position: 0,
offset: 0,
},
}
}
/**
当在页间切换时(不论是由于动画还是由于用户在页间滑动/拖拽)执行。
回调参数中的 event.nativeEvent 对象会包含如下数据:
position 从左数起第一个当前可见的页面的下标。
offset 一个在[0,1]之内的范围(可以等于0或1),代表当前页面切换的状态。值 x 表示现在"position"所表示的页有(1 - x)的部分可见,而下一页有 x 的部分可见。
ViewPager滑动时就会回调此方法,然后改变属性,视图就会不断刷新
*/
onPageScroll = (event) => {
console.log(event.nativeEvent);
this.setState({
progress: event.nativeEvent
});
}
/**
*
这个回调会在页面切换完成后(当用户在页面间滑动)调用。
回调参数中的 event.nativeEvent 对象会包含如下的字段:
position 当前被选中的页面下标
此方法当ViewPager完全显示时被调用 setState设置属性 改变视图刷新 setState是异步的 下面会有说明。
*/
onPageSelected = (event) => {
console.log(event.nativeEvent);
this.setState({
page: event.nativeEvent.position,
});
}
/**
* 跳到指定的页面 参数page 第几个页面
this.viewPager使用ref属性。详细请见ViewPageAndroid中的ref属性,也可以看看我写的ref属性这篇文章。
setPage是ViewPagerAndroid中的方法。跳到指定页面(带动画)
setPageWithoutAnimation和setPage方法类似,(不带动画)
最后对page属性赋值,刷新视图。
*/
go = (page) => {
if (this.state.animationsAreEnabled) {
this.viewPager.setPage(page);
} else {
this.viewPager.setPageWithoutAnimation(page);
}
console.log('go : ' + page);
this.setState({
page
});
//这里取到的page没有更新掉 但是render中更新了。 难道是因为 setState更新是异步的?
console.log('go page : ' + this.state.page);
}
/**
*这个方法和go方法类似 可以优化下代码,我没有优化的原因是因为这个写法报错了,改完之后 没有改回去,一样用
优化:
move = (page) => {
var current = this.state.page + page;
this.go(current);
}
*/
move = (page) => {
// let currentPage = this.state.page + page;
// console.log('move : ' + page + 'currentPage : ' + currentPage);
// this.go(currentPage);
let currentPage = this.state.page + page
if (this.state.animationsAreEnabled) {
this.viewPager.setPage(currentPage);
} else {
this.viewPager.setPageWithoutAnimation(currentPage);
}
console.log('move : ' + currentPage);
this.setState({
page: currentPage
}, () => {
console.log('改进写法:' + this.state.page);
});
//这里取到的page没有更新掉 但是render中更新了。 难道是因为 setState更新是异步的? 然后搜了一下 确实是异步的 在setState的第二个参数获取最新的值
/**
this.setState({
page:'123456',
}, () => {
console.log(this.state.page);
})
*/
console.log('move page : ' + this.state.page);
}
render() {
//点赞的小图标
const thunbsUp = "\uD83D\uDC4D";
//需要显示的页面数组 里面存放的都是组件
var pages = [];
//循环
for (var i = 0; i < PAGES; i++) {
//写页面样式 因为背景颜色不一样 动态生成
var pagerStyle = {
backgroundColor: PAGE_BG_COLORS[i % PAGE_BG_COLORS.length],
alignItems: 'center',
padding: 20,
}
//除去最有一个页面
if (i < PAGES - 1) {
//collapsable 如果一个View只用于布局它的子组件,
// 则它可能会为了优化而从原生布局树中移除。 把此属性设为false可以禁用这个优化,以确保对应视图在原生结构中存在。
pages.push(
<View style={pagerStyle} key={i} collapsable={false}>
<Image
style={styles.images}
source={{uri:PAGE_IMAGES[i]}}
/>
<Likes></Likes>
</View>
);
} else { //最后一个页面
pages.push(
<View style={pagerStyle} key={i} collapsable={false}>
<Image
style={styles.images}
source={{uri:PAGE_IMAGES[i]}}
/>
<Likes/>
<TouchableOpacity style={styles.startupButtpn} onPress={()=>this.props.navigation.navigate('Home')}>
<Text style={styles.likesText}>{thunbsUp+'启动首页'}</Text>
</TouchableOpacity>
</View>
);
}
}
var {
page,
animationsAreEnabled
} = this.state;
console.log('render page : ' + page);
return (
<View style={styles.container}>
<ViewPagerAndroid
style={styles.viewpager}
//初始选中的页的下标。你可以用 setPage 函数来翻页,并且用 onPageSelected 来监听页的变化。
initialPage={0}
onPageScroll={this.onPageScroll}
onPageSelected={this.onPageSelected}
ref={viewPager=>{this.viewPager=viewPager;}}
>
{pages}
</ViewPagerAndroid>
<View style={styles.buttons}>
{
animationsAreEnabled?
<CustomButton
text='Turn off animations'
enable={true}
onPress={()=>this.setState({animationsAreEnabled:false})}
/>
:
<CustomButton
text='Turn off animations back on'
enable={true}
onPress={()=>this.setState({animationsAreEnabled:true})}
/>
}
</View>
<View style={styles.buttons}>
<CustomButton text='Start' enable={page>0} onPress={()=>this.go(0)}/>
<CustomButton text='Prev' enable={page>0} onPress={()=>this.move(-1)}/>
<ProgressBar progress={this.state.progress} size={100} length={PAGES}></ProgressBar>
<CustomButton text='Next' enable={page<PAGES-1} onPress={()=>this.move(1)}/>
<CustomButton text='Last' enable={page<PAGES-1} onPress={()=>this.go(PAGES-1)}/>
</View>
</View>
);
}
}
class Home extends Component {
render() {
return (
<View style={styles.containerHome}>
<Text style={styles.welcomeHome}>'我是冯星'</Text>
</View>
);
}
}
const RootNavigation = createStackNavigator({
WelcomeUi: {
screen: WelcomeUi,
},
Home: {
screen: Home,
},
}, {
headerMode: 'none',
});
const styles = StyleSheet.create({
container: {
flex: 1,
},
viewpager: {
flex: 1,
},
images: {
width: 200,
height: 200,
padding: 20,
},
pagerStyle: {
backgroundColor: '#fff6b9',
alignItems: 'center',
padding: 20,
},
buttons: {
flexDirection: 'row',
height: 30,
backgroundColor: 'black',
alignItems: 'center',
justifyContent: 'space-between',
},
startupButtpn: {
backgroundColor: 'rgba(0,0,0,0.1)',
borderColor: '#333333',
borderWidth: 1 / PixelRatio.get(),
borderRadius: 5,
margin: 8,
padding: 8,
},
likesText: {
fontSize: 18,
alignSelf: 'center',
},
containerHome: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcomeHome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});
AppRegistry.registerComponent('MyApp', () => RootNavigation);
自定义按钮组件
import React, {
Component
} from 'react';
import {
StyleSheet,
Text,
TouchableWithoutFeedback,
TouchableHighlight,
View,
Image,
PixelRatio,
} from 'react-native';
export default class CustomButton extends Component {
//传递的属性 {text: "Turn off animations", enable: true, onPress: ƒ}
constructor(props) {
super(props);
console.log(props);
}
_handlerOnPress = () => {
//如果按钮可以使用 并且 传递过来的onPress有值 就执行onPress函数
if (this.props.enable && this.props.onPress) {
this.props.onPress();
}
}
render() {
return (
<TouchableWithoutFeedback onPress={this._handlerOnPress}>
<View style={[styles.button,this.props.enable?{}:styles.buttonDisabled]}>
<Text style={styles.buttonText}>{this.props.text}</Text>
</View>
</TouchableWithoutFeedback>
);
}
}
const styles = StyleSheet.create({
button: {
flex: 1,
width: 0,
margin: 5,
borderColor: 'red',
borderWidth: 1 / PixelRatio.get(),
backgroundColor: 'gray',
borderRadius: 3,
},
buttonDisabled: {
backgroundColor: 'yellow',
opacity: 0.5,
},
buttonText: {
color: 'white',
textAlign: 'center',
},
})
喜欢个数组件
import React, {
Component
} from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
PixelRatio,
} from 'react-native';
//rn 最小单位
var ptOne = 1 / PixelRatio.get();
export default class Likes extends Component {
constructor(props) {
super(props);
this.state = {
likes: 0,
}
}
//点击组件 +1刷新显示。
onClick = () => {
var a = this.state.likes;
this.setState({
likes: this.state.likes + 1,
});
}
render() {
//这是一个点赞的小图标 一个代码就搞定了
const thunbsUp = '\uD83D\uDC4D';
return (
<View style={styles.container}>
<TouchableOpacity style={styles.buttonLikes} onPress={this.onClick}>
<Text>{thunbsUp+'Like'}</Text>
</TouchableOpacity>
<Text style={styles.likesText}>{this.state.likes+'个喜欢数'}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
buttonLikes: {
borderWidth: ptOne,
borderColor: 'rgba(0,0,0,0.1)',
backgroundColor: '#cccccc',
borderRadius: 5,
margin: 5,
padding: 5,
},
container: {
flexDirection: 'row',
},
likesText: {
fontSize: 16,
alignSelf: 'center',
},
});
进度条组件
import React, {
Component
} from 'react';
import {
StyleSheet,
View,
} from 'react-native';
export default class ProgressBar extends Component {
//props内部参数 {length:5,Size:100,progress:{position:0,offset:0}}
constructor(props) {
super(props);
}
render() {
//进度条的实现是两个view。给view设置width属性 来改变进度。
//根据当前页面和偏移量计算出view的宽是多少
console.log(this.props);
var fractionalPosition = (this.props.progress.position + this.props.progress.offset);
var progressBarSize = (fractionalPosition / (this.props.length - 1)) * this.props.size;
return (
<View style={[styles.progressBarContainer,{width:this.props.size}]}>
<View style={[styles.progressBar,{width:progressBarSize}]}></View>
</View>
);
}
}
const styles = StyleSheet.create({
progressBarContainer: {
height: 10,
margin: 10,
borderColor: '#eeeeee',
borderWidth: 2,
},
progressBar: {
alignSelf: 'flex-start',
flex: 1,
backgroundColor: '#ff0000',
}
});
网友评论