एक बाधा को तेज में चेतन करने की कोशिश कर रहा है


242

मेरे पास एक UITextField है, जिस पर टैप करने पर मैं इसकी चौड़ाई बढ़ाना चाहता हूं। मैंने अड़चनें खड़ी कीं और सुनिश्चित किया कि बायीं ओर की कसावट की प्राथमिकता कम है, फिर जिसे मैं दाईं ओर चेतन करने की कोशिश कर रहा हूं।

यहां वह कोड है जिसे मैं उपयोग करने की कोशिश कर रहा हूं।

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

यह काम करता है, लेकिन यह सिर्फ तुरंत होने लगता है और कोई भी आंदोलन नहीं लगता है। मैंने यह सुनिश्चित करने के लिए 10 सेकंड सेट करने की कोशिश की कि मुझे कुछ भी याद नहीं है, लेकिन मुझे वही परिणाम मिले।

nameInputConstraint, उस बाधा का नाम है जिसे मैं IB से अपनी कक्षा में जोड़ने के लिए नियंत्रित करता हूं।

आपकी सहायता के लिए अग्रिम धन्यवाद!


जवाबों:


666

आपको पहले बाधा को बदलने और फिर अपडेट को चेतन करने की आवश्यकता है।

self.nameInputConstraint.constant = 8

स्विफ्ट 2

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

स्विफ्ट 3, 4, 5

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

2
क्या कोई समझा सकता है कि यह कैसे / क्यों काम करता है? किसी भी यूआईईवीवाई पर एनीमेशनविदड्रॉलिंग को कॉल करने से यूआईईवाई से विरासत में मिली किसी भी कक्षा को चेतन किया जाएगा और एक भौतिक मूल्य बदल जाएगा?
निप्पोंसे

3
आपके द्वारा उल्लिखित एनीमेशन एपीआई का उपयोग विचारों और परतों के गुणों को चेतन करने के लिए किया जाता है । यहां हमें लेआउट में परिवर्तन को चेतन करने की आवश्यकता है । यही कारण है कि एक लेआउट की निरंतरता को बदलने के लिए बाधाएं कॉल करती हैं - केवल निरंतर बदलने से कुछ नहीं होता है।
मुंडी

2
@ जैकी शायद आप मजबूत और कमजोर चर के संदर्भ में उद्देश्य-सी तर्क के साथ इसे गलत समझ रहे हैं। स्विफ्ट क्लोजर अलग हैं: एक बार क्लोजर खत्म होने के बाद, क्लोजर में इस्तेमाल होने वाली कोई वस्तु नहीं होती है self
मुंडी

2
मेरे मामले में काम नहीं कर रहा है, यह बहुत पहले हो रहा है, क्या करना है
शक्ति

13
यह नोटिस एक घंटे मुझे ले गया, मैं superview पर layoutIfNeeded कॉल करने के लिए है कि ...
Nominalista

28

स्विफ्ट 4.x:

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

पूरा होने के साथ उदाहरण:

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

2
यह काम नहीं कर रहा है कि मैं इस UIView.animate किया है (withDuration: 10, देरी: 0, विकल्प: .curveEaseInOut, एनिमेशन: {self.leftViewHeightConstraint.constant = 200 self.leftView.layoutIfNeeded ()}, पूरा होने: शून्य)
saurabhgoyal795

1
आपको बाधा और फिर चेतन को बदलना होगा ।
जेरेडह

हालांकि यह कोड स्निपेट समाधान हो सकता है, जिसमें स्पष्टीकरण भी शामिल है , जो आपके पोस्ट की गुणवत्ता को बेहतर बनाने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, और उन लोगों को आपके कोड सुझाव के कारणों का पता नहीं चल सकता है।
नरेंद्र जाधव

उपरोक्त पंक्ति ने मेरा दिन बनाया :) धन्यवाद @Hadzi
Nrv

18

यह इंगित करना बहुत महत्वपूर्ण है कि view.layoutIfNeeded()केवल दृश्य साक्षात्कार पर लागू होता है।

