Основное перетаскивание в iOS - программирование
Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

Для индивидуального транспортного средства намного легче справляться со своими перетаскиваниями по сравнению с управлением сценой в целом.

Ответ 2

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

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

Ответ 5

-(void)funcAddGesture
{ 

 // DRAG BUTTON
        UIPanGestureRecognizer *panGestureRecognizer;
        panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragButton:)];
        panGestureRecognizer.cancelsTouchesInView = YES;

        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake(50, 100, 60, 60);
        [button addTarget:self action:@selector(buttontapEvent) forControlEvents:UIControlEventPrimaryActionTriggered];
        [button setImage:[UIImage imageNamed:@"button_normal.png"] forState:UIControlStateNormal];
        [button addGestureRecognizer:panGestureRecognizer];
        [self.view addSubview:button];
}


- (void)dragButton:(UIPanGestureRecognizer *)recognizer {

    UIButton *button = (UIButton *)recognizer.view;
    CGPoint translation = [recognizer translationInView:button];

    float xPosition = button.center.x;
    float yPosition = button.center.y;
    float buttonCenter = button.frame.size.height/2;

    if (xPosition < buttonCenter)
        xPosition = buttonCenter;
    else if (xPosition > self.view.frame.size.width - buttonCenter)
        xPosition = self.view.frame.size.width - buttonCenter;

    if (yPosition < buttonCenter)
        yPosition = buttonCenter;
    else if (yPosition > self.view.frame.size.height - buttonCenter)
        yPosition = self.view.frame.size.height - buttonCenter;

    button.center = CGPointMake(xPosition + translation.x, yPosition + translation.y);
    [recognizer setTranslation:CGPointZero inView:button];
}


- (void)buttontapEvent {

    NSLog(@"buttontapEvent");
}

Ответ 6

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