iOS 中的基本拖放

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4707858/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:33:15  来源:igfitidea点击:

Basic Drag and Drop in iOS

iphoneipadiosdrag-and-droptouch

提问by Luke

I want to have a view in which there are vehicles driving around that the user can also drag and drop. What do you think is the best large-scale strategy for doing this? Is it best to get touch events from the views representing the vehicles, or from the larger view? Is there a simple paradigm you've used for drag and drop that you're satisfied with? What are the drawbacks of different strategies?

我想要一个视图,其中有车辆行驶,用户也可以拖放。您认为这样做的最佳大规模策略是什么?最好从代表车辆的视图还是从更大的视图中获取触摸事件?是否有一个您对拖放使用的简单范例令您满意?不同策略的缺点是什么?

回答by ohho

Assume you have a UIViewscene with a background image and many vehicles, you may define each new vehicle as a UIButton(UIImageView will probably work too):

假设您有一个UIView带有背景图像和许多的场景vehicles,您可以将每辆新车定义为一个UIButton(UIImageView 可能也可以工作):

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(imageTouch:withEvent:) forControlEvents:UIControlEventTouchDown];
[button addTarget:self action:@selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[button setImage:[UIImage imageNamed:@"vehicle.png"] forState:UIControlStateNormal];
[self.view addSubview:button];

Then you may move the vehicle wherever you want, by responding to the UIControlEventTouchDragInsideevent, e.g.:

然后您可以通过响应UIControlEventTouchDragInside事件将车辆移动到您想要的任何地方,例如:

- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event
{
    CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
    UIControl *control = sender;
    control.center = point;
}

It's a lot easier for individual vehicle to handle its own drags, comparing to manage the scene as a whole.

与管理整个场景相比,单个车辆处理自己的阻力要容易得多。

回答by JakubKnejzlik

In addition to ohho's answer I've tried similar implementation, but without problem of "fast" drag and centering to drag.

除了 ohho 的回答之外,我还尝试了类似的实现,但没有“快速”拖动和居中拖动的问题。

The button initialization is...

按钮初始化是...

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[button addTarget:self action:@selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragOutside];
[button setImage:[UIImage imageNamed:@"vehicle.png"] forState:UIControlStateNormal];
[self.view addSubview:button];

and method implementation:

和方法实现:

- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event
{
    UIControl *control = sender;

    UITouch *t = [[event allTouches] anyObject];
    CGPoint pPrev = [t previousLocationInView:control];
    CGPoint p = [t locationInView:control];

    CGPoint center = control.center;
    center.x += p.x - pPrev.x;
    center.y += p.y - pPrev.y;
    control.center = center;
}

I don't say, that this is the perfect solution for the answer. Nevertheless I found this the easiest solution for dragging.

我不是说,这是答案的完美解决方案。尽管如此,我发现这是最简单的拖动解决方案。

回答by jeyben

I had a case where I would like to drag/drop uiviews between multiple other uiviews. In that case I found the best solution to trace the pan events in a super view containing all the drop zones and all the drag gable objects. The primary reason for NOT adding the event listeners to the actual dragged views was that I lost the ongoing pan events as soon as I changed superview for the dragged view.

我有一个案例,我想在多个其他 uiviews 之间拖放 uiviews。在那种情况下,我找到了在包含所有放置区域和所有拖动山墙对象的超级视图中跟踪平移事件的最佳解决方案。不将事件侦听器添加到实际拖动视图的主要原因是,一旦我更改了拖动视图的超级视图,我就丢失了正在进行的平移事件。

Instead I implemented a rather generic drag drop solution that could be used on single or multiple drop zones.

相反,我实现了一个相当通用的拖放解决方案,可用于单个或多个拖放区。

I have created a simple example that can be seen here: Drag an drop uiviews between multiple other uiviews

我创建了一个简单的例子,可以在这里看到:在多个其他 uiviews 之间拖放一个 uiviews

If you decide to go the other way, try using uicontrol instead of uibutton. They declare the addTarget methods and are much easier to extend - hence give custom state and behavior.

如果您决定走另一条路,请尝试使用 uicontrol 而不是 uibutton。它们声明 addTarget 方法并且更容易扩展 - 因此提供自定义状态和行为。

回答by Magnus

I would actually track dragging on the vehicle viewitself, rather than the large view - unless there is a particular reason no to.

我实际上会跟踪车辆视图本身的拖动,而不是大视图 - 除非有特殊原因。

In one case where I allow the user to place items by dragging them on the screen. In that case I experimented with both having the top viewand the child viewsdraggable. I found it's cleaner code if you add a few "draggable" views to the UIView and handle how to they could be dragged. I used a simple callback to the parent UIView to check if the new location was suitable or not - so I could indicate with animations.

在一种情况下,我允许用户通过在屏幕上拖动项目来放置项目。在那种情况下,我尝试同时拥有可拖动的顶视图子视图。如果向 UIView 添加一些“可拖动”视图并处理如何拖动它们,我发现它的代码更清晰。我对父 UIView 使用了一个简单的回调来检查新位置是否合适 - 所以我可以用动画指示。

Having the top viewtrack dragging I guess is as good, but that makes it slightly more messy if you would like to add non-draggable views that still interact with the user, such as a button.

具有俯视轨道拖着我的猜测是一样好,但是这使得它稍微凌乱,如果你想添加的非可拖动的观点仍然与用户,如按钮交互。

回答by Balaji G

-(void)funcAddGesture
{ 

 // DRAG BUTTON
        UIPanGestureRecognizer *panGestureRecognizer;
        panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragButton:)];
        panGestureRecognizer.cancelsTouchesInView = YES;

        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake(50, 100, 60, 60);
        [button addTarget:self action:@selector(buttontapEvent) forControlEvents:UIControlEventPrimaryActionTriggered];
        [button setImage:[UIImage imageNamed:@"button_normal.png"] forState:UIControlStateNormal];
        [button addGestureRecognizer:panGestureRecognizer];
        [self.view addSubview:button];
}


