在UIScrollView中拖动UIView

Ser*_*nov 22 iphone objective-c

我试图解决iPhone上拖放的基本问题.这是我的设置:

  • 我有一个UIScrollView,它有一个大内容子视图(我可以滚动和缩放它)
  • 内容子视图有几个小图块作为子视图,应该在其中拖动.

我的UIScrollView子类有这个方法:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *tile = [contentView pointInsideTiles:[self convertPoint:point toView:contentView] withEvent:event];
    if (tile) {
        return tile;
    } else {
        return [super hitTest:point withEvent:event];
    }
}
Run Code Online (Sandbox Code Playgroud)

内容子视图有这种方法:

- (UIView *)pointInsideTiles:(CGPoint)point withEvent:(UIEvent *)event {
    for (TileView *tile in tiles) {
        if ([tile pointInside:[self convertPoint:point toView:tile] withEvent:event])
            return tile;
    }

    return nil;
}
Run Code Online (Sandbox Code Playgroud)

并且tile视图有这个方法:

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
    UITouch *touch = [touches anyObject];   
    CGPoint location = [touch locationInView:self.superview];

    self.center = location;
}
Run Code Online (Sandbox Code Playgroud)

这有效,但不完全正确:在拖动过程中,瓷砖有时会"掉落".更确切地说,它停止接收touchesMoved:invocations,滚动视图开始滚动.我注意到这取决于拖动速度:拖动越快,瓷砖"下降"越快.

有关如何将瓷砖粘在拖动手指上的任何想法?

小智 61

我正在努力解决同样的问题 - 我试图在软木板上做很多"卡片"(UIView子类)的接口,并且软木板区域可以滚动,但仍然能够拖放卡片.我正在做上面的hitTest()解决方案,但是一位Apple工程师问我为什么这样做.他们建议的更简单的解决方案如下:

1)在UIScrollView类中,将canCancelContentTouches的值设置为NO - 这告诉UIScrollView类允许子视图内的触摸(或者,在本例中,在子视图的子视图中).

2)在我的"card"类中,将exclusiveTouch设置为YES - 这告诉子视图它拥有它内部的触摸.

在此之后,我能够拖动卡片并仍然滚动子视图.它比上面的hitTest()解决方案更简单,更清晰.

(顺便说一下,如果您使用iOS 3.2或4.0或更高版本,请使用UIPanGestureRecognizer类来处理拖放逻辑 - 拖放动作比覆盖touchesBegan()/ touchesMoved()/ touchesEnded更顺畅()).

  • 1正是我想要的.canCancelContentTouches似乎是这个变量的一个相当差的名字. (2认同)

Ser*_*nov 1

已解决:事实证明,平铺中还应该有touchesBegan:和touchesEnded:实现(在我的例子中有空方法帮助),否则手势开始传播到父视图,并且它们以某种方式拦截手势。对阻力速度的依赖是虚构的。