ऑटोलयूट बाधाओं का उपयोग करते समय मैं एक दृश्य की वर्तमान चौड़ाई और ऊंचाई कैसे प्राप्त कर सकता हूं?


108

मैं फ्रेम प्रॉपर्टी के बारे में बात नहीं कर रहा हूं, क्योंकि इससे आप केवल xib में व्यू का आकार प्राप्त कर सकते हैं। मैं इस बारे में बात कर रहा हूं कि कब इसकी बाधाओं के कारण आकार बदला गया है (शायद एक रोटेशन के बाद, या किसी घटना के जवाब में)। क्या इसकी वर्तमान चौड़ाई और ऊंचाई पाने का कोई तरीका है?

मैंने इसकी कमी के माध्यम से चौड़ाई और ऊंचाई की कमी की तलाश करने की कोशिश की, लेकिन यह बहुत साफ नहीं है और जब आंतरिक बाधाएं होती हैं (तब से मैं दोनों के बीच अंतर नहीं कर सकता)। इसके अलावा, यह केवल तभी काम करता है जब उनके पास वास्तव में चौड़ाई और ऊंचाई की बाधाएं होती हैं, जो कि वे नहीं करते हैं यदि वे आकार बदलने के लिए अन्य बाधाओं पर भरोसा करते हैं।

मेरे लिए यह इतना मुश्किल क्यों है। ARG!


मैंने सोचा होगा कि किसी विशेष समय में दृश्य की सीमा इसकी वर्तमान चौड़ाई और ऊँचाई पर होती है। लेआउट प्रक्रिया के दौरान इसे समायोजित किया जाता है।
फिलिप मिल्स

हम्म मैंने कभी सीमा की जांच करने के लिए नहीं सोचा था। मैं अब वही करूंगा।
युफ

जवाबों:


246

उत्तर है [view layoutIfNeeded]

यहाँ पर क्यों:

आप अभी भी निरीक्षण करके view.bounds.size.widthऔर view.bounds.size.height(या फ्रेम, जो तब तक बराबर है जब तक आप के साथ खेल रहे हों , दृश्य की वर्तमान चौड़ाई और ऊंचाई प्राप्त नहीं कर सकतेview.transform ) ।

यदि आप चाहते हैं कि आपके मौजूदा अवरोधों द्वारा निहित चौड़ाई और ऊंचाई है, तो इसका जवाब मैन्युअल रूप से बाधाओं का निरीक्षण नहीं करना है, क्योंकि आपको उन लोगों की व्याख्या करने के लिए ऑटो लेआउट सिस्टम के संपूर्ण बाधा-समाधान तर्क को फिर से लागू करना होगा। बाधाओं। इसके बजाय, आपको जो करना चाहिए वह उस लेआउट को अपडेट करने के लिए बस ऑटो लेआउट से पूछें , ताकि यह बाधाओं को हल करता है और सही समाधान के साथ view.bounds के मान को अपडेट करता है, और फिर आप view.bounds का निरीक्षण करते हैं।

आप लेआउट को अपडेट करने के लिए ऑटो लेआउट से कैसे पूछेंगे? कॉल[view setNeedsLayout] यदि आप रन लूप के अगले मोड़ पर लेआउट को अपडेट करने के लिए ऑटो लेआउट चाहते हैं।

हालाँकि, यदि आप चाहते हैं कि यह लेआउट को तुरंत अपडेट करे, तो आप तुरंत अपने मौजूदा फ़ंक्शन के भीतर या बाद में रन लूप के मोड़ से पहले किसी अन्य बिंदु पर नए सीमा मूल्य तक पहुंच सकते हैं , फिर आपको कॉल करने की आवश्यकता है [view setNeedsLayout]और [view layoutIfNeeded]

आपने दूसरा प्रश्न पूछा: "अगर मैं सीधे इसका संदर्भ नहीं रखता तो मैं ऊंचाई / चौड़ाई की बाधा कैसे बदल सकता हूं?"

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


