React-native 实现表情商城 表情长按拖动预览(还原安卓微信效果)

前端之家收集整理的这篇文章主要介绍了React-native 实现表情商城 表情长按拖动预览(还原安卓微信效果)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

RN 简单的触摸监听已经无法满足这个需求,所以 引入 手势监听(handler)

代码

handler定义:

let _this = this;
		let handlers = {
			onStartShouldSetResponder: () => true,onMoveShouldSetResponder: () => true,onResponderTerminationRequest: () => false,onResponderStart: () => {
				console.log('start')
				console.log(_this.props._isScrollIng)
				clearTimeout(_this.longTimer);
				_this.longTimer = setTimeout(() => {
					if (!_this.props._isScrollIng) {
						this.setState({
							clickStatus: true,})
						_this.props._onLongPress()
						_this.props._getLocationNow(_this.props.id,0)
					}
				},300);// 300 ms 之后触发长按

			},onResponderMove: (evt) => {
				console.log('move')
				console.log(_this.props._isScrollIng)
				console.log(evt.nativeEvent.locationX)
				console.log(evt.nativeEvent.locationY)
				console.log(_this.props.id)
				if (!_this.props._isScrollIng && this.state.clickStatus) { // 条件:屏幕不滚动,触发长按 
					_this.props._getLocationNow(_this.props.id,evt.nativeEvent.locationX,evt.nativeEvent.locationY)//根据当前触发的handle对象,以及点击坐标与其相对位置,判断当前所处view
				}
			},onResponderRelease: () => {
				console.log(_this.props._isScrollIng)
				console.log('release')
				clearTimeout(_this.longTimer);
				this.setState({
					clickStatus: false,})
				_this.props._toggleIsActive();//让scrollView重新可以滚动,并且把屏幕滚动状态设置为false(针对短点表情触发的屏幕滚动结束)
				_this.props._onRefreshPreView();//让最后一个预览表情,离开预览状态
			},};

handler 使用:
<View
				{...handlers}
				style={[{
					width: iconWidth,height: iconWidth,},styles.iconWrap]}> </View>


表情Sticker组件的使用(自定义的,都有注释):

	if (this.state.stickerArr.pagInfo) {
			this.state.iconObj.forEach((v,k) => {
				Icons.push((
					<Sticker
						key={k}
						id = {k} //每个表情有自己的id标记
						index_touch = {this.state.nowTouchIndex} //当前手势所处view的id
						animateIconUrl = {v}
						iconUrl = {this.state.gifObj[k]}
						_toggleIsActive={this._toggleIsActive.bind(this) } //手势释放,触发的方法定义在上层界面
						_onLongPress = {this._onLongPress.bind(this) } //触发长按的方法,定义在上层界面
						_getLocationNow = {this._onGetLocationNow.bind(this) } //获取当前手势坐标方法,定义在上层界面
						_onRefreshPreView = {this._onRefreshPreview.bind(this) } //重置最后一个预览状态的表情方法,,定义在上层界面
						_isScrollIng = {this.state.scrollIng} //当前界面是否在滚动状态
						/>
				));
			})
		}



通过触发handler的id,及手势移动与其的相对偏移量,算出当前手势所在view:

上位置判断算法:

_onGetLocationNow(id,offsetX,offsetY) {
		let screenWidth = Dimensions.get('window').width;
		let iconWidth = (screenWidth - 5 * TAP) / 4;
		let row = 0;
		let col = 0;
		let index = undefined;
		let offsetXAbs = Math.abs(offsetX);
		let offsetYAbs = Math.abs(offsetY);
		if (offsetX <= iconWidth + TAP / 2 && offsetX >= 0 && offsetY <= iconWidth && offsetY >= 0) {
			index = id;
		} else {
			col = Math.ceil((offsetXAbs) / (iconWidth + TAP / 2)) - 1;
			row = Math.ceil((offsetYAbs) / (iconWidth)) - 1;
			console.log('row_1:' + row);
			if (offsetX < 0) {
				col = 0 - (col + 1);
			}
			if (offsetY < 0) {
				row = 0 - (row + 1);
			}
		}

		console.log('col_1:' + col);
		console.log('row_2:' + row);
		let rangetimes = Math.ceil((id + 1) / 4); // 超出范围判定
		if (col >= 0 && (col + id) >= rangetimes * 4 - 1) {
			col = rangetimes * 4 - 1 - id;
		} else {
			if (col < 0 && (id + col) <= (rangetimes - 1) * 4) {
				col = 0 - (id - (rangetimes - 1) * 4);
			}
		}
		console.log('col_2:' + col);
		console.log('row_3:' + row);
		index = id + row * 4 + col;

		if (index < 0 || index >= this.state.iconObj.length) {
			index = undefined;
		}
		console.log('index:' + index);
		console.log('col:' + col);
		this.setState({
			nowTouchIndex: index,})
	}

触发长按要屏蔽上层scrollView的滚动以及滚动要屏蔽view的触发长按:

这里代码杂:说个里面有的一个坑,就是scrollView 滚动结束 并不会调用onAnimatedScrollEnd(文档上说调用),想监听这个事件用:onMomentumScrollEnd


差不多了,全套代码肯定是没有的,毕竟是项目,大概理解下,想深入交流就加一下群:429307812

------- 我是小尾巴

原文链接:https://www.f2er.com/react/305600.html

猜你在找的React相关文章