Как оживить UIView с ограничениями в Swift?
В моем надуманном примере у меня есть следующий единственный вид:
![enter image description here]()
Как вы можете видеть, он состоит из нескольких простых ограничений:
- Совместите горизонтальные и вертикальные центры,
- Высота (установленная на константу)
- Верхние и конечные пробелы (заданы как константные)
То, что я хочу достичь, - это красноватое/розоватое представление "прийти" сверху. Традиционно, в мире с ограниченными условиями, я бы просто изменил фрейм внутри UIView.animateWithDuration
, однако я не уверен, как я делаю подобное в мире ограничений.
Чтобы повторить мой вопрос, как я могу заставить свое представление начать с сцены и оживить вид, летающий сверху,?
Я рассмотрел анимацию ограничения вертикальных центров (и впоследствии вызвал layoutIfNeeded
), но не достиг нужного эффекта.
Спасибо за вашу помощь.
Ответы
Ответ 1
Что вы можете сделать, так это добавить следующий код в свой метод viewDidAppear
. Сначала вы создаете свойство IBOutlet
вашего ограничения Y центра просмотра и затем изменяете его постоянное значение.
self.centerYConstraint.constant = 500.0
self.view.layoutIfNeeded()
UIView.animateWithDuration(Double(0.5), animations: {
self.centerYConstraint.constant = 0
self.view.layoutIfNeeded()
})
Ответ 2
То, что вы хотите, на самом деле довольно просто, и я подробно расскажу, как это нужно делать, не вникая в приоритеты или фанковые константы. Таким образом, мы можем получить анимацию, которая будет работать на любом размере экрана.
TL; DR - это то, что вам нужно настроить свои ограничения, а затем вызвать layoutIfNeeded внутри вашего блока анимации, чтобы анимировать изменения. Для получения дополнительной информации см. Этот SO-сообщение.
Итак, нам нужны два набора ограничений для скрытия и отображения представления. В viewDidLoad
вид будет скрыт, а затем в viewDidAppear
или везде, где мы хотим, чтобы этот просмотр скользил.
Установка раскадровки /XIB
Итак, сначала нужно настроить ограничения, которые не будут меняться в IB (или код, в зависимости от того, что вам удобно). А именно, высота красного изображения и его ведущее и конечное пространство для контейнера. Таким образом, ваши ограничения могут выглядеть так ( note: Я не задал ограничение ширины, но пусть начальное и конечное пространства определяют ширину):
![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)
}
Ответ 3
Попробуйте следующее:
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 == View.CenterY) priority = 750
- Вертикальное ограничение пространства (SuperView.Top == View.Bottom) priority = 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()
}
}
}
Ответ 4
Для тех, кто ищет простую анимацию, такую как запрос, отметьте мой пример в GitHub о том, как анимация UIview в Swift.
Я надеюсь, что это может помочь кому-то, потому что первоначальный запрос посмотрит на третью анимацию (анимация "Слайд вверх" ).
Для слайд-анимации вам необходимо использовать [...] 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.
Ответ 5
Для меня лучший способ для анимации Swift 3 и 4
self.constraint.constant = -150
UIView.animate(withDuration: 0.45) { [weak self] in
self?.view.layoutIfNeeded()
}