लेआउट कब कहा जाता है?


264

मेरे पास एक कस्टम दृश्य है जिसे layoutSubviewएनीमेशन के दौरान संदेश नहीं मिल रहे हैं ।

मेरे पास एक दृश्य है जो स्क्रीन को भरता है। स्क्रीन के निचले भाग में एक कस्टम सबव्यू है जो कि इंटरफ़ेस बार में सही ढंग से आकार लेता है अगर मैं नेव बार की ऊंचाई को बदल देता हूं। layoutSubviewsकहा जाता है जब दृश्य बनाया जाता है, लेकिन फिर कभी नहीं। मेरे साक्षात्कार सही ढंग से निर्धारित किए गए हैं। अगर मैं इन-कॉल स्टेटस बार को बंद कर देता हूं, तो सबव्यू को कॉल layoutSubviewsनहीं किया जाता है, भले ही मुख्य दृश्य इसके आकार को चेतन करता है।

किन परिस्थितियों में layoutSubviewsवास्तव में कहा जाता है?

मैंने अपने कस्टम दृश्य के लिए autoresizesSubviewsसेट कर दिया है NO। और इंटरफ़ेस बिल्डर में मेरे पास ऊपर और नीचे स्ट्रट्स और ऊर्ध्वाधर तीर सेट है।


पहेली का एक और हिस्सा यह है कि खिड़की को मुख्य बनाया जाना चाहिए:

[window makeKeyAndVisible];

अन्य सभी उप-सूचियों का स्वचालित रूप से आकार परिवर्तन नहीं होता है।

जवाबों:


492

मेरे पास एक समान प्रश्न था, लेकिन जवाब से संतुष्ट नहीं था (या कोई भी मुझे नेट पर मिल सकता था), इसलिए मैंने इसे अभ्यास में आजमाया और यहां मुझे वही मिला:

  • initlayoutSubviews(डुह) कहलाने का कारण नहीं है
  • addSubview:layoutSubviewsजोड़े जाने वाले दृश्य पर कॉल करने का कारण , वह दृश्य जिसे (लक्ष्य दृश्य) में जोड़ा जा रहा है, और लक्ष्य के सभी उपखंड
  • दृश्य setFrame समझदारी से कॉल layoutSubviewsइसके फ्रेम सेट होने ही अगर फ्रेम के आकार पैरामीटर अलग है दृश्य पर
  • UIScrollView layoutSubviewsको स्क्रॉल करने का कारण स्क्रॉल दृश्य, और इसके पर्यवेक्षण पर कहा जाता है
  • डिवाइस को घुमाने से केवल layoutSubviewपैरेंट व्यू पर कॉलिंग होती है (रिस्पांसिंग व्यू कंट्रोलर प्राइमरी व्यू)
  • एक दृश्य का आकार बदलना layoutSubviewsउसके पर्यवेक्षण पर कॉल करेगा

मेरे परिणाम - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-allall/


1
बहुत बढ़िया जवाब। मुझे हमेशा से आश्चर्य होता रहा है layoutSubviews। है initWithFrame:कारण layoutSubviewsके नाम से जाना?
रॉबर्ट

2
@ रॉबर्ट - मैं initWithFrame का उपयोग कर रहा था ... इसलिए नहीं।
BadPirate

8
@BadPirate: हाँ । मेरे प्रयोगों के अनुसार, यदि आप view1.1इसे और फिर के कॉल layoutSubviewsका आकार परिवर्तन करते हैं । यह कॉल पर्यवेक्षकों को अनिश्चित काल के लिए प्रचारित नहीं करता है, केवल कॉल ऑन और । बस आकार बदलने के बिना घूमना उनमें से किसी पर कॉल नहीं करता है। view1layoutSubviewsview1.1view1.1.1layoutSubviewsview1.1view1.1.1layoutSubviews
जोहो पोर्टेला

1
viewDidLoad को UIView (लेकिन UIViewController) नहीं कहा जाता है। UIView के init'd के बाद View Did load कहलाता है।
बैडपिरेट

2
अपने प्रयोग के आधार पर, दूसरा नियम सही नहीं हो सकता: जब मैं जोड़ने view1.2में view1, layoutSubviewsकी view1.2और view1कहा जाता है, लेकिन layoutSubviewsकी view1.1नहीं बुलाया जाता है। ( view1.1और के view1.2साक्षात्कार हैं view1)। अर्थात्, लक्ष्य दृश्य के सभी उप- layoutSubviewsविधि को विधि नहीं कहा जाता है
होंगचॉन्ग

