2016-11-06 79 views
4

我已經實現了用panResponder和ScrollView拖拽拖放列表。我希望即使在觸摸該項目時也能夠滾動列表。問題在於,當我做手勢滾動時,項目會移動。當然,我也希望能夠移動該項目,但現在它具有與滾動相同的手勢。我想通過只在長時間按下(1.5秒)後拖動元素來克服它。如何實現它?我想使用觸摸作爲onPressIn/onPressOut的元素,就像這裏所述:http://browniefed.com/blog/react-native-press-and-hold-button-actions/ 並以某種方式在時間段後啓用panResponder,但我不知道如何以編程方式啓用它。啓用長按後在滾動視圖中拖動元素

現在這是我在列表元素代碼:

class AccountItem extends Component { 

    constructor(props) { 
    super(props); 
    this.state = { 
     pan: new Animated.ValueXY(), 
     zIndex: 0, 
    } 

    this.panResponder = PanResponder.create({ 
     onStartShouldSetPanResponder:() => true, 
     onPanResponderGrant: (e, gestureState) => { 
     this.setState({ zIndex: 100 }); 
     this.props.disableScroll(); 
     }, 
     onPanResponderMove: Animated.event([null, { 
     dx: this.state.pan.x, 
     dy: this.state.pan.y, 
     }]), 
     onPanResponderRelease: (e, gesture) => { 
     this.props.submitNewPositions(); 
     Animated.spring(
      this.state.pan, 
      {toValue:{ x:0, y:0 }} 
     ).start(); 
     this.setState({ zIndex: 0 }); 
     this.props.enableScroll(); 
     } 
    }) 
    } 

    meassureMyComponent = (event) => { 
    const { setElementPosition } = this.props; 
    let posY = event.nativeEvent.layout.y; 
    setElementPosition(posY); 
    } 

    render() { 
    const {name, index, onChangeText, onRemoveAccount} = this.props; 

    return (
     <Animated.View 
      style={[this.state.pan.getLayout(), styles.container, {zIndex: this.state.zIndex}]} 
      {...this.panResponder.panHandlers} 
      onLayout={this.meassureMyComponent} 
     > 

some other components... 

     </Animated.View> 
    ) 
    } 
} 

export default AccountItem; 
+0

對於Android,請務必在'PanResponder'上設置'onShouldBlockNativeResponder'返回'false',否則如果您觸摸PanResponder對象,滾動將無法正常工作。根據:https://facebook.github.io/react-native/docs/panresponder.html –

回答

2

我跟你遇到同樣的問題釋放手勢(如onPanResponderTerminate等)的所有案件。我的解決方案是爲onLongPress定義2個不同的panResponder處理程序和正常行爲。

_onLongPressPanResponder(){ 
    return PanResponder.create({ 
     onPanResponderTerminationRequest:() => false, 
     onStartShouldSetPanResponderCapture:() => true, 
     onPanResponderMove: Animated.event([ 
     null, {dx: this.state.pan.x, dy: this.state.pan.y}, 
     ]), 
     onPanResponderRelease: (e, {vx, vy}) => { 
     this.state.pan.flattenOffset() 
     Animated.spring(this.state.pan, {   //This will make the draggable card back to its original position 
      toValue: 0 
     }).start(); 
     this.setState({panResponder: undefined}) //Clear panResponder when user release on long press 
     } 
    }) 
    } 

    _normalPanResponder(){ 
    return PanResponder.create({ 
     onPanResponderTerminationRequest:() => false, 
     onStartShouldSetPanResponderCapture:() => true, 
     onPanResponderGrant: (e, gestureState) => { 
     this.state.pan.setOffset({x: this.state.pan.x._value, y: this.state.pan.y._value}); 
     this.state.pan.setValue({x: 0, y: 0}) 
     this.longPressTimer=setTimeout(this._onLongPress, 400) // this is where you trigger the onlongpress panResponder handler 
     }, 
     onPanResponderRelease: (e, {vx, vy}) => { 
     if (!this.state.panResponder) { 
      clearTimeout(this.longPressTimer); // clean the timeout handler 
     } 
     } 
    }) 
    } 

定義您_onLongPress功能:

_onLongPress(){ 
    // you can add some animation effect here as wll 
    this.setState({panResponder: this._onLongPressPanResponder()}) 
    } 

定義構造函數:

constructor(props){ 
    super(props) 
    this.state = { 
     pan: new Animated.ValueXY() 
    }; 
    this._onLongPress = this._onLongPress.bind(this) 
    this._onLongPressPanResponder = this._onLongPressPanResponder.bind(this) 
    this._normalPanResponder = this._normalPanResponder.bind(this) 
    this.longPressTimer = null 
    } 

最後,在渲染之前,您應該根據狀態切換到不同的panResponder處理程序:

let panHandlers = {} 
    if(this.state.panResponder){ 
     panHandlers = this.state.panResponder.panHandlers 
    }else{ 
     panHandlers = this._normalPanResponder().panHandlers 
    } 

然後將panHandlers附加到您的視圖{...panHandlers} 您甚至可以更改不同panHandlers的css以顯示不同的效果。

0

如果你唯一的問題是,滾動型移動滾動項目時,那我就乾脆建議禁用父的滾動的運動週期。 像:

//component with ScrollView: 
... 
constructor() { 
    super() 
    this.state = {scrolling: true} 
    this.enableScroll = this.enableScroll.bind(this) 
    this.disableScroll = this.disableScroll.bind(this) 
} 

// inject those methods into Drag&Drop item as props: 
enableScroll() { 
    this.setState({scrolling: true}) 
} 
disableScroll() { 
    this.setState({scrolling: false}) 
} 

... 
<ScrollView scrollEnabled={this.state.scrolling} ... /> 
... 

//component with drag&drop item: 
... 
onPanResponderGrant() { 
    ... 
    this.props.disableScroll() 
    ... 
} 
onPanResponderRelease() { 
    this.props.enableScroll() 
} 

確保覆蓋

+0

實際上首先我需要列表滾動,因爲列表可以很大,超出屏幕,所以當我想要隨着姿勢下降,物品會移動(在這種情況下我想避免的)。所以我需要區分列表滾動和實際項目移動之間的意圖。 –

+0

和你的建議已經實現:) –

相關問題