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

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

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

Мой подclass 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; } 

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

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

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

1) В classе UIScrollView задайте значение canCancelContentTouches равным NO – это указывает classу UIScrollView разрешить касания в subviews (или, в данном случае, в subviews subviews).

2) В моем classе «card» установите значение exclusiveTouch в YES – это говорит, что subview владеет собственными штрихами внутри него.

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

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

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

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

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

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

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

 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's movement here. */ [gesture setTranslation:CGPointZero inView:[self superview]]; } 
  • Создание UIImage в форме круга
  • Как читать трассировки стека объектов-c
  • Прокрутка двумя пальцами с помощью UIScrollView
  • Ошибка модуля сборки iOS8 для Facebook для FBSDKCoreKit
  • Как отобразить изображение base64 в UIImageView?
  • Как получить текущее название города?
  • Переменная Property vs. instance
  • NSTimeZone: в чем разница между localTimeZone и systemTimeZone?
  • Что такое двойная звезда (например, NSError **)?
  • Как размыть сцену в SpriteKit?
  • Как получить разницу во времени в iPhone
  • Давайте будем гением компьютера.