直接从进入app开始讲每一个功能的具体实现。
先声明本文提到的这些功能,我的实现方法可能并不是最优的,如果有更好的实现方法,欢迎交流!
转载请注明出处!
1.引导页只在第一次打开app后出现:
实现方法:类似于原生Android的处理方法,直接存一个值到本地,原生用的是Sharedpreferences,RN里面就直接用AsyncStorage。原理就是在第一次打开的时候设定一个值保存在本地,之后打开再取出这个值,如果不为之前设定的那个值就显示不同的内容。
实现代码:我这里是根据需求进入不同的路由,具体操作可以自己设置
openApp(){
AsyncStorage.getItem('isFirst',(error,result)=>{
if (result === 'false') {
this.props.navigator.resetTo({ component:Root }) }
else { console.log('第一次打开');
AsyncStorage.setItem('isFirst','false',(error)=>{ if (error) { alert(error); } });
this.props.navigator.resetTo({ component:Root2 })}});
}
2.启动页图片铺满屏幕:
实现方法:设置图片的style
实现代码:
image:{
flex:1,
alignItems:'center',
justifyContent:'center',
width:null,
height:null,
}
3.类似qq消息列表的侧滑删除:
实现方法:列表用的是FlatList,实现侧滑删除用到的了swipable,每个Item都给它在外层包裹一层swipeable,使得每个Item都是能够左滑的,然后在Swipeable中给rightButtons设置样式、点击事件,来实现侧滑删除的功能。
下载:npm install --save react-swipeable
导入:import Swipeable from 'react-native-swipeable';
实现代码:FlatList不用改,直接在renderItem上操作
<FlatList
renderItem={this.ViewList}
data={this.state.dataArray}
keyExtractor={this._keyExtractor}
ItemSeparatorComponent={this.ItemSeparatorComponent}
/>
ViewList = ({item}) => {
return (
<Swipeable
rightButtons={[
<TouchableOpacity
style={styles.swipeableStyle}
onPress={() => {
this._delete(item.value.id);
//这里我是把这个Item的Id发给后台,后台删除后我再重新渲染页面
}}
>
<Text style={{fontSize: 20, color: 'black'}}>删除</Text>
</TouchableOpacity>
]}
>
<View style={styles.wrap}>
//这里是具体Item的样式
</View>
</Swipeable>
4.轮播图(点击轮播图的图片可跳转):
实现方法:轮播图用到是swiper,实现点击跳转是直接在Image外加一层TouchableWithoutFeedback,然后再写点击事件就行了
下载:npm install react-native-swiper --save
导入:import Swiper from 'react-native-swiper';
实现代码:
<Swiper
style={styles.wrap2}
loop={true}//如果设置为false,那么滑动到最后一张时,再次滑动将不会展示第一张图片
autoplay={true}//设置为true,则页面可以自动轮播
autoplayTimeout={3}//设置每个页面自动滑动停留的时间
horizontal={true}//如果值为true时,那么滚动的内容将是横向排列的,而不是垂直于列中的
paginationStyle={{bottom:ScreenUtils.scaleSize(7)}}//设置页面原点的样式
dotStyle={{backgroundColor:'#E1E1E1', width:ScreenUtils.scaleSize(14), height:ScreenUtils.scaleSize(14)}}//自定义不是当前圆点的样式
activeDotStyle={{backgroundColor:'#F6D574', width:ScreenUtils.scaleSize(14), height:ScreenUtils.scaleSize(14)}}//自定义当前页面圆点的样式
>
<TouchableWithoutFeedback
onPress={()=>this.props.navigation.navigate('WebPage', {url: this.state.url1, ...this.props})}
>
<Image resizemode={'contain'} style={styles.image} source={{uri:this.state.img1}}/>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback
onPress={()=>this.props.navigation.navigate('WebPage', {url: this.state.url2, ...this.props})}
>
<Image resizemode={'contain'} style={styles.image} source={{uri:this.state.img2}}/>
</TouchableWithoutFeedback>
</Swiper>
5.文字竖向轮播,跑马灯
实现方法:用的是别人封的一个类,然后根据自己的需要写一下就行了
实现代码:先把下面这个ScrollVertical放在自己项目里面去,然后我是在我的scroll方法里面使用它的
import React, {Component} from 'react'
import {
Text,
View,
Animated,
Easing,
StyleSheet,
} from 'react-native'
//这个类直接复制进去就好
export default class ScrollVertical extends Component {
static defaultProps = {
enableAnimation: true,
};
constructor(props) {
super(props);
let translateValue= new Animated.ValueXY({x: 0, y: 0});
translateValue.addListener(({x,y})=>{
// Log('value',x,y)
});
this.state = {
translateValue: translateValue,
// 滚屏高度
scrollHeight: this.props.scrollHeight || 32,
// 滚屏内容
kb_content: [],
// Animated.View 滚动到的 y轴坐标
kb_tempValue: 0,
// 最大偏移量
kb_contentOffsetY: 0,
// 每一次滚动切换之前延迟的时间
delay: this.props.delay || 500,
// 每一次滚动切换的持续时间
duration: this.props.duration || 500,
enableAnimation: true,
}
}
render() {
return (
<View style={[styles.kbContainer, {height: this.state.scrollHeight}, this.props.kbContainer]}>
{
this.state.kb_content.length !== 0 ?
<Animated.View
style={[
{flexDirection: 'column'},
{
transform: [
{translateY: this.state.translateValue.y}
]
}
]}>
{this.state.kb_content.map(this._createKbItem.bind(this))}
</Animated.View> : null
}
</View>
)
}
componentWillReceiveProps(nextProps) {
this.setState({
enableAnimation: nextProps.enableAnimation?true:false
}, () => {
this.startAnimation();
}
)
}
componentDidMount() {
let content = this.props.data || [];
console.log("========================");
console.log(content);
if (content.length !== 0) {
let h = (content.length + 1) * this.state.scrollHeight;
this.setState({
kb_content: content.concat(content[0]),
kb_contentOffsetY: h
});
// 开始动画
// this._startAnimation()
this.startAnimation();
}
}
_createKbItem(kbItem, index) {
return (
<View key={index}
style={[{ justifyContent: 'center', height: this.state.scrollHeight}, this.props.scrollStyle]}>
<Text style={[styles.kb_text_c, this.props.textStyle]}>{kbItem.content}</Text>
</View>
)
}
startAnimation = () => {
if (this.state.enableAnimation) {
if(!this.animation){
this.animation = setTimeout(() => {
this.animation=null;
this._startAnimation();
}, this.state.delay);
}
}
};
componentWillUnmount() {
if (this.animation) {
clearTimeout(this.animation);
}
if(this.state.translateValue){
this.state.translateValue.removeAllListeners();
}
}
_startAnimation = () => {
this.state.kb_tempValue -= this.state.scrollHeight;
if (this.props.onChange) {
let index = Math.abs(this.state.kb_tempValue) / (this.state.scrollHeight);
this.props.onChange(index<this.state.kb_content.length-1?index:0);
}
Animated.sequence([
// Animated.delay(this.state.delay),
Animated.timing(
this.state.translateValue,
{
isInteraction: false,
toValue: {x: 0, y: this.state.kb_tempValue},
duration: this.state.duration, // 动画持续的时间(单位是毫秒),默认为500
easing: Easing.linear
}
),
])
.start(() => {
if (this.state.kb_tempValue - this.state.scrollHeight === -this.state.kb_contentOffsetY) {
// 快速拉回到初始状态
this.state.translateValue.setValue({x: 0, y: 0});
this.state.kb_tempValue = 0;
}
this.startAnimation();
})
}
}
const styles = StyleSheet.create({
kbContainer: {
// 必须要有一个背景或者一个border,否则本身高度将不起作用
backgroundColor: 'transparent',
overflow: 'hidden'
},
kb_text_c: {
fontSize: 18,
color: '#181818',
}
});
scroll(){
let array = [{ content: "" }];
let dataArray = this.state.kuaibaoArray;//这里是数据源
if (dataArray && dataArray.length > 0) {
array = [];
for (let item of dataArray) {
array.push({ content: item.text});
}
}
if(array[0].content !== ""&&array.length>=1){
return<ScrollVertical
onChange={(index => {
Index = index;//这个Index是个全局的
})}
enableAnimation={true}
data={array}//放入数据
delay={2500}
duration={1000}
scrollHeight={ScreenUtils.scaleSize(45)}
scrollStyle={{ alignItems: 'flex-start' }}
textStyle={{ color: 'black', fontSize:ScreenUtils.setSpText(13) }} />
}
}
6.FlatList上拉加载更多(及onEndReached触发时间不对的解决)
实现方法:对onEndReached进行监听,请求时附上页数来展示更多数据
首先实现上拉加载会出现的问题就是onEndReached不正常地调用,所以我们就要对调用这个方法的时机做一下限制,我在网上找了很久没发现解决办法,最后在github上facebook RN的关于Flatlist的issue里面发现了解决方法,可能这个解决方法不是最好的,但目前看来还是勉强能用,如果有更好的方法欢迎交流,下面上代码。
实现代码:
<FlatList
renderItem={this.ViewList}
data={this.state.dataArray}
ListFooterComponent={this._renderFooter.bind(this)}
onEndReached={()=>this._onEndReached()}//这里是滑到底执行的方法
onEndReachedThreshold={0.1}//这个的值是0到1,网上很多文章都用错了,但如果是我用错了欢迎指正
ListHeaderComponent={this._header}
refreshing={this.state.Refresh}
keyExtractor={this._keyExtractor}
//就是通过下面这几个手势监听来判定onEndReached的调用
onScrollBeginDrag={() => {
this.canAction = true;
}}
onScrollEndDrag={() => {
this.canAction = false;
}}
onMomentumScrollBegin={() => {
this.canAction = true;
}}
onMomentumScrollEnd={() => {
this.canAction = false;
}}
/>
_onEndReached(){
if(!this.canAction) return;//这里就直接拦截了不正确调用onEndReached的情况
if (this.state.showFoot !== 0){
return;
}
if ((this.state.currentPage!==1)&&(this.state.currentPage>=this.state.totalPage)){
return;
}else {
this.setState({
currentPage:this.state.currentPage+1
})
}
this.setState({showFoot:2});
this.onLoad(this.state.currentPage+1);//这里请求更多数据
}
//根据showFoot的值来判断底部显示的是什么
_renderFooter(){
if (this.state.showFoot === 1) {
return (
<View style={{height:30,alignItems:'center',justifyContent:'flex-start'}}>
<Text style={{color:'#999999',fontSize:14,marginTop:5,marginBottom:5,}}> 没有更多数据了 </Text>
</View>
);
}
else if(this.state.showFoot === 2) {
return (
<View style={styles.loading}>
<ActivityIndicator/>
<Text>Loading...</Text>
</View>
);
} else if(this.state.showFoot === 0){
return (
<View style={styles.footer}>
<Text/>
</View>
);
}
}
//这部分代码是在请求数据的时候的
let foot = 0;
if (this.state.currentPage>=page){//这个page是根据需要的分页自己算出来的
foot = 1
}
this.setState({
dataArray: this.state.dataArray.concat(datas),//这里有个小细节需要注意下,就是拼接数据用的是concat来拼接的
showFoot:foot,
});
7.浮动弹窗(Modal的使用):
实现方法:用Modal来自定义浮动弹窗,根据需要来确定Modal的显示状态
实现代码:
<Modal
visible={this.state.visible}//可见性
animationType='slide'//从下往上滑出
transparent={true}
onRequestClose={() => this.setModalVisible(false)}>
<View style={styles.modalStyle}>
//这里自定义Modal的样式
</View>
</Modal>
//在需要显示这个Modal的时候,调用下面这个方法设置true就行了
setModalVisible(visible) {
this.setState({
visible: visible
})
}
先写这么多吧,有空了再继续
本文分享了React Native应用开发中的七个实用技巧,包括如何仅在首次启动应用时显示引导页、实现启动页图片全屏显示、添加侧滑删除功能、制作可点击的轮播图、实现文字竖向滚动效果、解决FlatList上拉加载更多的问题以及使用Modal创建浮动弹窗。
1232

被折叠的 条评论
为什么被折叠?



