raywenderlich priority constraint xcode swift constraints xcode6

xcode - priority - swift constraints programmatically



tratando de animar una restricción de forma rápida (6)

Con Swift 5 y iOS 12.3, según sus necesidades, puede elegir una de las 3 formas siguientes para resolver su problema.

# 1 Usando el método de clase animate(withDuration:animations:)

animate(withDuration:animations:) tiene la siguiente declaración:

Anime los cambios en una o más vistas usando la duración especificada.

class func animate(withDuration duration: TimeInterval, animations: @escaping () -> Void)

El siguiente código de Playground muestra una posible implementación de animate(withDuration:animations:) para animar el cambio constante de una restricción de Diseño automático.

import UIKit import PlaygroundSupport class ViewController: UIViewController { let textView = UITextView() lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50) override func viewDidLoad() { view.backgroundColor = .white view.addSubview(textView) textView.backgroundColor = .orange textView.isEditable = false textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." textView.translatesAutoresizingMaskIntoConstraints = false textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true heightConstraint.isActive = true let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:))) textView.addGestureRecognizer(tapGesture) } @objc func doIt(_ sender: UITapGestureRecognizer) { heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50 UIView.animate(withDuration: 2) { self.view.layoutIfNeeded() } } } PlaygroundPage.current.liveView = ViewController()

# 2 Usando el UIViewPropertyAnimator init(duration:curve:animations:) initialiser y startAnimation()

init(duration:curve:animations:) tiene la siguiente declaración:

Inicializa el animador con una curva de sincronización UIKit incorporada.

convenience init(duration: TimeInterval, curve: UIViewAnimationCurve, animations: (() -> Void)? = nil)

El siguiente código de Playground muestra una posible implementación de init(duration:curve:animations:) y startAnimation() para animar el cambio constante de una restricción de diseño automático.

import UIKit import PlaygroundSupport class ViewController: UIViewController { let textView = UITextView() lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50) override func viewDidLoad() { view.backgroundColor = .white view.addSubview(textView) textView.backgroundColor = .orange textView.isEditable = false textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." textView.translatesAutoresizingMaskIntoConstraints = false textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true heightConstraint.isActive = true let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:))) textView.addGestureRecognizer(tapGesture) } @objc func doIt(_ sender: UITapGestureRecognizer) { heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50 let animator = UIViewPropertyAnimator(duration: 2, curve: .linear, animations: { self.view.layoutIfNeeded() }) animator.startAnimation() } } PlaygroundPage.current.liveView = ViewController()

# 3 Usando el UIViewPropertyAnimator de runningPropertyAnimator(withDuration:delay:options:animations:completion:)

runningPropertyAnimator(withDuration:delay:options:animations:completion:) tiene la siguiente declaración:

Crea y devuelve un objeto animador que comienza a ejecutar sus animaciones de inmediato.

class func runningPropertyAnimator(withDuration duration: TimeInterval, delay: TimeInterval, options: UIViewAnimationOptions = [], animations: @escaping () -> Void, completion: ((UIViewAnimatingPosition) -> Void)? = nil) -> Self

El siguiente código de Playground muestra una posible implementación de runningPropertyAnimator(withDuration:delay:options:animations:completion:) para animar el cambio constante de una restricción de Diseño automático.

import UIKit import PlaygroundSupport class ViewController: UIViewController { let textView = UITextView() lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50) override func viewDidLoad() { view.backgroundColor = .white view.addSubview(textView) textView.backgroundColor = .orange textView.isEditable = false textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." textView.translatesAutoresizingMaskIntoConstraints = false textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true heightConstraint.isActive = true let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:))) textView.addGestureRecognizer(tapGesture) } @objc func doIt(_ sender: UITapGestureRecognizer) { heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50 UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 2, delay: 0, options: [], animations: { self.view.layoutIfNeeded() }) } } PlaygroundPage.current.liveView = ViewController()

Tengo un UITextField que quiero ampliar su ancho cuando se toca. Configuré las restricciones y me aseguré de que la restricción de la izquierda tenga la prioridad más baja que la que estoy tratando de animar en el lado derecho.

Aquí está el código que estoy tratando de usar.

// move the input box UIView.animateWithDuration(10.5, animations: { self.nameInputConstraint.constant = 8 }, completion: { (value: Bool) in println(">>> move const") })

Esto funciona, pero parece ocurrir instantáneamente y no parece haber ningún movimiento. Traté de configurarlo 10 segundos para asegurarme de que no me faltaba nada, pero obtuve los mismos resultados.

nameInputConstraint es el nombre de la restricción que controlo arrastrado para conectarme a mi clase desde IB.

Gracias de antemano por su ayuda!


En mi caso, solo actualicé la vista personalizada.

// DO NOT LIKE THIS customView.layoutIfNeeded() // Change to view.layoutIfNeeded() UIView.animate(withDuration: 0.5) { customViewConstraint.constant = 100.0 customView.layoutIfNeeded() // Change to view.layoutIfNeeded() }


Es muy importante señalar que view.layoutIfNeeded() aplica solo a las subvistas de vista.

Por lo tanto, para animar la restricción de la vista, es importante llamarla en la vista general de la vista para animar de la siguiente manera:

topConstraint.constant = heightShift UIView.animate(withDuration: 0.3) { // request layout on the *superview* self.view.superview?.layoutIfNeeded() }

Un ejemplo para un diseño simple de la siguiente manera:

class MyClass { /// Container view let container = UIView() /// View attached to container let view = UIView() /// Top constraint to animate var topConstraint = NSLayoutConstraint() /// Create the UI hierarchy and constraints func createUI() { container.addSubview(view) // Create the top constraint topConstraint = view.topAnchor.constraint(equalTo: container.topAnchor, constant: 0) view.translatesAutoresizingMaskIntoConstraints = false // Activate constaint(s) NSLayoutConstraint.activate([ topConstraint, ]) } /// Update view constraint with animation func updateConstraint(heightShift: CGFloat) { topConstraint.constant = heightShift UIView.animate(withDuration: 0.3) { // request layout on the *superview* self.view.superview?.layoutIfNeeded() } } }


Mira this

El video dice que solo necesita agregar self.view.layoutIfNeeded() la siguiente manera:

UIView.animate(withDuration: 1.0, animations: { self.centerX.constant -= 75 self.view.layoutIfNeeded() }, completion: nil)


Primero debe cambiar la restricción y luego animar la actualización.

self.nameInputConstraint.constant = 8

Swift 2

UIView.animateWithDuration(0.5) { self.view.layoutIfNeeded() }

Swift 3, 4, 5

UIView.animate(withDuration: 0.5) { self.view.layoutIfNeeded() }


SWIFT 4.x:

self.mConstraint.constant = 100.0 UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() }

Ejemplo con finalización:

self.mConstraint.constant = 100 UIView.animate(withDuration: 0.3, animations: { self.view.layoutIfNeeded() }, completion: {res in //Do something })