- (void)dragButton:(UIPanGestureRecognizer *)recognizer {

    UIButton *button = (UIButton *)recognizer.view;
    CGPoint translation = [recognizer translationInView:button];

    float xPosition = button.center.x;
    float yPosition = button.center.y;
    float buttonCenter = button.frame.size.height/2;

    if (xPosition < buttonCenter)
        xPosition = buttonCenter;
    else if (xPosition > self.view.frame.size.width - buttonCenter)
        xPosition = self.view.frame.size.width - buttonCenter;

    if (yPosition < buttonCenter)
        yPosition = buttonCenter;
    else if (yPosition > self.view.frame.size.height - buttonCenter)
        yPosition = self.view.frame.size.height - buttonCenter;

    button.center = CGPointMake(xPosition + translation.x, yPosition + translation.y);
    [recognizer setTranslation:CGPointZero inView:button];
}


- (void)buttontapEvent {

    NSLog(@"buttontapEvent");
}

回答by parag

ohho's answer worked well for me. In case you need the swift 2.x version:

ohho 的回答对我很有效。如果您需要 swift 2.x 版本:

override func viewDidLoad() {

    let myButton = UIButton(type: .Custom)
    myButton.setImage(UIImage(named: "vehicle"), forState: .Normal)

    // drag support
    myButton.addTarget(self, action:#selector(imageMoved(_:event:)), forControlEvents:.TouchDragInside)
    myButton.addTarget(self, action:#selector(imageMoved(_:event:)), forControlEvents:.TouchDragOutside)
}

private func imageMoved(sender: AnyObject, event: UIEvent) {
    guard let control = sender as? UIControl else { return }
    guard let touches = event.allTouches() else { return }
    guard let touch = touches.first else { return }

    let prev = touch.previousLocationInView(control)
    let p = touch.locationInView(control)
    var center = control.center
    center.x += p.x - prev.x
    center.y += p.y - prev.y
    control.center = center
}

回答by Anup Gupta

For Swift 4 Easy and easiest way.

对于 Swift 4 简单易行的方法。

Step 1:Connect Your Button From Storyboard To View Controller. And Set The all Basic AutoLayout Constraints

第 1 步:将您的按钮从故事板连接到视图控制器。并设置所有基本的 AutoLayout 约束

 @IBOutlet weak var cameraButton: UIButton!

Step 2:Add Pan Gesture for your button In viewDidLoad()

第 2 步:viewDidLoad() 中为您的按钮添加平移手势

self.cameraButton.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGestureHandler(panGesture:))))

Step 3:

第 3 步:

Add panGestureHandler

添加 panGestureHandler

@objc func panGestureHandler(panGesture recognizer: UIPanGestureRecognizer) {

         let location = recognizer.location(in: view)
        cameraButton.center = location

    }

And Now Your Button Action

现在你的按钮操作

@IBAction func ButtonAction(_ sender: Any) {

        print("This is button Action")
    }

enter image description here

在此处输入图片说明

Add See the Result ??

添加 查看结果 ??