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

IOS >> Перетаскиваемый вид переходит в исходное положение >> Автоматический макет в сочетании с проблемой UIPanGestureRecognizer

У меня есть несколько UIView, которые пользователь должен уметь перетаскивать. Я использую UIPanGestureRecognizer для управления действиями d & d (см. Код ниже). Действие d & d работает нормально, но когда я начинаю перетаскивать другой UIView, тот, который я только что сбросил, возвращается в исходное положение.

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

    CGPoint translation = [recognizer translationInView:self.view];

    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan:
            for (UIView* checkView in dragAndDropImageViewsArray) {
                if (checkView == recognizer.view) {
                    [checkView.superview bringSubviewToFront:checkView]; //this is done to make sure the currently dragged object is the top one
                }
            }
            break;

        case UIGestureRecognizerStateChanged:
            recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y + translation.y);
            break;

        case UIGestureRecognizerStateEnded:
            NSLog(@"UIGestureRecognizerStateEnded");
            break;

        default:
            break;
    }

    [recognizer setTranslation:CGPointMake(0, 0) inView:self.view];

}

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

  • Отменить автомакет. Это полностью решает его, но теперь я должен начать вычислять и управлять местоположениями и размерами объектов для разных устройств и ориентации.
  • Использовать layer.zPosition вместо showSubviewToFront: что объекты появляются над другими объектами, но, по-видимому, избегают "перехода назад", но не позволяют мне изменять иерархию между различными перетаскиваемыми объектами.

Я начал углублять свое понимание Auto Layout, но он становится очень сложным, когда мне кажется, что то, что я ищу, должно быть очень простым; Я видел много методов, которые касаются выполнения "повторной автомашировки", но я не понимаю, как с ними работать.

Есть ли здесь простое решение? как вызов метода, который переопределяет ограничения автоматической компоновки IB и переопределяет их в соответствии с новой позицией UIView?

Любая помощь будет очень оценена.

4b9b3361

Ответ 1

Я думаю, что если вы используете автозапуск и хотите изменить положение представления, вам нужно обновлять ограничения на представление вместо того, чтобы вручную устанавливать центр представления. Из описания это похоже на то, что вы устанавливаете центр, но когда приложение затем выводит вид (например, вы перетаскиваете другое), он снова устанавливает центр в любое автозапуск, которое должно быть указано.

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

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

Наконец, если он работает так, как вы хотите без автозапуска, вы можете попробовать установить translatesAutoresizingMaskIntoConstraints = YES на перемещенные представления, но имейте в виду, что это может вызвать конфликты в другом месте.

Ответ 2

Все это возможно с помощью Interface Builder. Вот код, который я использовал для этого:

@property (weak,nonatomic) IBOutlet NSLayoutConstraint *buttonXConstraint;
@property (weak,nonatomic) IBOutlet NSLayoutConstraint *buttonYConstraint;

Затем подключите эти IBOutlets к горизонтальному ограничению (положение X) и вертикальному ограничению (положение Y) в построителе интерфейса. Убедитесь, что ограничения привязаны к базовому виду, а не к ближайшему виду.

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

- (IBAction)panPlayButton:(UIPanGestureRecognizer *)sender
{
    if(sender.state == UIGestureRecognizerStateBegan){

    } else if(sender.state == UIGestureRecognizerStateChanged){
        CGPoint translation = [sender translationInView:self.view];

        //Update the constraint constant
        self.buttonXConstraint.constant += translation.x;
        self.buttonYConstraint.constant += translation.y;

        // Assign the frame position only for checking it fully on the screen
        CGRect recognizerFrame = sender.view.frame;
        recognizerFrame.origin.x = self.buttonXConstraint.constant;
        recognizerFrame.origin.y = self.buttonYConstraint.constant;

        // Check if UIImageView is completely inside its superView
        if(!CGRectContainsRect(self.view.bounds, recognizerFrame)) {
            if (self.buttonYConstraint.constant < CGRectGetMinY(self.view.bounds)) {
                self.buttonYConstraint.constant = 0;
            } else if (self.buttonYConstraint.constant + CGRectGetHeight(recognizerFrame) > CGRectGetHeight(self.view.bounds)) {
                self.buttonYConstraint.constant = CGRectGetHeight(self.view.bounds) - CGRectGetHeight(recognizerFrame);
            }

            if (self.buttonXConstraint.constant < CGRectGetMinX(self.view.bounds)) {
                self.buttonXConstraint.constant = 0;
            } else if (self.buttonXConstraint.constant + CGRectGetWidth(recognizerFrame) > CGRectGetWidth(self.view.bounds)) {
                self.buttonXConstraint.constant = CGRectGetWidth(self.view.bounds) - CGRectGetWidth(recognizerFrame);
            }
        }

        //Layout the View
        [self.view layoutIfNeeded];
    } else if(sender.state == UIGestureRecognizerStateEnded){

    }

    [sender setTranslation:CGPointMake(0, 0) inView:self.view];
}

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

Мне потребовалось немного времени, чтобы понять, что использование AutoLayout было сбросом представления, но ограничения будут делать то, что вам нужно здесь!