अतः दृश्य बाधा को चेतन करने के लिए, इसे निम्नानुसार दृश्य-प्रति-चेतन पर्यवेक्षण पर कॉल करना महत्वपूर्ण है:

    topConstraint.constant = heightShift

    UIView.animate(withDuration: 0.3) {

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

एक सरल लेआउट के लिए एक उदाहरण इस प्रकार है:

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

स्विफ्ट 4 पर एक ऊँचाई की कसौटी को अद्यतन करना और इस लेआउट को कॉल करते समय काम किया। दृश्य पर निगरानी की गई, लेकिन पर्यवेक्षण नहीं किया। वास्तव में उपयोगी, धन्यवाद!
डेविक्सोस नोव

यह वास्तव में सही उत्तर है। यदि आप इसे पर्यवेक्षण पर नहीं कहते हैं, तो आपका दृष्टिकोण नए स्थान पर कूदता है। यह एक बहुत महत्वपूर्ण अंतर है।
ब्रायन डीमर

11

स्विफ्ट 5 और आईओएस 12.3 के साथ, अपनी आवश्यकताओं के अनुसार, आप अपनी समस्या को हल करने के लिए निम्नलिखित 3 तरीकों में से एक चुन सकते हैं।


# 1। का उपयोग करते हुए UIView's animate(withDuration:animations:)वर्ग विधि

animate(withDuration:animations:) निम्नलिखित घोषणा है:

निर्दिष्ट अवधि का उपयोग करके एक या एक से अधिक विचारों में परिवर्तन।

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

नीचे दिया गया प्लेग्राउंड कोड animate(withDuration:animations:)एक ऑटो लेआउट बाधा के निरंतर परिवर्तन को चेतन करने के लिए एक संभावित कार्यान्वयन दिखाता है ।

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। का उपयोग करते हुए UIViewPropertyAnimatorकी init(duration:curve:animations:)initialiser और startAnimation()विधि

init(duration:curve:animations:) निम्नलिखित घोषणा है:

ऐनिमेटर को एक अंतर्निहित UIKit टाइमिंग वक्र के साथ आरंभ करता है।

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

नीचे दिया खेल का मैदान कोड का एक संभावित क्रियान्वयन init(duration:curve:animations:)और startAnimation()आदेश में एक ऑटो लेआउट बाधा के लगातार परिवर्तन चेतन करने के लिए।

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। का उपयोग करते हुए UIViewPropertyAnimator's runningPropertyAnimator(withDuration:delay:options:animations:completion:)वर्ग विधि

runningPropertyAnimator(withDuration:delay:options:animations:completion:) निम्नलिखित घोषणा है:

एक एनिमेटर ऑब्जेक्ट बनाता है और लौटाता है जो तुरंत अपने एनिमेशन चलाना शुरू कर देता है।

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

नीचे दिया गया प्लेग्राउंड कोड runningPropertyAnimator(withDuration:delay:options:animations:completion:)एक ऑटो लेआउट बाधा के निरंतर परिवर्तन को चेतन करने के लिए एक संभावित कार्यान्वयन दिखाता है ।

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
इतना बढ़िया जवाब!
१३'१ta

@Imanou महान जवाब, विस्तार की सराहना! संभवतः विकल्पों का एक संक्षिप्त विवरण जोड़ें और अंतर क्या है? वास्तव में मेरे लिए उपयोगी होगा और मुझे यकीन है कि दूसरों को इस बारे में एक वाक्य देना होगा कि मैंने एक को दूसरे पर क्यों चुना।
रियप्प्स

3

मेरे मामले में, मैंने केवल कस्टम दृश्य ही अपडेट किया है।

// 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

यह देखो ।

वीडियो कहता है कि आपको self.view.layoutIfNeeded()निम्नलिखित की तरह बस जोड़ना होगा :

UIView.animate(withDuration: 1.0, animations: {
       self.centerX.constant -= 75
       self.view.layoutIfNeeded()
}, completion: nil)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.