Как анимировать UIView с ограничениями в Swift?

в моем примере, у меня есть следующие один вид:

enter image description here

Как вы можете видеть, он состоит из нескольких простых ограничений:

  1. выровнять горизонтальные и вертикальные центры,
  2. Высота (установлена на константу)
  3. ведущие и конечные пробелы (постоянное)

то, что я стремлюсь достичь, - это иметь этот красноватый/розоватый вид "войти" сверху. Традиционно, в ограничении-менее мир, я бы просто изменил кадр внутри UIView.animateWithDuration, однако я не уверен, как я делаю подобное в мире ограничений.

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

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

Спасибо за вашу помощь.

5 ответов


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

self.centerYConstraint.constant = 500.0
self.view.layoutIfNeeded()

UIView.animateWithDuration(Double(0.5), animations: {
        self.centerYConstraint.constant = 0
        self.view.layoutIfNeeded()
    })

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

TL; DR - это то, что вам нужно настроить ограничения, а затем вызвать layoutIfNeeded внутри вашего блока анимации для анимации изменений. Для большего см. это так сообщение.

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

раскадровка / XIB Setup

Итак, первое, что нужно настроить ограничения, которые не будут меняться в IB (или коде, в зависимости от того, что вам удобно). А именно; высота красного вида, а также его ведущее и конечное пространство до контейнера. Таким образом, ваши ограничения могут выглядеть так (Примечание: Я не установил ограничение ширины, но пусть ведущий и конечные пробелы определяют ширину):

Constraints

теперь вы увидите, что IB предупредит вас, что нет ограничений, настроенных для позиции Y вашего вида (отсюда красные пунктирные линии)

View with warnings

теперь вы можете добавить верхнее пространство в ограничение контейнера и установить его как ограничение-заполнитель (флажок "удалить во время сборки"). Мы делаем это, потому что хотим контролировать, где находится вид программно.

enter image description here

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

Кодирование Времени

теперь нам нужен метод, чтобы скрыть представление, метод, чтобы показать представление. Для этого мы будем хранить ограничение позиционирования Y в представлении, а затем анимировать его. Наши файле ViewController может выглядеть так:

@IBOutlet weak var redView: UIView!
var redViewYPositionConstraint: NSLayoutConstraint?

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideRedViewAnimated(false)
}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    self.showRedViewAnimated(true)
}

прячась

наш метод, чтобы скрыть вид, может просто удалить ограничение позиции, а затем добавить один с красным видом снизу, равным виду контроллера вида сверху:

func hideRedViewAnimated(animated: Bool) {
    //remove current constraint
    self.removeRedViewYPositionConstraint()
    let hideConstraint = NSLayoutConstraint(item: self.redView,
        attribute: .Bottom,
        relatedBy: .Equal,
        toItem: self.view,
        attribute: .Top,
        multiplier: 1,
        constant: 0)
    self.redViewYPositionConstraint = hideConstraint
    self.view.addConstraint(hideConstraint)
    //animate changes
    self.performConstraintLayout(animated: animated)
}

показывает

аналогично, наше ограничение show переместит центр представления Y в центр контроллеров Y:

func showRedViewAnimated(animated: Bool) {
    //remove current constraint
    self.removeRedViewYPositionConstraint()
    let centerYConstraint = NSLayoutConstraint(item: self.redView,
        attribute: .CenterY,
        relatedBy: .Equal,
        toItem: self.view,
        attribute: .CenterY,
        multiplier: 1,
        constant: 0)
    self.redViewYPositionConstraint = centerYConstraint
    self.view.addConstraint(centerYConstraint)
    //animate changes
    self.performConstraintLayout(animated: animated)
}

Методы

для полноты методов удобства я использовал выглядеть это:

func performConstraintLayout(animated animated: Bool) {
    if animated == true {
          UIView.animateWithDuration(1,
          delay: 0,
          usingSpringWithDamping: 0.5,
          initialSpringVelocity: 0.6,
          options: .BeginFromCurrentState,
          animations: { () -> Void in
             self.view.layoutIfNeeded()
          }, completion: nil)
     } else {
          self.view.layoutIfNeeded()
     }
}

func removeRedViewYPositionConstraint() {
    if redViewYPositionConstraint != nil {
        self.view.removeConstraint(self.redViewYPositionConstraint!)
        self.redViewYPositionConstraint = nil
    }
}

вы также можете проверить, виден ли красный вид, используя некоторую математику CGRect:

func isRedViewVisible() -> Bool {
    return CGRectContainsPoint(self.view.bounds, self.redView.frame.origin)
}

попробуйте это:

class ViewController: UIViewController {

    // red view
    @IBOutlet weak var myView: UIView!
    //  vertical align contraint
    @IBOutlet weak var verticalConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        verticalConstraint.constant = (myView.bounds.height + self.view.bounds.height)/2
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        self.view.layoutIfNeeded()
        UIView.animateWithDuration(0.5) {
            self.verticalConstraint.constant = 0
            self.view.layoutIfNeeded()
        }
    }

}

будьте осторожны firstItem и secondItem порядок в ограничение. Приведенный выше код предполагает, что Superview является firstItem:

screenshot


альтернативный способ-определить два ограничения:

  • ограничение выравнивания по центру Y (Superview.В. == Вид.CenterY) приоритет = 750
  • Ограничение Вертикального Пространства (SuperView.Верхний== Вид.Низу) приоритет = 500

screenshot

и настройка приоритет чтобы определить, какой контрапункт должен быть принят.

class ViewController: UIViewController {

    //  vertical align contraint
    @IBOutlet weak var centerYConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        centerYConstraint.priority = 250
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        self.view.layoutIfNeeded()
        UIView.animateWithDuration(0.5) {
            self.centerYConstraint.priority = 750
            self.view.layoutIfNeeded()
        }
    }

}

для тех, кто ищет простой анимации, подобный запрос:

для анимации скольжения вверх вам нужно использовать [...] этот CGAffineTransformMakeTranslation (x, y).

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

yourView.transform = CGAffineTransformMakeTranslation(0, 500)

это перемещает представление с экрана, в этом случае внизу. Теперь в этот viewDidAppear вы можете показать свой вид с:

UIView.animateWithDuration(0.7, delay: 0.0, usingSpringWithDamping: 0.5,
initialSpringVelocity: 0.5, options: [], animations: {
        self.yourView.transform = CGAffineTransformMakeScale(1, 1)
    }, completion: nil)

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


для меня лучший способ для animate Swift 3 & 4

self.constraint.constant = -150

UIView.animate(withDuration: 0.45) { [weak self] in
    self?.view.layoutIfNeeded()
}