16
एक उत्कृष्ट उत्तर और अच्छी तरह से समझाया गया है। एक-दो घंटे के बाद मेरे बाल खींचकर मुझे बचाया।
बेन क्रीगर

2
layoutIfNeededमहान है, और फ्रेम को तुरंत उपलब्ध कराएगा। हालांकि, यह उन सभी विचारों पर बाधाओं के प्रतिपादन को भी मजबूर कर देगा, जिन पर इसे कहा जाता है। यदि आप उदाहरण के लिए प्रोग्राम को जोड़ रहे हैं, और layoutIfNeededअपनी पुनरावर्ती दिनचर्या में उन सभी को कॉल करते हैं, तो आप पा सकते हैं कि आपका दृष्टिकोण पदानुक्रम बहुत धीरे-धीरे प्रस्तुत करता है। (मैंने इसे कठिन तरीके से सीखा) जैसा कि उत्कृष्ट उत्तर में बताया गया है, 'setNeedsLayout` अधिक कुशल है और फ्रेम को अगले लेआउट पास पर उपलब्ध कराएगा, जो आदर्श रूप से एक सेकंड के लगभग 1/60 वें हिस्से में होता है।
शमीम

1
मुझे पता है कि यह पुराना है, लेकिन आप इस विधि को कहां कहते हैं? में initWithCoder?
MayNotBe

4
केवल सीमा पाने के लिए लेआउट को क्यों मजबूर करें? यह अक्षम लगता है और एक जटिल इंटरफ़ेस के साथ यह संभवतः महंगा होने जा रहा है। इसके बजाय viewDidLayoutSubviews या यहां तक ​​कि viewWillLayoutSubviews से नवीनतम सीमा तक पहुंचें और कोको को अपने स्वयं के लेआउट समय को संभालने दें। यदि आपको कोई समस्या है तो कई कॉल से बचने के लिए मान या ध्वज को एक्सेस करने की आवश्यकता है, तो एक संपत्ति सेट करें।
स्माइलबोट

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

8

मेरे पास एक ऐसा ही मुद्दा था जहां मुझे एक ऊपरी और नीचे की सीमा को जोड़ने की आवश्यकता थी जो UITableViewकि अपने अवरोधों के सेटअप के आधार पर आकार बदलता है UIStoryboard। मैं के साथ अद्यतन बाधाओं का उपयोग करने में सक्षम था - (void)viewDidLayoutSubviews। यह उपयोगी है ताकि आपको किसी दृश्य को देखने और उसकी लेआउट विधि को ओवरराइड करने की आवश्यकता न हो।

/*** SET TOP AND BOTTOM BORDERS ON TABLE VIEW ***/
- (void)addBorders
{
    CALayer *topBorder           = [CALayer layer];
    topBorder.frame              = CGRectMake(0.0f, self.tableView.frame.origin.y, 320.0f, 0.5f);
    topBorder.backgroundColor    = [UIColor redColor].CGColor;

    CALayer *bottomBorder        = [CALayer layer];
    bottomBorder.frame           = CGRectMake(0.0f, (self.tableView.frame.origin.y + self.tableView.frame.size.height), 320.0f, 0.5f);
    bottomBorder.backgroundColor = [UIColor redColor].CGColor;

    [self.view.layer addSublayer:topBorder];
    [self.view.layer addSublayer:bottomBorder];
}

/*** GET AUTORESIZED FRAME DIMENSIONS ***/
- (void)viewDidLayoutSubviews{
    [self addBorders];
}

विधि से विधि को कॉल किए बिना viewDidLayoutSubview, केवल शीर्ष सीमा सही ढंग से खींची गई है, क्योंकि नीचे की सीमा कहीं-कहीं ऑफस्क्रीन है।


3
viewDidLayoutSubviews कई बार बुलाया जा रहा है, तो आप परतों के टन पैदा कर रहे ... आप जोड़ने से पहले कुछ अस्तित्व चेकों जोड़ने की जरूरत है एक और परत।
कालजाम

