如何使用触摸移动UIImageView

5

我正在尝试为我的imageView(以下代码中的maskPreview)创建移动功能,以便用户可以将包含在maskPreview中的图片在屏幕上移动。下面是我用于触摸开始和触摸移动的代码:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([touches count]==1) {
    UITouch *touch= [touches anyObject];
    originalOrigin = [touch locationInView:maskPreview];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([touches count]==1) {
    UITouch *touch = [touches anyObject];
    CGPoint lastTouch = [touch previousLocationInView:self.view];
    CGFloat movedDistanceX = originalOrigin.x-lastTouch.x;
    CGFloat movedDistanceY = originalOrigin.y-lastTouch.y;
    [maskPreview setFrame:CGRectMake(maskPreview.frame.origin.x+movedDistanceX, maskPreview.frame.origin.y + movedDistanceY, maskPreview.frame.size.width, maskPreview.frame.size.height)];
}
}

但是我从应用程序中得到了一些奇怪的反应。我没有限制imageview可以移动的距离,即防止它超出屏幕,但即使是小幅移动,我的imageview也会疯狂地消失。

非常感谢您提前提供的所有帮助。

2个回答

9

在现代世界中,实现touchesBegan等方法是过度的。你只会让自己困惑不已,而且你的代码很快就会变得难以理解或维护。使用UIPanGestureRecognizer;这就是它的用途。使用UIPanGestureRecognizer使视图可拖动是微不足道的。下面是一个UIPanGestureRecognizer的操作处理程序,可以使视图可拖动:

- (void) dragging: (UIPanGestureRecognizer*) p {
    UIView* vv = p.view;
    if (p.state == UIGestureRecognizerStateBegan ||
        p.state == UIGestureRecognizerStateChanged) {
        CGPoint delta = [p translationInView: vv.superview];
        CGPoint c = vv.center;
        c.x += delta.x; c.y += delta.y;
        vv.center = c;
        [p setTranslation: CGPointZero inView: vv.superview];
    }
}

太棒了,Matt,你绝对是个天才!但我没有足够的声望来评价你的回答!你让我的生活变得更加轻松了! - Septronic
只是提供信息,那段代码直接来自我的书:http://shop.oreilly.com/product/0636920023562.do - 还有很多类似的内容。 - matt

2
你的代码存在两个问题。首先,这一行是错误的:
CGPoint lastTouch = [touch previousLocationInView:self.view];

应该是这样的:
CGPoint lastTouch = [touch previousLocationInView:maskPreview];

实际上,你甚至不应该使用previousLocationInView:。你应该像这样使用locationInView:

CGPoint lastTouch = [touch locationInView:maskPreview];

其次,您将movedDistanceXmovedDistanceY的标志弄错了。请将它们更改为:

CGFloat movedDistanceX = lastTouch.x - originalOrigin.x;
CGFloat movedDistanceY = lastTouch.y - originalOrigin.y;

此外,touchesBegan:withEvent:的文档还说:

如果您重写此方法而不调用super(这是常见的用法模式),则必须还要重写其他处理触摸事件的方法,即使只是作为空实现。

因此,请确保还覆盖了touchesEnded:withEvent:touchesCancelled:withEvent:

无论如何,您可以更简单地完成此操作。一种方法是使touchesBegan:withEvent:为空,并使用previousLocationInView:locationInView:两者来在touchesMoved:withEvent:中完成所有工作,然后更新maskPreview.center而不是maskPreview.frame。您甚至不需要originalOrigin实例变量:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if ([touches count]==1) {
        UITouch *touch = [touches anyObject];
        CGPoint p0 = [touch previousLocationInView:maskPreview];
        CGPoint p1 = [touch locationInView:maskPreview];
        CGPoint center = maskPreview.center;
        center.x += p1.x - p0.x;
        center.y += p1.y - p0.y;
        maskPreview.center = center;
    }
}

另一种方法是使用 UIPanGestureRecognizer。我把它作为读者的练习。

嗨,罗布,谢谢你的回答,我意识到了代码中的错误!我使用了马特的UIPanGestureRecognizer教程,它非常有效。但是关于覆盖所有触摸事件的部分真的很有帮助,我不知道也没有想过我们应该这样做。 - Septronic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接