96

@BadPirate द्वारा पिछले उत्तर पर निर्माण, मैंने थोड़ा आगे प्रयोग किया और कुछ स्पष्टीकरण / सुधार के साथ आया। मैंने पाया कि layoutSubviews:अगर और केवल अगर एक दृश्य पर बुलाया जाएगा:

  • इसकी अपनी सीमाएं (फ्रेम नहीं) बदल गईं।
  • इसके एक प्रत्यक्ष साक्षात्कार की सीमा बदल गई।
  • एक सबव्यू दृश्य में जोड़ा जाता है या दृश्य से हटा दिया जाता है।

कुछ प्रासंगिक विवरण:

  • सीमा को केवल तभी माना जाता है जब नया मूल्य अलग हो, जिसमें एक अलग मूल भी शामिल हो । ध्यान दें कि layoutSubviews:जब भी UIScrollView स्क्रॉल होता है, तो इसे क्यों कहा जाता है, क्योंकि यह अपनी सीमा के मूल को बदलकर स्क्रॉल करता है।
  • फ्रेम को बदलने से केवल सीमा बदल जाएगी यदि आकार बदल गया है, क्योंकि यह एकमात्र संपत्ति सीमा संपत्ति के लिए प्रचारित है।
  • किसी दृश्य की सीमा में परिवर्तन जो अभी तक दृश्य पदानुक्रम में नहीं है, इसका परिणाम layoutSubviews: तब होगा जब दृश्य अंत में दृश्य पदानुक्रम में जोड़ा जाएगा
  • और सिर्फ पूर्णता के लिए: ये ट्रिगर्स सीधे लेआउटसुब्यू को कॉल नहीं करते हैं , बल्कि कॉल करते हैं setNeedsLayout, जो एक ध्वज को सेट / बढ़ाता है। रन लूप के प्रत्येक पुनरावृत्ति, पदानुक्रम में सभी दृश्यों के लिए , इस ध्वज की जाँच की जाती है। प्रत्येक दृश्य के लिए जहां झंडा उठा हुआ पाया layoutSubviews:जाता है, उस पर कॉल किया जाता है और ध्वज को रीसेट कर दिया जाता है। उच्चतर पदानुक्रम की जाँच की जाएगी / पहले बुलाया जाएगा।

5
इस उत्तर को पर्याप्त नहीं बना सकते। यह शीर्ष उत्तर होना चाहिए। दिए गए तीन नियम आप सभी की जरूरत है मैं कभी भी किसी भी लेआउट व्यवहार में नहीं आया हूं जो इन नियमों का पूरी तरह से वर्णन नहीं करता है।
पर्ट्सेक

1
मुझे नहीं लगता कि लेआउट को देखा जाता है जब प्रत्यक्ष उप-सीमा के परिवर्तन को कहा जाता है। मुझे लगता है कि लेआउटसुब्यू का बुलावा आपके परीक्षण का एक दुष्प्रभाव है। कुछ मामलों में लेआउट्सब्यूव्यू तब नहीं बुलाया जाएगा जब एक सबव्यू सीमा बदल जाती है। कृपया मेंढक के उत्तर की जांच करें, क्योंकि उसका एवरर केवल प्रयोगों के बजाय एप्पल द्वारा प्रलेखन पर आधारित है।
साइमन बैकएक्स

19

https://developer.apple.com/library/prerelease/tvos/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html#//apple_ref/doc/uid/TP40009503-CH5-SW1

जब भी निम्न में से कोई भी घटना किसी दृश्य में होती है, तो लेआउट परिवर्तन हो सकते हैं:

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


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

13

