如何在React Native中使用多个视图进行拖放?

时间:2017-11-29 11:13:55

标签: reactjs react-native react-native-android react-native-ios

我已经在动态相同位置添加了多个视图,还添加了每个视图的pan Gesture。所有视图都在同一位置,以便覆盖。我的问题是,当想要拖动最后一个视图时,它会拖动所有视图。如何拖动单个视图。

在这里你可以看到GIF中的所有视图。 View1,View 2和View 3.所有都是拖动。我想只查看3是可拖动的,其他拖动完成拖3后。

1。拖动3 - 首先拖动。

2。拖动2 - 第二次拖动。

第3。拖动1 - 第三次拖动。

代码:

import React, { Component } from 'react';
import {
  StyleSheet,
  View,
  Text,
  PanResponder,
  Animated,
  Easing,
  Dimensions,
  Platform,
  TouchableOpacity,
} from 'react-native';

let CIRCLE_RADIUS = 36;
let Window = Dimensions.get('window');
const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' +
    'Cmd+D or shake for dev menu',
  android: 'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
});

export default class App extends Component<{}> {
  constructor(props){
    super(props);

    this.state = {
        showDraggable   : true,
        dropZoneValues  : null,
        pan             : new Animated.ValueXY(),
        dataDrag        : [1,2,3,4],
    };

    this.panResponder = PanResponder.create({
        onStartShouldSetPanResponder    : () => true,
        onPanResponderMove              : Animated.event([null,{
            dx  : this.state.pan.x,
            dy  : this.state.pan.y
        }]),
        onPanResponderRelease           : (e, gesture) => {
            if(this.isDropZone(gesture)){
                this.setState({
                    showDraggable : false
                });
            }else{
                Animated.spring(
                    this.state.pan,
                    {toValue:{x:0,y:0}}
                ).start();
            }
        }
    });
}

isDropZone(gesture){
    var dz = this.state.dropZoneValues;
    return gesture.moveY > dz.y && gesture.moveY < dz.y + dz.height;
}

setDropZoneValues(event){
    this.setState({
        dropZoneValues : event.nativeEvent.layout
    });
}

render(){
    return (
        <View style={styles.mainContainer}>
            <View
                onLayout={this.setDropZoneValues.bind(this)}
                style={styles.dropZone}>
                <Text style={styles.text}>Drop me here!</Text>
            </View>

            {this.state.dataDrag.map((d, index) => (
              <View key = {index} style={styles.draggableContainer}>
                  <Animated.View
                      {...this.panResponder.panHandlers}
                      style={[this.state.pan.getLayout(), styles.circle]}>
                      <Text style={styles.text}>Drag {index}</Text>
                  </Animated.View>
              </View>
            ))}


        </View>
    );
}

renderDraggable(){
    //if(this.state.showDraggable){
        return (
            <View style={styles.draggableContainer}>
                <Animated.View
                    {...this.panResponder.panHandlers}
                    style={[this.state.pan.getLayout(), styles.circle]}>
                    <Text style={styles.text}>Drag me!</Text>
                </Animated.View>
            </View>
        );
    //}
  }
}

let styles = StyleSheet.create({
    mainContainer: {
        flex    : 1
    },
    dropZone    : {
        height  : 100,
        backgroundColor:'#2c3e50'
    },
    text        : {
        marginTop   : 25,
        marginLeft  : 5,
        marginRight : 5,
        textAlign   : 'center',
        color       : '#fff'
    },
    draggableContainer: {
        position    : 'absolute',
        top         : Window.height/2 - CIRCLE_RADIUS,
        left        : Window.width/2 - CIRCLE_RADIUS,
    },
    circle      : {
        backgroundColor     : '#1abc9c',
        width               : CIRCLE_RADIUS*2,
        height              : CIRCLE_RADIUS*2,
        borderRadius        : CIRCLE_RADIUS
    },
});

GIF:

enter image description here

我想低于结果:

enter image description here

1 个答案:

答案 0 :(得分:6)

有几个地方需要修改以使其有效。

一步一步:

  1. 您的四个圈子拥有自己的位置。所以4 <{1}}是必需的。

    Animated.ValueXY
  2. 您的this.dataDrag = [1,2,3,4]; this.pan = this.dataDrag.map( () => new Animated.ValueXY() ); 需要当前索引中的信息。把它拉出来 返回函数的函数,包括PanResponder的信息。

    index
  3. 根据上述变化制作你的风格。删除外部视图,这是不必要的,也会阻止事件。

    getPanResponder(index) {
        return PanResponder.create({
            onStartShouldSetPanResponder: () => true,
            onPanResponderMove: Animated.event([null,{
                dx: this.pan[index].x,
                dy: this.pan[index].y
            }]),
            onPanResponderRelease : (e, gesture) => {
                if(this.isDropZone(gesture)){
                    this.setState({
                        showDraggable : false
                    });
                }else{
                    Animated.spring(
                        this.pan[index],
                        {toValue:{x:0,y:0}}
                    ).start();
                }
            }
        });    
    }
    
  4. 利用边际技巧来减少位置计算。将{this.dataDrag.map((d, index) => ( <Animated.View key={index} {...this.getPanResponder(index).panHandlers} style={[styles.draggableContainer, this.pan[index].getLayout(), styles.circle]}> <Text style={styles.text}>Drag {index}</Text> </Animated.View> ))} 更改为top / left

    marginTop / marginLeft
  5. 最终代码:

    draggableContainer: {
        position    : 'absolute',
        marginTop   : Window.height/2 - CIRCLE_RADIUS,
        marginLeft  : Window.width/2 - CIRCLE_RADIUS,
    },
    

    结果:

    enter image description here