hızlı bir şekilde bir kısıtlamayı canlandırmaya çalışmak


242

Vurulduğunda genişliğini artırmak istiyorum bir UITextField var. Kısıtlamaları ayarladım ve sol taraftaki kısıtlamanın sağ tarafta canlandırmaya çalıştığımdan daha düşük önceliğe sahip olduğundan emin oldum.

İşte kullanmaya çalıştığım kod.

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

Bu işe yarıyor, ancak anında gerçekleşiyor gibi görünüyor ve herhangi bir hareket yok gibi görünüyor. Hiçbir şeyi eksik olmadığımdan emin olmak için 10 saniye ayarlamaya çalıştım, ama aynı sonuçları aldım.

nameInputConstraint, IB'den sınıfıma bağlanmak için sürüklediğim denetimin adıdır.

Yardımınız için şimdiden teşekkür ederiz!


Yanıtlar:


666

Önce kısıtlamayı değiştirmeniz ve ardından güncellemeyi canlandırmanız gerekir.

self.nameInputConstraint.constant = 8

Hızlı 2

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

Hızlı 3, 4, 5

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

2
Birisi bunun nasıl / neden çalıştığını açıklayabilir mi? Herhangi bir UIView'deki animationWithDuration çağrısı, UIView'den devralınan ve fiziksel bir değeri değiştiren herhangi bir sınıfı canlandıracak mı?
Nipponese

3
Bahsettiğiniz animasyon API'sı , görünümlerin ve katmanların özelliklerini canlandırmak için kullanılır . Burada mizanpajdaki değişikliği canlandırmamız gerekiyor . Bir düzen kısıtlamasının sabitini değiştirmek budur - tek başına sabiti değiştirmek hiçbir şey yapmaz.
Mundi

2
@Jacky Belki de bunu Objective-C mantığıyla güçlü ve zayıf değişkenlere referansla yanlış yapıyorsunuzdur. Hızlı kapaklar farklıdır: kapak bittikten sonra, kapakta selfkullanılana tutunan bir nesne yoktur .
Mundi

2
Benim durumumda çalışmıyor, çok önce oluyor, ne yapmalı
Shakti

13
Fark etmem bir saat sürdü, mizanpajı çağırmam gerekiyor ...
Nominalista

28

SWIFT 4.x:

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

Tamamlama ile örnek:

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

2
çalışmıyor Bu UIView.animate (withDuration: 10, delay: 0, options: .curveEaseInOut, animasyonlar: {self.leftViewHeightConstraint.constant = 200 self.leftView.layoutIfNeeded ()}, tamamlanma: nil)
saurabhgoyal795

1
Kısıtlamayı değiştirmeniz ve ardından canlandırmanız gerekir.
JaredH

Bu kod snippet'i çözüm olsa da, bir açıklama da dahil olmak üzere mesajınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın.
Narendra Jadhav

Yukarıdaki satır Günümü yaptı :) Teşekkürler @Hadzi
Nrv

18

Bunun view.layoutIfNeeded()yalnızca görünüm alt görünümleri için geçerli olduğunu belirtmek çok önemlidir .

Dolayısıyla görünüm kısıtlamayı canlandırmak, görünüm-to-canlandırılır üzerinde diyoruz önemlidir Superview şöyle:

    topConstraint.constant = heightShift

    UIView.animate(withDuration: 0.3) {

        // request layout on the *superview*
        self.view.superview?.layoutIfNeeded()
    }

Aşağıdaki gibi basit bir düzen örneği:

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()
        }
    }
}

Swift 4'te bir yükseklik kısıtlaması güncelleniyor ve bu, layoutIfNeeded görünümünde çağrılırken çalıştı, ancak denetim yapmadı. Gerçekten yararlı, teşekkürler!
Alekxos

Bu gerçekten doğru cevap. Gözetim altında çağırmazsanız, görüşünüz yeni konuma atlar. Bu çok önemli bir ayrım.
Bryan Deemer

11

Swift 5 ve iOS 12.3 ile, ihtiyaçlarınıza göre, sorununuzu çözmek için aşağıdaki 3 yoldan birini seçebilirsiniz.


# 1. Kullanma UIViews' animate(withDuration:animations:)sınıf yöntemi

animate(withDuration:animations:) aşağıdaki beyanı içerir:

Belirtilen süreyi kullanarak bir veya daha fazla görünümdeki değişiklikleri canlandırın.

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

Aşağıdaki Oyun Alanı kodu, animate(withDuration:animations:)bir Otomatik Düzen kısıtlamasının sürekli değişimini canlandırmak için olası bir uygulamasını gösterir .

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. Kullanma UIViewPropertyAnimatorsitesindeki init(duration:curve:animations:)Başlatıcı ve startAnimation()yöntem

init(duration:curve:animations:) aşağıdaki beyanı içerir:

Animatörü yerleşik bir UIKit zamanlama eğrisi ile başlatır.

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

Aşağıdaki Oyun Alanı kodu, bir Otomatik Düzen kısıtlamasının sürekli değişiminin olası bir uygulamasını init(duration:curve:animations:)ve startAnimation()bu animasyonu canlandırmak için göstermektedir.

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.. Kullanma UIViewPropertyAnimators' runningPropertyAnimator(withDuration:delay:options:animations:completion:)sınıf yöntemi

runningPropertyAnimator(withDuration:delay:options:animations:completion:) aşağıdaki beyanı içerir:

Animasyonlarını hemen çalıştırmaya başlayan bir animatör nesnesi oluşturur ve döndürür.

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

Aşağıdaki Oyun Alanı kodu, runningPropertyAnimator(withDuration:delay:options:animations:completion:)bir Otomatik Düzen kısıtlamasının sürekli değişimini canlandırmak için olası bir uygulamasını gösterir .

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()

1
Harika bir cevap!
Bashta

@ Harika bir cevap, detay için teşekkür ederiz! Muhtemelen seçeneklerin kısa bir açıklamasını ekleyin ve fark nedir? Bana gerçekten yardımcı olur ve başkalarına neden bir başkasını seçtiğime dair bir cümle olacağına eminim.
rayepps

3

Benim durumumda, yalnızca özel görünümü güncelledim.

// 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()
}

-1

Bunu izle .

Video self.view.layoutIfNeeded(), aşağıdaki gibi eklemeniz gerektiğini söylüyor :

UIView.animate(withDuration: 1.0, animations: {
       self.centerX.constant -= 75
       self.view.layoutIfNeeded()
}, completion: nil)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.