setNeedsLayout बनाम setNeedsUpdateConstraints और LayoutIfNeeded बनाम अपडेट


227

मुझे पता है कि ऑटो लेआउट श्रृंखला में मूल रूप से 3 अलग-अलग प्रक्रिया शामिल हैं।

  1. बाधाओं को अद्यतन करना
  2. लेआउट दृश्य (यहां हम फ्रेम की गणना प्राप्त करते हैं)
  3. प्रदर्शन

जो मेरे लिए पूरी तरह से स्पष्ट नहीं है, वह आंतरिक अंतर है -setNeedsLayoutऔर -setNeedsUpdateConstraints। Apple डॉक्स से:

setNeedsLayout

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

setNeedsUpdateConstraints

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

जब मैं एक बाधा को संशोधित करने के बाद एक दृश्य को चेतन करना चाहता हूं और उन परिवर्तनों को चेतन करता हूं जिन्हें मैं आमतौर पर उदाहरण के लिए कहता हूं:

[UIView animateWithDuration:1.0f delay:0.0f usingSpringWithDamping:0.5f initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        [self.modifConstrView setNeedsUpdateConstraints];
        [self.modifConstrView layoutIfNeeded];
    } completion:NULL];

मुझे पता चला है कि अगर मैं अपेक्षा -setNeedsLayoutके अनुसार -setNeedsUpdateConstraintsहर काम के बजाय उपयोग करता हूं , लेकिन अगर मैं बदल -layoutIfNeededजाता हूं -updateConstraintsIfNeeded, तो एनीमेशन नहीं होगा।
मैंने अपना निष्कर्ष निकालने की कोशिश की है:

  • -updateConstraintsIfNeeded केवल अपडेट की कमी है, लेकिन लेआउट को इस प्रक्रिया में आने के लिए मजबूर नहीं करता है, इस प्रकार मूल फ्रेम अभी भी संरक्षित हैं
  • -setNeedsLayoutकॉल भी -updateContraintsविधि

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


27
मुझे समझ में नहीं आ रहा है कि लोग वास्तव में ... तो आपको इसके बारे में कुछ करना चाहिए, जैसे कि एक कारण पूछना अनिवार्य है या वे पूरी तरह से व्यर्थ हैं
एंड्रिया

7
शायद उन्हें सिर्फ क्रिटिक बैज (फर्स्ट डाउन वोट) प्राप्त करने की आवश्यकता है
fujianjin6471

1
मैं आपको यहां देखने की अत्यधिक सलाह देता हूं । इसका जवाब एक वास्तविक समस्या का समाधान है। इस वीडियो को
Honey

जवाबों:


258

आपके निष्कर्ष सही हैं। मूल योजना है:

  • setNeedsUpdateConstraintsभविष्य कॉल करने के लिए सुनिश्चित updateConstraintsIfNeededकरता है updateConstraints
  • setNeedsLayoutभविष्य कॉल करने के लिए सुनिश्चित layoutIfNeededकरता है layoutSubviews

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

का उपयोग करते हुए बाधाओं को अद्यतन करना setNeedsUpdateConstraintsबहुत दुर्लभ है, objc.io- ऑटोलैयूट्स के बारे में अवश्य पढ़ें- कहते हैं :

यदि बाद में कुछ बदल जाता है जो आपके किसी अवरोध को अमान्य कर देता है, तो आपको बाधा को तुरंत हटा देना चाहिए और setNeedsUpdateConstraints को कॉल करना चाहिए। वास्तव में, यह एकमात्र मामला है जहां आपको एक बाधा अद्यतन पास को ट्रिगर करना चाहिए।

इसके अलावा, मेरे अनुभव में, मुझे कभी भी बाधाओं को अमान्य नहीं करना पड़ा है, और setNeedsLayoutकोड की अगली पंक्ति में सेट नहीं किया गया है, क्योंकि नई बाधाएं बहुत कुछ एक नए लेआउट के लिए पूछ रही हैं।

अंगूठे के नियम हैं:

  • यदि आपने सीधे तौर पर बाधाओं का हेरफेर किया है, तो कॉल करें setNeedsLayout
  • यदि आपने कुछ शर्तों (जैसे ऑफ़सेट या स्मथ) को बदल दिया है जो आपके ओवरराइड updateConstraintsविधि में बाधाओं को बदल देगा (बाधाओं को बदलने के लिए एक अनुशंसित तरीका, btw), कॉल setNeedsUpdateConstraints, और अधिकांश समय, setNeedsLayoutउसके बाद।
  • यदि आपको तत्काल प्रभाव डालने के लिए उपरोक्त किसी भी क्रिया की आवश्यकता है - जैसे कि जब लेआउट पास होने के बाद आपकी नई फ़्रेम ऊंचाई सीखने की आवश्यकता होती है - तो इसे एक के साथ जोड़ें layoutIfNeeded

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


