this.panResponder = PanResponder.create({
/***************** 要求成為響應(yīng)者 *****************/
// 單機(jī)手勢是否可以成為響應(yīng)者
onStartShouldSetPanResponder: (evt, gestureState) => true,
// 移動手勢是否可以成為響應(yīng)者
onMoveShouldSetPanResponder: (evt, gestureState) => true,
// 攔截子組件的單擊手勢傳遞,是否攔截
onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
// 攔截子組件的移動手勢傳遞,是否攔截
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
/***************** 響應(yīng)者事件回調(diào)處理 *****************/
// 單擊手勢監(jiān)聽回調(diào)
onPanResponderGrant: (e, gestureState) => {
console.log('onPanResponderGrant==>' + '單擊手勢申請成功,開始處理手勢');
this._onPanResponderGrant(e);
},
// 移動手勢監(jiān)聽回調(diào)
onPanResponderMove: throttle((e, gestureState) => {
console.log('onPanResponderMove==>' + '移動手勢申請成功,開始處理手勢' + `${gestureState}`);
this._onPanResponderMove(e, gestureState);
}, 200),
// 手勢動作結(jié)束回調(diào)
onPanResponderEnd: (evt, gestureState) => {
console.log('onPanResponderEnd==>' + '手勢操作完成了,用戶離開');
this._onPanResponderEnd(evt);
},
// 手勢釋放, 響應(yīng)者釋放回調(diào)
onPanResponderRelease: (e, gestureState) => {
// 用戶放開了所有的觸摸點(diǎn),且此時(shí)視圖已經(jīng)成為了響應(yīng)者。
// 一般來說這意味著一個(gè)手勢操作已經(jīng)成功完成。
this._onPanResponderRelease(e, gestureState);
console.log('onPanResponderRelease==>' + '放開了觸摸,手勢結(jié)束');
},
// 手勢申請失敗,未成為響應(yīng)者的回調(diào)
onResponderReject: (e, gestureState) => {
// 申請失敗,其他組件未釋放響應(yīng)者
console.log('onResponderReject==>' + '響應(yīng)者申請失敗');
this._onPanResponderRelease(e, gestureState);
},
// 當(dāng)前手勢被強(qiáng)制取消的回調(diào)
onPanResponderTerminate: e => {
// 另一個(gè)組件已經(jīng)成為了新的響應(yīng)者,所以當(dāng)前手勢將被取消
console.log('onPanResponderTerminate==>' + '由于某些原因(系統(tǒng)等),所以當(dāng)前手勢將被取消');
return true;
},
onShouldBlockNativeResponder: (evt, gestureState) => {
return true;
}
});
需求是多個(gè)可以拖拽的對象所以需要知道每次是拖拽哪個(gè),而調(diào)用方法需要用 {...this.panResponder.panHandlers}解構(gòu)之后得到的json通過props傳遞給組件,使得組件變成響應(yīng)者,打印{...this.panResponder.panHandlers}
[圖片上傳失敗...(image-3e7074-1580929245556)]
多個(gè)拖拽就不能知道是哪個(gè)變成了響應(yīng)者
- 不用解構(gòu),給View綁定事件,傳遞index
Animated.View綁定事件,如
<Animated.View
onResponderMove={(nativeEvent, gestureState) => this.onResponderMove(index, nativeEvent, gestureState}
>
將index作為參數(shù)傳遞過去就知道是哪項(xiàng)作為了響應(yīng)者,但是,參數(shù)中g(shù)estureState是undefined
[圖片上傳失敗...(image-5cb757-1580929245556)]
官網(wǎng)中說:它提供了一個(gè)對觸摸響應(yīng)系統(tǒng)響應(yīng)器的可預(yù)測的包裝。對于每一個(gè)處理函數(shù),它在原生事件之外提供了一個(gè)新的gestureState對象。
所以不用PanResponder.create得不到gestureState對象
2.通過重寫解構(gòu)出來的{...this.panResponder}后的onResponderGrant將index放到state中
List.map(li => (
<Animated.View
style={styles.scheduleMoveImgView}
{...this.panResponder.panHandlers}
onResponderGrant={e => {
this.touchY = e.nativeEvent.locationY - 12;
this.initHeight = ((li.end - li.start) / 1800) * initOneHeight;
this.dragItem = li;
this.setState({
isMove: true,
movingHeight: this.initHeight,
dragIndex: index
});
}}
>
</Animated.View>
))
項(xiàng)目中使用了第二種方法,因?yàn)橥献r(shí)需要得到gestureState對象
[站外圖片上傳中...(image-ff863f-1580929245556)]
<ScrollView
style={{ flex: 1 }}
scrollEnabled={!isMove}
ref={view => {
this.areaScrollView = view;
}}
>
<View style={styles.scheduleList}>
{
scheduleList.map((li, index) => ())
}
</View>
<View style={styles.lineWrap}>
{
scheduleList.map((li, index) => ())
}
</View>
<View style={styles.scheduleSelectList}>
{
scheduleSelectList.map((li, index) => ())
}
</View>
</ScrollView>
ScrollView的children有3個(gè)View,scheduleList是0-24小時(shí)的間距,lineWrap是今天線,絕對定位,scheduleSelectList是選中的時(shí)間段,絕對定位。
android中的坑
[圖片上傳失敗...(image-8bd84e-1580929245556)]
[圖片上傳失敗...(image-d90c41-1580929245556)]
在android里面只有1/4的區(qū)域能夠點(diǎn)擊,ios沒事,截圖中綠色和黃色的交界處才能點(diǎn)擊。原來只有圖標(biāo)能點(diǎn)擊(圓圈灰色X,2424),在手機(jī)中點(diǎn)擊體驗(yàn)不好,改成黃色區(qū)域能夠點(diǎn)擊(5050),因?yàn)辄S色刪除按鈕和拖動按鈕都是絕對定位,通過拖動,動態(tài)設(shè)置box(藍(lán)色區(qū)域)的height。
box{
position: 'absolute',
top,
height
}
藍(lán)色區(qū)域外的區(qū)域點(diǎn)擊在android中無效
解決方案
<View> // 青色區(qū)域,top - 25, 高度 + 50
<View></View> // 內(nèi)部邊框區(qū)域 margin 25
</View>
[圖片上傳失敗...(image-6670c6-1580929245556)]
這個(gè)時(shí)候,按鈕就在區(qū)域內(nèi)了,可以點(diǎn)擊按鈕全部位置了
接下來就遇到第二個(gè)問題
2個(gè)box之間間隔一個(gè)區(qū)域,這個(gè)時(shí)候就不能選擇這個(gè)區(qū)域了,2個(gè)box區(qū)域重疊,上面一個(gè)box的高度向下25,下面一個(gè)box的top向上25,中間的一個(gè)區(qū)域不能點(diǎn)擊
設(shè)置區(qū)域position: 'absolute', zIndex: 100會導(dǎo)致按鈕的3/4能點(diǎn)擊,左下角1/4不能點(diǎn)擊問題
[圖片上傳失敗...(image-11774f-1580929245556)]
解決方案
<View> // 一塊區(qū)域
<View></View> // 不定位
<View></View> // 定位(寬度80%)
</View>
解決之后
[圖片上傳失敗...(image-7bd580-1580929245556)]
紅色區(qū)域在andriod能點(diǎn)擊選中
但是在ios中紅色區(qū)域是在青色的內(nèi)部(心中感到ios和anroid都有不同的渲染機(jī)制,都有坑),只有設(shè)置外層的View的zIndex: 100大于青色區(qū)域才行,ios中內(nèi)部View的zIndex是在外層zIndex 的基礎(chǔ)上的。所以方案失敗。(如果設(shè)置外面的View的zIndex: 100,就不能設(shè)置width: 80%, 因?yàn)槊總€(gè)區(qū)域都有一個(gè)下邊框,80%的話下邊框的長度也變成了80%了,可以通過設(shè)置內(nèi)部的View的width為Dimensions.get('window').width*0.8 這時(shí)候的下邊框就是一樣了,最終沒采用這種方案)
最終方案
通過設(shè)置 scheduleList.map((li, index) => ()) 生成不同時(shí)間段的高為0.5的下邊框(絕對定位), 內(nèi)部View展示為80%,效果就是上圖一樣了
rn的體驗(yàn)等級,能用,湊合,流暢,絲滑