前言:学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