React Native指示器view(简单、高效)

前言:学rn已经一段时间了,还处于入门阶段(好尴尬!),从开始的不懂到后面能敲出点东西的时候,觉得好激动,也为自己点个赞,继续努力!

无意中在别人的项目中看到了一个view的方法:

setNativeProps()

然后习惯性的搜索了一下仿佛发现了新大陆一样:

setNativeProps 方法可以理解为web的直接修改dom。使用该方法修改 View 、 Text 等 RN自带的组件 ,则不会触发组件的 componentWillReceiveProps 、 shouldComponentUpdate 、 componentWillUpdate 等组件生命周期中的方法。

建议频繁更新的操作,如slider、tabs切换等拖曳操作时,使用 setNativeProps 来更新属性,会获得意想不到的性能体验。

me.refs.tabView.setNativeProps({
                style : {
                    height : 0,
                    opacity : 0
                }
            });

利用java面向对象的解释也就是说,我们可以拿到一个view的对象,然后直接修改对象中的一些属性,哇哦~!! 原来可以这样,先看一下我们今天要实现的一个自定义view效果:
这里写图片描述

上面的菜单是一个scrollview,然后下面的指示器view是随着scrollview的滑动改变而改变。

以前的实现思路是这样的:
1、监听scrollview的onscroll方法。
2、定义一个state,然后动态的改变state。
3、根据state的变化重新执行render,改变指示器view中的被选中view的translatex的值。

这样做的缺点:
由于不断的执行onscroll方法更新state,然后view会不断的执行render方法,虽说现在的手机已经很强大了,但是效率上很低,如果开的程序多一点,你感觉有丝丝的卡顿。

现在的思路:
1、监听scrollview的onscroll方法。
2、获取被选中原点view的引用。
3、通过onscroll改变,获取水平方向滑动的距离,然后通过调用view的setNativeProps方法,动态的改变view的style属性。

这样我们就不需要频繁的去执行render方法,效率自然就高了~!!

代码很简单,搞过rn的都看得懂哈(我简单的封装了一下),使用方法:

1、引入IndicatorView

import IndicatorView from '../IndicatorView';

2、获取IndicatorView的引用

return (
            <IndicatorView
                ref={(ref)=>this.indicator=ref}
                count={this.props.datas.length}
                position={this.currIndicator}
                selectedColor='orange'
                unselectColor='gray'
            />
        );

3、调用IndicatorView的setCurrPage方法即可

 onIndicatorScroll(event) {
        let offsetX = event.nativeEvent.contentOffset.x;
        let nextPage = offsetX / event.nativeEvent.layoutMeasurement.width;
        this.currIndicator = nextPage;
        if (this.indicator != null) {
            this.indicator.setCurrPage(nextPage);
        }
    }

**注意:nextPage是一个浮点类型,当然你也可以传一个整型(小圆点就不会有跟随的效果)
ios中如果是监听scrollview的滚动的话,记得加上下面属性**

scrollEventThrottle={50}

scrollEventThrottle表示调用scrollview的频率,越小频率越高。

view所有代码:

IndicatorView.js:

/**
 * @author YASIN
 * @version [Android YASIN V01, ]
 * @blog http://blog.csdn.net/vv_bug
 * @description 指示器view
 */
import React,{Component,PropTypes}from 'react';
import {
    View,
    StyleSheet
}from 'react-native';
import * as ScreenUtils from '../../Util/ScreenUtil';
const INDICATOR_LEFT = 8;
const INDICATOR_WIDTH = 12;
export default class IndicatorView extends Component {
    static propTypes = {
        count: PropTypes.number.isRequired,
        position: PropTypes.number.isRequired,
        selectedColor:PropTypes.string,
        unselectColor:PropTypes.string,
        selectedStyle:View.propTypes.style,
        unselectStyle:View.propTypes.style
    }
    static defaultProps = {
        position: 0,
        unselectColor:'black',
        selectedColor:'red',
    }
    // 构造
    constructor(props) {
        super(props);
        this.currIndicator = this.props.position;
    }

