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, 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 

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值