प्रोग्राम बनाते समय मुझे ऑटोलैयट बाधाओं को कहां स्थापित करना चाहिए


79

मैं विभिन्न उदाहरणों को देखता हूं, जहां अड़चनें निर्धारित हैं। कुछ ने उन्हें viewDidLoad/ loadView(सबव्यू जोड़ने के बाद) सेट किया। दूसरों ने उन्हें विधि में सेट किया updateViewConstraints, जिसे कहा जाता है viewDidAppear

जब मैं updateViewContraintsवहां अड़चनें स्थापित करने की कोशिश करता हूं तो लेआउट में उछाल आ सकता है, उदाहरण से पहले दृश्य में थोड़ी देरी। इसके अलावा, अगर मैं इस पद्धति का उपयोग करता हूं, तो क्या मुझे पहले मौजूदा बाधाओं को दूर करना चाहिए [self.view [removeConstraints:self.view.constraints]?


1
मुझे अपडेट व्यू कॉनस्ट्रेन्ट्स के साथ समान अनुभव है, इसलिए मैंने इसका उपयोग करने की कोशिश करना बंद कर दिया। मैं viewDidLoad में या एक कस्टम दृश्य के अद्यतन विधि में बाधाओं को कॉन्फ़िगर करता हूं। उम्मीद है, कोई आपको निश्चित उत्तर देगा।
बिलोबाटम

1
updateViewConstraints: आप इस विधि को एक उपवर्ग में ओवरराइड कर सकते हैं ताकि दृष्टि या उसके साक्षात्कार में बाधाएं जोड़ सकें। ( Apple डॉक्स से )
परीक्षण

जवाबों:


108

मैं viewDidLoad/ loadView(मैं iOS> = 6 को लक्षित कर रहा हूं) में अपनी बाधाओं को सेट करता हूं । updateViewConstraintsबाधाओं के बदलते मूल्यों के लिए उपयोगी है, उदाहरण के लिए अगर कुछ बाधा स्क्रीन के उन्मुखीकरण पर निर्भर है (मुझे पता है, यह एक बुरा अभ्यास है) तो आप constantइस पद्धति में इसे बदल सकते हैं ।

39:22 से शुरू होने वाले viewDidLoadसत्र "iOS और OS X के लिए ऑटो लेआउट का परिचय" (WWDC 2012) के दौरान बाधाओं को जोड़ना दिखाया गया है । मुझे लगता है कि यह उन चीजों में से एक है जो व्याख्यान के दौरान कही जाती हैं, लेकिन दस्तावेज में नहीं आती हैं।

अद्यतन: मैंने देखा है कि नियंत्रकों में संसाधन प्रबंधन में बाधाओं की स्थापना का उल्लेख है :

यदि आप स्टोरीबोर्ड का उपयोग करने के बजाय, प्रोग्रामेटिक रूप से व्यू बनाना पसंद करते हैं, तो आप ऐसा अपने व्यू कंट्रोलर के loadView तरीके को ओवरराइड करके करते हैं । इस पद्धति का आपका कार्यान्वयन निम्नलिखित कार्य करना चाहिए:

(...)

3. यदि आप ऑटो लेआउट का उपयोग कर रहे हैं, तो अपने विचारों की स्थिति और आकार को नियंत्रित करने के लिए आपके द्वारा बनाए गए प्रत्येक दृश्य के लिए पर्याप्त बाधाओं को असाइन करें । अन्यथा, दृश्य पदानुक्रम में उप-फ़्रेमों को समायोजित करने के लिए viewWillLayoutSubviewsऔर viewDidLayoutSubviewsविधियों को लागू करें । देखें "कंट्रोलर के दृश्य का आकार बदलना।"

अद्यतन 2 : WWDC 2015 के दौरान एप्पल एक नया स्पष्टीकरण दे दिया की updateConstraintsऔर updateViewConstraintsसिफारिश उपयोग:

वास्तव में, यह सब विचारों के लिए अगले लेआउट पास के लिए समय में बाधाओं को बदलने का मौका देने का एक तरीका है, लेकिन इसकी वास्तव में आवश्यकता नहीं है।

आपके सभी प्रारंभिक बाधा सेटअप आदर्श रूप से इंटरफ़ेस बिल्डर के अंदर होने चाहिए।

या यदि आप वास्तव में यह पाते हैं कि आपको अपने अवरोधों को प्रोग्रामेटिक रूप से आवंटित करने की आवश्यकता है, तो कुछ जगह जैसे कि व्यूडालैड बहुत बेहतर है।

अपडेट की कमी वास्तव में सिर्फ उस काम के लिए है जिसे समय-समय पर दोहराया जाना चाहिए।

इसके अलावा, जब आप ऐसा करने की आवश्यकता पाते हैं तो बस बाधाओं को बदलना बहुत आसान है; जबकि, यदि आप उस तर्क को उस दूसरे कोड से अलग लेते हैं जो उससे संबंधित है और आप इसे एक अलग विधि में स्थानांतरित करते हैं जो बाद के समय में निष्पादित हो जाता है, तो आपका कोड अनुसरण करना बहुत कठिन हो जाता है, इसलिए इसे बनाए रखना आपके लिए कठिन होगा , यह अन्य लोगों को समझने के लिए बहुत कठिन होगा।

तो आपको अपडेट बाधाओं का उपयोग करने की आवश्यकता कब होगी?

खैर, यह प्रदर्शन के लिए उबलता है।

यदि आप पाते हैं कि बस अपनी बाधाओं को जगह में बदलना बहुत धीमा है, तो अद्यतन बाधाएं आपकी मदद करने में सक्षम हो सकती हैं।

यह पता चला है कि अद्यतन बाधाओं के अंदर एक बाधा को बदलना वास्तव में अन्य समय में एक बाधा को बदलने से तेज है।

इसका कारण यह है क्योंकि इंजन बैच के रूप में इस पास में होने वाले सभी बाधा परिवर्तनों का इलाज करने में सक्षम है।


2
सबसे अच्छा जवाब के रूप में इसके लिए +1। Apple ने शुरुआती बाधाओं को निर्धारित करने के लिए loadView को सही जगह के रूप में निर्धारित किया है और इसके लिए अपडेट कॉन्ट्रैन्सट विधि (जो कि सिर्फ हैकी लगती है) में अतिरिक्त BOOL ध्वज की आवश्यकता नहीं है।
जाग्रत

4
मेरा मानना ​​है कि दृष्टि बाधाओं के लिए जिम्मेदार होनी चाहिए, न कि दृश्य नियंत्रक के लिए। बहुत सारे मामलों में व्यू कंट्रोलर को यह भी पता नहीं होता है कि दृश्य के सभी तत्व क्या हैं (उदाहरण के लिए टेबल व्यू सेल में स्टैटिक लेबल)।
दशमी

1
@dasdom अन्य विचारों को देखने के अपने संबंध को कैसे नियंत्रित कर सकते हैं? आपको @"|-[button1]-[button2]-|"ViewController में बाधाओं की तरह सेट करना होगा, है ना? या कोई अलग तरीका है?
जोसेफ

@ कैस्पर अधिकांश बार मेरे पास एक UIView उपवर्ग है, जो दृश्य नियंत्रक का दृश्य है। उस दृश्य के भीतर उप-साक्षात्कार हैं और उप-साक्षात्कार के लिए अड़चनें हैं।
दशमी तिथि

3
इसमें अड़चनें बदलना एक बुरा अभ्यास क्यों है updateViewConstraints?
परीक्षण

33

मैं एक BOOL बनाने और उन्हें -updateConstraintsUIView (या -updateViewConstraints, UIViewController के लिए) स्थापित करने की सलाह देता हूं ।

-[UIView updateConstraints]: (सेब डॉक्स)

कस्टम विचार जो स्वयं को विवश करते हैं उन्हें इस विधि को ओवरराइड करके करना चाहिए।

दोनों -updateConstraintsऔर -updateViewConstraintsएक दृश्य के जीवनकाल के दौरान कई बार कहा जा सकता है। ( setNeedsUpdateConstraintsउदाहरण के लिए कॉल करने से यह ट्रिगर होगा, उदाहरण के लिए।) परिणामस्वरूप, आपको डुप्लिकेट बाधाओं को बनाने और सक्रिय करने से रोकने के लिए सुनिश्चित करने की आवश्यकता है - या तो केवल एक बार केवल कुछ बाधा सेटअप करने के लिए BOOL का उपयोग करके, या सुनिश्चित करके। नए लोगों को बनाने और सक्रिय करने से पहले मौजूदा बाधाओं को निष्क्रिय करने / हटाने के लिए।

उदाहरण के लिए:

  - (void)updateConstraints {  // for view controllers, use -updateViewConstraints

         if (!_hasLoadedConstraints) {
              _hasLoadedConstraints = YES;
             // create your constraints
         }
         [super updateConstraints];
    }

टिप्पणी के लिए @fresidue को चीयर्स कि एप्पल के डॉक्स superअंतिम चरण के रूप में कॉल करने की सलाह देते हैं । यदि आप superकुछ बाधाओं में बदलाव करने से पहले फोन करते हैं, तो आप रनटाइम अपवाद (क्रैश) को मार सकते हैं।


7
मुझे यकीन नहीं है कि यह व्यावहारिक रूप से कोई अंतर करता है, लेकिन प्रलेखन कहता है कि 'महत्वपूर्ण: कॉल [सुपर अपडेटकंस्ट्रक्ट] अपने कार्यान्वयन में अंतिम चरण के रूप में।'
fresidue

डॉक्स के अनुसार यदि आप रनटाइम पर एक दृश्य बदलते हैं और अपनी बाधाओं को अमान्य करते हैं, तो सिस्टम तुरंत उस बाधा को हटा देता है और setNeedsUpdateConstraints को कॉल करता है। एक नया लेआउट करने से पहले सिस्टम कॉल अपडेट करता है जहां आप अमान्य लेआउट को अनुकूलित कर सकते हैं। जैसे, मैं शायद इस पद्धति पर एक ध्वज स्थापित नहीं करूंगा, जो सिस्टम को इसे कॉल करने से रोक सकता है।
स्माइलबोट

1
यदि आप इस उत्तर में सुझाए गए अनुसार BOOL ध्वज का उपयोग करते हैं, तो यह केवल आपके कुछ अवरोधों को एक से अधिक बार जोड़े जाने से रोकने के लिए है। यह पूरी तरह से ठीक है। एक अन्य विकल्प केवल आपके द्वारा बनाई गई किसी भी बाधा के संदर्भ को संग्रहीत करना है, और फिर किसी भी नए को बनाने और सक्रिय करने से पहले उन सभी को निकालना (निष्क्रिय करना) सुनिश्चित करें। यह दृष्टिकोण हालांकि, बदतर प्रदर्शन को प्रभावित करेगा, खासकर यदि आपके पुराने और नए अवरोध सटीक हैं।
स्माइबॉर्ग

2
@cocoanutmobile इसके अलावा, ध्यान दें कि यहां BOOL ध्वज सिस्टम को कॉल -updateConstraintsया कुछ भी करने से रोकता नहीं है - यह अभी भी कॉल किया जाएगा, और आप अभी भी कॉल करते हैं [super updateConstraints]
स्माइबॉर्ग

1
जैसा कि @fresidue ने उल्लेख किया है, superअपने -updateConstraintsया के कार्यान्वयन के बहुत अंत में कॉल करना सुनिश्चित करें -updateViewConstraints। अधिक जानकारी के लिए यह टिप्पणी देखें ।
स्माइबॉर्ग

4

यह Apple और WW प्रलेखन से WWDC वीडियो के अनुसार, ViewDidLoad में किया जाना चाहिए।

पता नहीं क्यों लोग अपडेटकॉन्स्ट्रक्ट्स की सिफारिश करते हैं। यदि आप अद्यतनों में काम करते हैं तो आप NSAutoresizingMaskLayoutConstraint के साथ ऑटो रिसाइज़िंग के साथ मुद्दों को हिट करेंगे क्योंकि आपके विचार पहले ही ऑटो मास्क को ध्यान में रखते हैं। काम करने के लिए आपको उन्हें अपडेटडोनस्ट्रेन्ट में निकालना होगा।

UpdateConstraints सिर्फ उस के लिए होना चाहिए, जब आपको उन्हें 'अपडेट' करने की आवश्यकता हो, तो अपने प्रारंभिक सेटअप से बदलाव करें आदि।


1
क्या आप उस वीडियो और प्रलेखन के लिंक जोड़ सकते हैं जिसका आप यहाँ उल्लेख कर रहे हैं।
शिवम पोखरियाल

2

इसे देखने के लेआउट लेआउट विधि किया था

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
}

