Подтвердить что ты не робот

Перетаскивание UIView внутри UIScrollView

Я пытаюсь решить основную проблему с перетаскиванием на iPhone. Здесь моя настройка:

  • У меня есть UIScrollView, у которого есть один большой просмотр содержимого (я могу прокручивать и масштабировать его).
  • В subview для контента есть несколько небольших фрагментов, которые должны быть перемещены внутри него.

Мой подкласс 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];
    }
}

Подпоследовательность содержимого имеет этот метод:

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

И в режиме просмотра плитки этот метод:

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

    self.center = location;
}

Это работает, но не полностью корректно: плитка иногда "падает" во время процесса перетаскивания. Точнее, он перестает получать штрихи. Вместо этого запускается прокрутка: вызовы и прокрутка. Я заметил, что это зависит от скорости перетаскивания: чем быстрее я перетаскиваю, тем быстрее "падает".

Любые идеи о том, как сохранить плиту, приклеенную к перетаскивающему пальцу?

4b9b3361

Ответ 1

Решено: выяснилось, что также должны быть затронутыBegan: и touchesEnded: реализации (в моем случае с пустым методом помогли) в плитке, иначе жест начал распространяться на родительские представления, и они каким-то образом перехватили жест. Зависимость от скорости перемещения была мнимой.

Ответ 2

Я боролся с этой же проблемой - я пытался сделать интерфейс с большим количеством "карточек" (подклассы UIView) на пробковой доске и иметь прокручиваемую область пробки, но все же способную перетаскивать мышью, отбросьте карты. Я делал решение hitTest() выше, но один из инженеров Apple спросил меня, почему я так делаю. Более простое решение, которое они предложили, было следующим:

1) В классе UIScrollView задайте значение canCancelContentTouches в НЕТ - это указывает классу UIScrollView разрешить касания в пределах subviews (или, в данном случае, в subviews subviews).

2) В моем классе "card" установите для параметра exclusiveTouch значение "ДА" - это говорит подчиненному, что он владеет штрихами внутри него.

После этого мне удалось перетащить карты и еще прокрутить подвью. Это намного проще и чище, чем решение hitTest() выше.

(BTW, для дополнительного кредита, если вы используете iOS 3.2 или 4.0 или новее, используйте класс UIPanGestureRecognizer для обработки логики перетаскивания - движение перетаскивания намного более плавное, чем переопределение касанийBegan()/touchhesMoved ( )/touchesEnded().)

Ответ 3

На основе кода, который вы поделили, похоже, что ваш метод touchesMoved: будет вызываться только для жестов внутри плитки. При каждом касании вы перемещаете плитку так, чтобы она была сосредоточена на этом касании, поэтому медленные движения будут давать обновление внутри плитки - и плитка "догонит" кончиком пальца - до того, как жест выйдет из плитки. Однако, когда жест выполняется быстрее, (x, y) касается событий, связанных друг с другом, и вы потеряете жест, когда одна (x, y) точка находится достаточно далеко от последней, которая находится за пределами плитка уже.

Вы можете обойти это, захватив движения в супервиде, достаточно большие, чтобы покрыть всю область перетаскивания, и контролировать движение плитки изнутри этого супервизора.

Кстати, есть ли причина, по которой вы переопределяете метод hitTest:? Может быть проще (и, возможно, более эффективно?) Использовать встроенную реализацию.

Ответ 4

Сначала установите:

scrollview.canCancelContentTouches = NO;

yourSubView. exclusiveTouch = YES;

Затем в вашей функции обработки жестов subview,

- (void)handleSubviewMove:(UIPanGestureRecognizer *)gesture {

if(gesture.state == UIGestureRecognizerStateBegan) {
    if(_parentScrollView != nil) {
        _parentScrollView.scrollEnabled = NO;
    }
}
if(gesture.state == UIGestureRecognizerStateEnded) {
    if(_parentScrollView != nil) {
        _parentScrollView.scrollEnabled = YES;
    }
}

CGPoint translation = [gesture translationInView:[self superview]];
/* handle your view movement here. */
[gesture setTranslation:CGPointZero inView:[self superview]];
}