    renderSecondView(index){
        let style = [this.props.unselectStyle?this.props.unselectStyle:styles.circle];
        if (index != 0) {
            style.push({marginLeft: ScreenUtils.scaleSize(INDICATOR_LEFT)});
        }
        style.push({backgroundColor:this.props.unselectColor});
        return (
            <View
                key={index}
                style={style}
            />
        );
    }
    renderView(){
        let views=[];
        for (var index = 0; index< this.props.count; index++) {
            views.push(this.renderSecondView(index));
        }
        return views;
    }

    render() {
        let self = this;
        let translateX = self._computeOffset();
        return (
            <View
                style={styles.indicatorStyle}
            >
                {this.renderView()}
                <View
                    ref={(ref)=>this.indicatorBall=ref}
                    style={[
                        this.props.selectedStyle?this.props.selectedStyle:styles.circleIndicator,
                        {
                            transform:[
                                {
                                    translateX:-translateX
                                }
                            ],
                            backgroundColor: this.props.selectedColor
                        }
                    ]}
                />
            </View>
        );
    }

    setCurrPage(nextPage:number) {
        this.currIndicator = nextPage;
        let translateX = this._computeOffset();
        if (this.indicatorBall != null) {
            this.indicatorBall.setNativeProps({
                style: {
                    transform: [
                        {
                            translateX: -translateX
                        }
                    ]
                }
            });
        }
    }
    _computeOffset() {
        let count = this.props.count;
        let translateX = (count - this.currIndicator) * ScreenUtils.scaleSize(INDICATOR_WIDTH) + (count - this.currIndicator - 1) * ScreenUtils.scaleSize(INDICATOR_LEFT);
        return translateX;
    }
}
const styles = StyleSheet.create({
    indicatorStyle: {
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'center',
        padding: ScreenUtils.scaleSize(5),
    },
    circle: {
        width: ScreenUtils.scaleSize(INDICATOR_WIDTH),
        height: ScreenUtils.scaleSize(INDICATOR_WIDTH),
        borderRadius: ScreenUtils.scaleSize(INDICATOR_WIDTH / 2),
        backgroundColor: 'gray'
    },
    circleIndicator: {
        width: ScreenUtils.scaleSize(INDICATOR_WIDTH),
        height: ScreenUtils.scaleSize(INDICATOR_WIDTH),
        borderRadius: ScreenUtils.scaleSize(INDICATOR_WIDTH / 2),
        backgroundColor: 'red'
    },
});

ScreenUtil.js:

/**
 * @author YASIN
 * @version [Android YASIN V01, ]
 * @blog http://blog.csdn.net/vv_bug
 * @description
 * 屏幕工具类
 * ui设计基准,iphone 6
 * width:750
 * height:1334
 */
import {
    PixelRatio,
}from 'react-native';
import Dimensions from 'Dimensions';
export var screenW = Dimensions.get('window').width;
export var screenH = Dimensions.get('window').height;
var fontScale = PixelRatio.getFontScale();
export var pixelRatio =PixelRatio.get();

export const DEFAULT_DENSITY=2;
const w2 = 750/DEFAULT_DENSITY;
const h2 = 1334/DEFAULT_DENSITY;

export function setSpText(size:Number) {
    var scaleWidth = screenW / w2;
    var scaleHeight = screenH / h2;
    var scale = Math.min(scaleWidth, scaleHeight);
    size = Math.round((size * scale + 0.5) * pixelRatio / fontScale);
    return size;
}
/**
 * 屏幕适配,缩放size
 * @param size
 * @returns {Number}
 * @constructor
 */
export function scaleSize(size:Number) {
    var scaleWidth = screenW / w2;
    var scaleHeight = screenH / h2;
    var scale = Math.min(scaleWidth, scaleHeight);
    size = Math.round((size * scale + 0.5));
    return size/DEFAULT_DENSITY;
}

项目github链接:
https://github.com/913453448/IndicatorView

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值