iOS中的基本拖放


Answers:


126

假设您有一个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];

然后,您可以通过响应该UIControlEventTouchDragInside事件,将车辆移至所需位置,例如:

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

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


看起来很棒,非常简单!我会尝试的。
路加福音

10
如果用户拖动按钮的速度比更新动画的速度快,此策略会导致拖动中断吗?如果他们的手指不在盒子外面,它将停止接收imageMoved:withEvent:调用,对吗?
蒂姆

您怎么知道图像是否停止拖动?您怎么知道手指移开了?
ymutlu

ohho-是否可以偏移图像或按钮的拖动“句柄”,以便可以将其拖动到右上角或左上角?
LJ威尔逊,

当我尝试获取异常-[drag_move_textViewController imageTouch:withEvent:]:无法识别的选择器发送到实例0x4b4b1c0
iosDev 2012年

34

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

按钮初始化为...

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];

和方法实现:

- (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;
}

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


2
在示例代码中,您将在使用UIControl * control = sender之后定义它-不应该更早定义吗?
彼得·约翰逊

@PeterJohnson:实际上在这种情况下没关系。自从您提到过这行以来,就没有此变量的早期用法:)
JakubKnejzlik 2012年

1
那么CGPoint pPrev = [t previousLocationInView:control]; CGPoint p = [t locationInView:control]; 前面的这两行似乎都指向“控件”?
彼得·约翰逊

哦,天哪!我怎么会错过呢?:-O ...我已经编辑了答案。
JakubKnejzlik 2012年

我添加了按钮表单界面生成器,并使用了自动布局进行一些登录我确实隐藏了按钮并在我这样做时再次显示它,使它返回到原始位置如何防止这种现象发生
Amr Angry

2

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

相反,我实现了一个相当通用的拖放解决方案,该解决方案可以在单个或多个拖放区域中使用。

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

如果您决定采用其他方法,请尝试使用uicontrol而不是uibutton。它们声明了addTarget方法,并且易于扩展-因此提供了自定义状态和行为。


1

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

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

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


1
-(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");
}

1

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
}


0

对于Swift 4简便的方法。😛

步骤1: 将您的按钮从情节提要连接到View Controller。并设置所有基本的自动布局约束

 @IBOutlet weak var cameraButton: UIButton!

步骤2:viewDidLoad()中为按钮添加Pan Gesture

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

第三步:

添加panGestureHandler

@objc func panGestureHandler(panGesture recognizer: UIPanGestureRecognizer) {

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

    }

现在您的按钮动作

@IBAction func ButtonAction(_ sender: Any) {

        print("This is button Action")
    }

在此处输入图片说明

添加查看结果☝️

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.