【问题标题】:How To Drag and Drop with Multiple View in React Native?如何在 React Native 中使用多个视图进行拖放?
【发布时间】:2018-05-13 02:01:04
【问题描述】:

我在同一位置动态添加了多个视图,还添加了每个视图的平移手势。同一位置的所有视图,以便它覆盖。我的问题是,当想要拖动最后一个视图时,它已经拖动了所有视图。怎样才能拖动单个视图。

在这里你可以看到 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:

我想要以下结果:

【问题讨论】:

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


    【解决方案1】:

    有几个地方需要修改才能使其工作。

    一步一步:

    1. 你的四个圈子各有各的立场。所以 4 Animated.ValueXY 为必填项。

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

      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();
                  }
              }
          });    
      }
      
    3. 根据上面的变化制作你的风格。移除不必要的外部视图,并阻止事件。

      {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>
      ))}
      
    4. 做保证金技巧以减少头寸计算。将top / left 更改为marginTop / marginLeft

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

    最终代码:

    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');
    
    export class App extends Component<{}> {
        constructor(props){
            super(props);
    
            this.dataDrag = [1,2,3,4];
            this.pan = this.dataDrag.map( () => new Animated.ValueXY() );
    
            this.state = {
                showDraggable   : true,
                dropZoneValues  : null,
            };
        }
    
        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();
                    }
                }
            });    
        }
    
        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.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>
                    ))}
                </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',
            marginTop         : Window.height/2 - CIRCLE_RADIUS,
            marginLeft        : Window.width/2 - CIRCLE_RADIUS,
        },
        circle      : {
            backgroundColor     : '#1abc9c',
            width               : CIRCLE_RADIUS*2,
            height              : CIRCLE_RADIUS*2,
            borderRadius        : CIRCLE_RADIUS
        },
    });
    

    结果:

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-30
    • 1970-01-01
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    • 2019-09-09
    • 1970-01-01
    • 2020-09-25
    相关资源
    最近更新 更多