1

मेरे पास यह समाधान है कि स्टोरीबोर्ड में लोड होने से पहले बाधाओं को बदल दिया जाए। यह समाधान दृश्य लोड होने के बाद किसी भी अंतराल को हटा देता है।

-(void)updateViewConstraints{

    dispatch_async(dispatch_get_main_queue(), ^{

            //Modify here your Constraint -> Activate the new constraint and deactivate the old one

            self.yourContraintA.active = true;
            self.yourContraintB.active= false;
            //ecc..
           });

    [super updateViewConstraints]; // This must be the last thing that you do here -> if! ->Crash!
}

1

आप उन्हें में सेट कर सकते हैं viewWillLayoutSubviews: भी:

 override func viewWillLayoutSubviews() {

    if(!wasViewLoaded){
        wasViewLoaded = true

        //update constraint

        //also maybe add a subview            
    }
}

0

यह मेरे लिए काम किया:

स्विफ्ट 4.2

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

// Modify your constraints in here

  ...

}

हालांकि ईमानदारी से मुझे यकीन नहीं है कि अगर यह इसके लायक है। यह देखने में थोड़ा धीमा लगता है। मैं उन्हें बाद के बाहर ले जाना चाहता था, क्योंकि यह बड़े पैमाने पर हो रहा है।


0

निम्न उदाहरण किसी भी दृश्य को किसी अन्य कक्षा में पास करना है। स्टोरीबोर्ड से मेरा विचार बनाएं

स्विफ्ट 5.0

    override func viewWillAppear(_ animated: Bool) {
        
      super.viewWillAppear(animated) 
        DispatchQueue.main.async {
            self.abcInstance = ABC(frame: self.myView.frame)
          } 
      }

 

यदि आप DispatchQueue.main.async को मिस करते हैं, तो viewWillAppear में बाधाओं को अपडेट करने में समय लगेगा। स्टोरीबोर्ड में myView बनाएं और स्क्रीन की चौड़ाई और ऊँचाई के समान अड़चनें दें, फिर myView का प्रिंटिंग फ़्रेम आज़माएं। यह DispatchQueue.main.async या viewDidAppear में सटीक मान देगा, लेकिन DispatchQueue.main.async के बिना viewWillAppear में सटीक मूल्य नहीं देगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.