直接从进入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 })}});
}
实现方法:设置图片的style
实现代码:
image:{
flex:1,
alignItems:'center',
justifyContent:'center',
width:null,
height:null,
}
实现方法:列表用的是FlatList,实现侧滑删除用到的了swipable,每个Item都给它在外层包裹一层swipeable,使得每个Item都是能够左滑的,然后在Swipeable中给rightButtons设置样式、点击事件,来实现侧滑删除的功能。
下载:npm install --save react-swipeable
导入:import Swipeable from 'react-native-swipeable';
实现代码:FlatList不用改,直接在renderItem上操作
ViewList = ({item}) => {
return (
{
this._delete(item.value.id);
//这里我是把这个Item的Id发给后台,后台删除后我再重新渲染页面
}}
>
删除
]}
>
//这里是具体Item的样式
实现方法:轮播图用到是swiper,实现点击跳转是直接在Image外加一层TouchableWithoutFeedback,然后再写点击事件就行了
下载:npm install react-native-swiper --save
导入:import Swiper from 'react-native-swiper';
实现代码:
this.props.navigation.navigate('WebPage', {url: this.state.url1, ...this.props})}
>
this.props.navigation.navigate('WebPage', {url: this.state.url2, ...this.props})}
>
实现方法:用的是别人封的一个类,然后根据自己的需要写一下就行了
实现代码:先把下面这个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 (
{
this.state.kb_content.length !== 0 ?
{this.state.kb_content.map(this._createKbItem.bind(this))}
: null
}
)
}
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 (
{kbItem.content}
)
}
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 {
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 {
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) }} />
}
}
实现方法:对onEndReached进行监听,请求时附上页数来展示更多数据
首先实现上拉加载会出现的问题就是onEndReached不正常地调用,所以我们就要对调用这个方法的时机做一下限制,我在网上找了很久没发现解决办法,最后在github上facebook RN的关于Flatlist的issue里面发现了解决方法,可能这个解决方法不是最好的,但目前看来还是勉强能用,如果有更好的方法欢迎交流,下面上代码。
实现代码:
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 (
没有更多数据了
);
}
else if(this.state.showFoot === 2) {
return (
Loading...
);
} else if(this.state.showFoot === 0){
return (
);
}
}
//这部分代码是在请求数据的时候的
let foot = 0;
if (this.state.currentPage>=page){//这个page是根据需要的分页自己算出来的
foot = 1
}
this.setState({
dataArray: this.state.dataArray.concat(datas),//这里有个小细节需要注意下,就是拼接数据用的是concat来拼接的
showFoot:foot,
});
实现方法:用Modal来自定义浮动弹窗,根据需要来确定Modal的显示状态
实现代码:
this.setModalVisible(false)}>
//这里自定义Modal的样式
//在需要显示这个Modal的时候,调用下面这个方法设置true就行了
setModalVisible(visible) {
this.setState({
visible: visible
})
}
先写这么多吧,有空了再继续