BadPirate के उत्तर में कुछ बिंदु केवल आंशिक रूप से सत्य हैं:

  1. के लिए addSubViewबिंदु

    addSubview लेआउट्सब्यूब्स के कारण जोड़े जाने वाले दृश्य पर कॉल किया जा सकता है, वह दृश्य जिसे (लक्ष्य दृश्य) में जोड़ा जा रहा है, और लक्ष्य के सभी साक्षात्कार।

    यह दृश्य (लक्ष्य दृश्य) पर निर्भर करता है ऑटोरेस्ज़ मास्क। यदि इसमें ऑटोरेसेज़ मास्क ऑन है, तो प्रत्येक पर लेआउटसुब्यू को बुलाया जाएगा addSubview। यदि इसमें कोई ऑटोरेस्पोन्ग मास्क नहीं है, तो लेआउटसुब्यू को केवल तभी कहा जाएगा जब दृश्य का (लक्ष्य देखें) फ्रेम आकार बदल जाता है।

    उदाहरण: यदि आपने यूआईवीवाई को प्रोग्रामेटिक रूप से बनाया है (इसमें डिफ़ॉल्ट रूप से कोई ऑटोरेस्ज़ मास्क नहीं है), तो लेआउटब्यूव्यू केवल तभी कहा जाएगा जब यूआईवीवाईई फ्रेम हर पर नहीं बदलता है addSubview

    यह इस तकनीक के माध्यम से है कि आवेदन का प्रदर्शन भी बढ़ता है।

  2. डिवाइस रोटेशन बिंदु के लिए

    डिवाइस को घुमाने से केवल लेआउट दिखाई देता है (पेरेंट व्यू का जवाब देने वाला व्यूकंट्रोलर का प्राथमिक दृश्य)

    यह तभी सही हो सकता है जब आपका वीसी वीसी पदानुक्रम (रूट पर window.rootViewController) में हो, खैर यह सबसे आम मामला है। IOS 5 में, यदि आप एक VC बनाते हैं, लेकिन इसे किसी अन्य VC में नहीं जोड़ा जाता है, तो डिवाइस के घूमने पर इस VC पर कोई ध्यान नहीं जाएगा। इसलिए इसका दृश्य लेआउटसुब्यू को कॉल करके नहीं देखा जाएगा।


9

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

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

इसे डीबग करने में एक अतिरिक्त समस्या यह है कि जब मेनू में इन-कॉल स्थिति टॉगल की जाती है, तो सिम्युलेटर ऐप को छोड़ देता है। ऐप छोड़ें = कोई डिबगर नहीं।


क्या आप यह कह रहे हैं कि लेआउट को देखा जाता है जब दृश्य को आकार दिया जाता है? मैंने हमेशा माना कि यह नहीं है ...
एंड्री टारनटोसव

यह है। जब एक दृश्य का आकार बदला जाता है तो उसे अपने उप-साक्षात्कारों के साथ कुछ करने की आवश्यकता होती है। यदि आप इसे प्रदान नहीं करते हैं, तो यह उन्हें स्प्रिंग्स, स्ट्रट्स आदि का उपयोग करके स्वचालित रूप से स्थानांतरित करता है
स्टीव वेलर

8

बुला [self.view setNeedsLayout]; ViewController में कॉल viewDidLayoutSubviews के लिए बनाता


5

क्या आपने लेआउट पर ध्यान दिया है

प्रलेखन स्निपेट नीचे है। यदि आप एनीमेशन के दौरान इस विधि को स्पष्ट रूप से कहते हैं, तो क्या एनीमेशन काम करता है?

अगर जरूरत हो, तो लेआउटइन्फाइड किए गए सबव्यू को छोड़ देता है।

- (void)layoutIfNeeded

चर्चा इस पद्धति का उपयोग ड्राइंग से पहले साक्षात्कार के लेआउट को मजबूर करने के लिए करें।

उपलब्धता iPhone OS 2.0 और बाद में उपलब्ध है।


2

जब SDK 3 से 4 के लिए एक OpenGL एप्लिकेशन को माइग्रेट किया जा रहा है, तो लेआउटसुब्यू को अब नहीं बुलाया गया था। बहुत सारे परीक्षण और त्रुटि के बाद मैंने अंततः मेनविंडो। Xib को खोला, विंडो ऑब्जेक्ट का चयन किया, निरीक्षक में विंडो एट्रिब्यूट्स टैब (सबसे बाईं ओर) चुना और "लॉन्च पर दिखाई" की जाँच की। ऐसा लगता है कि एसडीके 3 में यह अभी भी एक लेआउटसुब्यू का कारण बनता है, लेकिन 4 में नहीं।

6 घंटे की घबराहट खत्म हुई।


क्या आपने खिड़की की चाबी बनाई? यदि नहीं, तो यह सभी प्रकार की दिलचस्प चीजें नहीं होने का कारण बन सकता है।
स्टीव वेलर

-2

एक बल्कि अस्पष्ट, फिर भी संभावित रूप से महत्वपूर्ण मामला जब layoutSubviewsकभी नहीं कहा जाता है:

import UIKit

class View: UIView {

    override class var layerClass: AnyClass { return Layer.self }

    class Layer: CALayer {
        override func layoutSublayers() {
            // if we don't call super.layoutSublayers()...
            print(type(of: self), #function)
        }
    }

    override func layoutSubviews() {
        // ... this method never gets called by the OS!
        print(type(of: self), #function)
    }
}

let view = View(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

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