Базовое перетаскивание в iOS

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


person Luke    schedule 16.01.2011    source источник
comment
developer.apple.com/ios/drag-and-drop   -  person matt.writes.code    schedule 28.11.2017


Ответы (7)


Предположим, у вас есть 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;
}

Отдельному транспортному средству намного проще справляться с собственным перетаскиванием, чем управлять сценой в целом.

person ohho    schedule 17.01.2011
comment
Выглядит здорово и очень просто! Я попробую это сделать. - person Luke; 19.01.2011
comment
Будет ли эта стратегия вызывать прерывание перетаскивания, если пользователь перетаскивает кнопку быстрее, чем обновляется анимация? Если бы их палец вышел за пределы коробки, он перестал бы получать вызовы imageMoved: withEvent:, верно? - person Tim; 10.06.2011
comment
Как узнать, перестало ли перетаскивать изображение? Откуда вы знаете, что палец съехал? - person ymutlu; 28.11.2011
comment
оххо - можно ли сместить ручку перетаскивания для изображения или кнопки так, чтобы ее можно было перетаскивать за верхний правый или верхний левый угол? - person LJ Wilson; 29.02.2012
comment
когда я пытаюсь получить исключение - [drag_move_textViewController imageTouch: withEvent:]: нераспознанный селектор отправлен в экземпляр 0x4b4b1c0 - person iosDev; 29.04.2012
comment
@Luke: следует ли это исправить, настроив таргетинг на событие UIControlEventTouchDragOutside? - person JakubKnejzlik; 28.07.2012
comment
правда ... вам придется перетаскивать довольно быстро :) Я бы просто рекомендовал не использовать это ни в каких играх, но для типичного приложения это работает. - person d2burke; 10.01.2013
comment
@Tim Слишком поздно, но вы тоже можете попробовать это с UIPanGestureRecognizer. Это не сломается ни при какой скорости сопротивления. - person tipycalFlow; 03.09.2013

В дополнение к ответу 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;
}

Я не говорю, что это идеальное решение для ответа. Тем не менее, я нашел это самым простым решением для перетаскивания.

person JakubKnejzlik    schedule 28.07.2012
comment
В вашем примере кода вы определяете UIControl * control = sender после его использования - не следует ли это определять ранее? - person Peter Johnson; 24.08.2012
comment
@PeterJohnson: На самом деле, в данном случае это не имеет значения. Эта переменная не использовалась ранее, начиная с упомянутой вами строки :) - person JakubKnejzlik; 06.09.2012
comment
А как насчет CGPoint pPrev = [t previousLocationInView: control]; CGPoint p = [t locationInView: control]; Эти две предыдущие строки, кажется, относятся к control? - person Peter Johnson; 07.09.2012
comment
О Боже! Как я мог это пропустить? : -O ... Я отредактировал ответ. - person JakubKnejzlik; 10.09.2012
comment
Я добавляю конструктор интерфейса формы кнопки и использую автозапуск для некоторого входа в систему. Я скрываю кнопку и показываю ее снова, когда я это делаю, поэтому она возвращается в исходное место, как предотвратить это поведение - person Amr Angry; 17.04.2017

У меня был случай, когда я хотел бы перетаскивать uiviews между несколькими другими uiviews. В этом случае я нашел лучшее решение для отслеживания событий панорамирования в суперпредставлении, содержащем все зоны перетаскивания и все объекты перетаскивания. Основная причина, по которой НЕ добавлялись прослушиватели событий к фактическим перетаскиваемым представлениям, заключалась в том, что я потерял текущие события панорамирования, как только я изменил супервизор для перетаскиваемого представления.

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

Я создал простой пример, который можно увидеть здесь: Перетащите перетаскивание uiviews между несколькими другими uiviews

Если вы решили пойти другим путем, попробуйте использовать uicontrol вместо uibutton. Они объявляют методы addTarget и их намного проще расширять - следовательно, они дают настраиваемое состояние и поведение.

person jeyben    schedule 08.04.2012

На самом деле я бы отслеживал перетаскивание самого вида транспортного средства, а не большого вида - если для этого нет особой причины.

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

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

person Magnus    schedule 17.01.2011

Ответ оххо сработал для меня. Если вам нужна версия 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
}
person parag    schedule 29.03.2016


Для Swift 4 Простой и легкий способ. ????

Шаг 1. Подключите кнопку из раскадровки к контроллеру просмотра. И установите все основные ограничения AutoLayout

 @IBOutlet weak var cameraButton: UIButton!

Шаг 2. Добавьте жест панорамирования для кнопки в viewDidLoad ()

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

Шаг 3:

Добавить 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")
    }

введите описание изображения здесь

Добавить Посмотреть результат ☝️

person Anup Gupta    schedule 21.06.2018