一个完整的RN项目总结

直接从进入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上操作


ViewList = ({item}) => {
            return (
                 {
                                this._delete(item.value.id);
                                //这里我是把这个Item的Id发给后台,后台删除后我再重新渲染页面
                            }}
                        >
                            删除
                        
                    ]}
                >
                    
                        //这里是具体Item的样式
                    
                

4.轮播图(点击轮播图的图片可跳转):

实现方法:轮播图用到是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})}
                        >
                            
                        
                    

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 (
            
                {
                    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) }} />
        }
    }

6.FlatList上拉加载更多(及onEndReached触发时间不对的解决)

实现方法:对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,
                });

7.浮动弹窗(Modal的使用):

实现方法:用Modal来自定义浮动弹窗,根据需要来确定Modal的显示状态

实现代码:

 this.setModalVisible(false)}>
                    
                        //这里自定义Modal的样式
                    
                
//在需要显示这个Modal的时候,调用下面这个方法设置true就行了
setModalVisible(visible) {
        this.setState({
            visible: visible
        })
    }

先写这么多吧,有空了再继续

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(一个完整的RN项目总结)