कुछ साल देर से टिप्पणी करें ... आपको इस विधि को सुपरक्लास पर भी कॉल करना चाहिए जब कुछ भी करने से पहले ओवरराइड करना हो:[super viewDidLayoutSubviews];
एलेजांद्रो इवान

5

उन लोगों के लिए जो अभी भी ऐसे मुद्दों का सामना कर रहे हैं, खासकर टेबलव्यूसेल के साथ।

बस विधि को ओवरराइड करें:

-(void)layoutSubviews
{
//your code here like drawing a shadow
}

UITableViewCell या UICollectionViewCell के मामले में सेल का एक उपवर्ग बनाएँ और एक ही ओवरराइड करें:

-(void)layoutSubviews
{
//your code here like drawing a shadow
}

यह एकमात्र तरीका है जिससे मैं अपने विचार का वास्तविक अंतिम आकार प्राप्त कर सकता हूं
बेनोइट जैडिनॉन

यह एकमात्र तरीका था कि मैं अपने किसी भी विवश विचार के लिए अंतिम आकार प्राप्त करने में सक्षम था, क्योंकि इससे पहले कि मैं उन्हें जागृत करने की कोशिश कर रहा था, जो कि वास्तव में पहले आकार देने के लिए साक्षात्कार का समय नहीं देते थे। धन्यवाद!
अजिन मेहरनोश

3

उपयोग -(void)viewWillAppear:(BOOL)animatedऔर कॉल [self.view layoutIfNeeded];- यह मेरे द्वारा आजमाया गया काम है।

क्योंकि यदि आप इसका उपयोग करते हैं तो -(void)viewDidLayoutSubviewsयह निश्चित रूप से काम करेगा लेकिन इस विधि को हर बार कहा जाता है जब आपका UI अपडेशन / बदलाव की मांग करता है। जिसे मैनेज करना मुश्किल हो जाएगा। सॉफ्ट कुंजी आप कॉल के ऐसे लूप से बचने के लिए बूल वेरिएबल का उपयोग करते हैं। बेहतर उपयोग viewWillAppear। याद रखना viewWillAppearभी कहा जाएगा यदि दृश्य फिर से लोड किया गया है (बिना reallocating)।


2

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


1
मैं अन्यथा देख रहा हूं। फ्रेम मान नहीं बदलते हैं, यहां तक ​​कि सीधे चौड़ाई / ऊंचाई की सीमाओं को बदलने के बाद (उनके स्थिरांक को बदलकर। मेरे पास उनके लिए एक IBOutlet है xib में)
yuf

मेरी समस्या अद्वितीय है क्योंकि मैं बाधा को बदल देता हूं, फिर उसी फ़ंक्शन में फ़्रेम का उपयोग करने की आवश्यकता होती है। SetNeedsLayout को कॉल करना तुरंत इसे अपडेट नहीं करता है। मुझे लगता है कि मुझे पहले लेआउट के लिए प्रतीक्षा करने की आवश्यकता है फिर फ्रेम का उपयोग करें। मेरा दूसरा सवाल यह है कि अगर मैं सीधे इसका संदर्भ नहीं रखता तो मैं ऊंचाई / चौड़ाई की बाधा कैसे बदल सकता हूं?
युफ

1
आपको तब डिस्पैच_संकल्प भेजना चाहिए, और यह आपको अगले फ्रेम तक अपने कोड में देरी करने की अनुमति देगा। दूसरे भाग के रूप में ... मुझे नहीं पता ... आपको सभी बाधाओं को दूर करना होगा और यह देखना होगा कि कौन सा लागू है ... IBOutlets बहुत आसान हैं।
बॉनरडेन

IBOutlets के लिए सही है, लेकिन मैं एक UIView के लिए एक श्रेणी में एक फ़ंक्शन लिखना चाहता हूं जिसमें मेरे पास काम करने के लिए आईबी नहीं होगा।
युफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.