@coverback, इसलिए objc.io का कहना है कि "अगर बाद में कुछ बदल जाता है जो आपके किसी अवरोध को अमान्य कर देता है, तो आपको बाधा को तुरंत हटा देना चाहिए और setNeedsUpdateConstraints को कॉल करना चाहिए। वास्तव में, यह एकमात्र मामला है जहां आपको एक बाधा अद्यतन पास को ट्रिगर करना होगा।" और फिर एनीमेशन ब्लॉक में यह कहा गया है कि जब मैं हटाता हूं, तो बाधाएं जोड़ें या बदलें। मुझे कॉल सेट करना होगा। क्या फर्क पड़ता है? मुझे असली बेवकूफी महसूस होती है :(
pash3r

3
@ pash3r अंतर अपडेट हो रहा है निरंतर "अमान्य" के रूप में योग्य नहीं है। अमान्य तब है जब यह अब बिल्कुल भी प्रासंगिक नहीं है, जैसे किसी अन्य दृश्य के साथ संलग्न होना है या पूरी तरह से हटा दिया गया है। लगातार केवल एक दृश्य को निकट या दूर तक ले जाएगा, या इसके आकार को बदल देगा, इस प्रकार इसकी आवश्यकता है setNeedsLayout
कवरबैक

@ कोवरबैक setNeedsLayoutयह सुनिश्चित करता है कि layoutSubviewsअगले अपडेटिंग चक्र में बुलाया जाएगा, लेकिन शायद इससे कोई लेना-देना नहीं है layoutIfNeeded?
फुजियानजिन6471

2
@ कोवरबैक यदि आप बाधाओं को सीधे जोड़ते हैं, layoutSubviewsतो स्वचालित रूप से कॉल किया जाएगा, कॉल करने की आवश्यकता नहीं हैsetNeedsLayout
fujianjin6471

हां, एक बाधा के गुणों को सीधे हेरफेर करने से ट्रिगर हो जाएगा layoutSubviews, इसलिए इसे मैन्युअल रूप से करने की आवश्यकता नहीं है। हालांकि, layoutIfNeededअगर आपको अगले लेआउट चक्र के बजाय तुरंत प्रभाव लेने के लिए परिवर्तनों की आवश्यकता है , तो कॉल करना होगा
चार्ली मार्टिन

89

Coverback द्वारा जवाब बहुत सही है। हालाँकि, मैं कुछ अतिरिक्त विवरण जोड़ना चाहूंगा।

नीचे एक विशिष्ट UIView चक्र का आरेख है जो अन्य व्यवहारों की व्याख्या करता है:

UIView का जीवनचक्र

  1. मुझे पता चला है कि अगर मैं अपेक्षा -setNeedsLayoutके अनुसार -setNeedsUpdateConstraintsहर काम के बजाय उपयोग करता हूं , लेकिन अगर मैं बदल -layoutIfNeededजाता हूं -updateConstraintsIfNeeded, तो एनीमेशन नहीं होगा।

updateConstraintsआमतौर पर कुछ भी नहीं करता है। यह बस उन बाधाओं को हल करता है जब तक layoutSubviewsकि उन्हें बुलाया न जाए। इसलिए एनीमेशन के लिए कॉल की आवश्यकता होती है layoutSubviews

  1. setNeedsLayout भी -updateContraints विधि कहता है

नहीं, यह आवश्यक नहीं है। यदि आपके अवरोधों को संशोधित नहीं किया गया है तो UIView कॉल को छोड़ देगा updateConstraints। आपको setNeedsUpdateConstraintप्रक्रिया में बाधाओं को संशोधित करने के लिए स्पष्ट रूप से कॉल करने की आवश्यकता है ।

कॉल करने के लिए updateConstraintsआपको निम्नलिखित कार्य करने होंगे:

[view setNeedsUpdateConstraints];
[view setNeedsLayout]; 
[view layoutIfNeeded];

धन्यवाद, इससे मेरी समस्या हल हो गई। मेरे पास एक UIWindow था जिसमें कोई अभिभावक UIView नहीं था, जिसमें एक एनीमेशन से पहले LayoutIfNeeded () को कॉल करने पर इसमें अस्थायी बाधाएं थीं। UIWindow में एक सबव्यू रैपर जोड़ना और उस पर इन तीन तरीकों को कॉल करना मेरे मुद्दे को तय करता है।
मास्‍टरवॉक

मुझे नहीं लगता कि setNeedsLayout के सही होने के बाद लेआउट को कॉल करना सही है। क्योंकि विधियां इस तथ्य के बावजूद भी करती हैं कि एक लेआउट को तुरंत फिर से तैयार किया जा रहा है और दूसरा अगले अद्यतन चक्र में।
भराव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.