[संपादित करें: चेतावनी: संपूर्ण आगामी चर्चा संभवतः आईओएस 8 के द्वारा कम या कम से कम भारी रूप से कम कर दी जाएगी, जो उस समय लेआउट को ट्रिगर करने की गलती नहीं कर सकती है कि एक दृश्य परिवर्तन लागू किया जाता है।]
Autolayout बनाम रूपांतरण देखें
ऑटोलैयूट दृश्य रूपांतरों के साथ अच्छी तरह से नहीं खेलता है। कारण, जहाँ तक मैं समझ सकता हूँ, यह है कि आप एक ऐसे दृश्य के फ्रेम के साथ गड़बड़ नहीं कर रहे हैं जिसमें एक परिवर्तन है (डिफ़ॉल्ट पहचान परिवर्तन के अलावा) - लेकिन यह वही है जो ऑटोलेयूट करता है। जिस तरह से ऑटोलैयट काम करता है वह यह है कि layoutSubviews
रनटाइम में सभी बाधाओं के माध्यम से डैशिंग आता है और सभी विचारों के फ्रेम को तदनुसार सेट करता है।
दूसरे शब्दों में, बाधाएं जादू नहीं हैं; वे सिर्फ एक करने के लिए सूची है। layoutSubviews
वह जगह है जहां टू-डू सूची हो जाती है। और यह फ्रेम सेट करके करता है।
मैं बग के रूप में इस बारे में मदद नहीं कर सकता। अगर मैं इस परिवर्तन को एक दृश्य में लागू करता हूं:
v.transform = CGAffineTransformMakeScale(0.5,0.5);
मुझे उम्मीद है कि पहले और आधे आकार में इसके केंद्र के साथ दृश्य दिखाई देगा। लेकिन इसकी बाधाओं के आधार पर, यह वह नहीं हो सकता है जो मैं देख रहा हूं।
[वास्तव में, यहां एक दूसरा आश्चर्य है: एक दृश्य में परिवर्तन को लागू करना लेआउट को तुरंत ट्रिगर करता है। यह मुझे एक और बग लगता है। या शायद यह पहली बग का दिल है। मुझे क्या उम्मीद होगी कि लेआउट समय तक कम से कम एक परिवर्तन के साथ दूर होने में सक्षम हो, जैसे कि डिवाइस को घुमाया जाता है - जैसे मैं लेआउट समय तक फ्रेम एनीमेशन के साथ दूर हो सकता हूं। लेकिन वास्तव में लेआउट का समय तत्काल है, जो गलत लगता है।]
समाधान 1: कोई बाधा नहीं
एक वर्तमान समाधान है, अगर मैं एक दृश्य के लिए एक अर्धचालक परिवर्तन लागू करने जा रहा हूं (और न केवल इसे किसी तरह अस्थायी रूप से बंद कर दूं), जिससे सभी बाधाओं को दूर किया जा सके। दुर्भाग्य से यह आम तौर पर दृश्य को स्क्रीन से गायब करने का कारण बनता है, क्योंकि ऑटोलॉयट अभी भी होता है, और अब हमें यह बताने के लिए कोई बाधा नहीं है कि दृश्य कहां रखा जाए। इसलिए बाधाओं को दूर करने के अलावा, मैंने व्यू translatesAutoresizingMaskIntoConstraints
को YES पर सेट किया । अब दृश्य पुराने तरीके से काम करता है, प्रभावी रूप से ऑटोलेयआउट द्वारा अप्रभावित है। (यह ऑटोलैयूट से प्रभावित है, जाहिर है, लेकिन निहित ऑटोरेस्पोन्ग मुखौटा बाधाओं के कारण इसका व्यवहार वैसा ही हो सकता है जैसा कि ऑटोलॉययट से पहले था।)
समाधान 2: केवल उचित बाधाओं का उपयोग करें
यदि यह थोड़ा कठोर लगता है, तो एक और उपाय यह है कि बाधाओं को एक इच्छित परिवर्तन के साथ सही ढंग से काम करने के लिए सेट किया जाए। यदि किसी दृश्य को उसकी आंतरिक निश्चित चौड़ाई और ऊंचाई के अनुसार शुद्ध रूप से आकार दिया जाता है, और उसके केंद्र द्वारा विशुद्ध रूप से तैनात किया जाता है, उदाहरण के लिए, मेरा स्केल ट्रांसफॉर्मेशन मेरी अपेक्षा के अनुरूप काम करेगा। इस कोड में, मैं एक सबव्यू ( otherView
) पर मौजूदा बाधाओं को हटा देता हूं और उन्हें उन चार बाधाओं के साथ बदल देता हूं, इसे एक निश्चित चौड़ाई और ऊंचाई देता है और इसे अपने केंद्र द्वारा शुद्ध रूप से पिन करता है। उसके बाद, मेरा स्केल ट्रांसफॉर्म काम करता है:
NSMutableArray* cons = [NSMutableArray array];
for (NSLayoutConstraint* con in self.view.constraints)
if (con.firstItem == self.otherView || con.secondItem == self.otherView)
[cons addObject:con];
[self.view removeConstraints:cons];
[self.otherView removeConstraints:self.otherView.constraints];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:self.otherView.center.x]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:self.otherView.center.y]];
[self.otherView addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeWidth relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.width]];
[self.otherView addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.height]];
अपशॉट यह है कि यदि आपके पास कोई अवरोध नहीं है जो किसी दृश्य के फ्रेम को प्रभावित करता है, तो ऑटोलॉययट दृश्य के फ्रेम को स्पर्श नहीं करेगा - जो कि आपके द्वारा परिवर्तन के बाद बस यही है।
समाधान 3: एक सबव्यू का उपयोग करें
उपरोक्त दोनों समाधानों के साथ समस्या यह है कि हम अपना दृष्टिकोण रखने के लिए बाधाओं का लाभ खो देते हैं। तो यहाँ एक समाधान है जो हल करता है। एक अदृश्य दृश्य से शुरू करें जिसका काम केवल एक मेजबान के रूप में कार्य करना है, और इसे स्थिति में लाने के लिए बाधाओं का उपयोग करना है। उसके अंदर, वास्तविक दृश्य को एक सबव्यू के रूप में रखें। मेजबान दृश्य के भीतर सबव्यू की स्थिति के लिए बाधाओं का उपयोग करें, लेकिन उन बाधाओं को सीमित करें जो एक परिवर्तन लागू करने पर वापस नहीं लड़ेंगे।
यहाँ एक उदाहरण है:
सफेद दृश्य मेजबान दृश्य है; आप यह दिखावा करने वाले हैं कि यह पारदर्शी है और इसलिए अदृश्य है। लाल दृश्य इसका उप-भाग है, जिसे इसके केंद्र को होस्ट दृश्य केंद्र पर पिन करके पोस्ट किया गया है। अब हम बिना किसी समस्या के इसके केंद्र के चारों ओर लाल दृश्य को माप सकते हैं और घुमा सकते हैं, और वास्तव में चित्रण से पता चलता है कि हमने ऐसा किया है:
self.otherView.transform = CGAffineTransformScale(self.otherView.transform, 0.5, 0.5);
self.otherView.transform = CGAffineTransformRotate(self.otherView.transform, M_PI/8.0);
और इस बीच मेजबान दृश्य पर बाधाएं इसे सही जगह पर रखती हैं क्योंकि हम डिवाइस को घुमाते हैं।
समाधान 4: इसके बजाय लेयर ट्रांसफ़ॉर्म का उपयोग करें
दृश्य परिवर्तनों के बजाय, लेयर ट्रांसफ़ॉर्म का उपयोग करें, जो लेआउट को ट्रिगर नहीं करता है और इस प्रकार बाधाओं से तत्काल संघर्ष का कारण नहीं बनता है।
उदाहरण के लिए, यह सरल "थ्रोब" दृश्य एनीमेशन ऑटोलेयूट के तहत अच्छी तरह से टूट सकता है:
[UIView animateWithDuration:0.3 delay:0
options:UIViewAnimationOptionAutoreverse
animations:^{
v.transform = CGAffineTransformMakeScale(1.1, 1.1);
} completion:^(BOOL finished) {
v.transform = CGAffineTransformIdentity;
}];
भले ही अंत में दृश्य के आकार में कोई परिवर्तन नहीं हुआ था, केवल इसके transform
होने के लिए लेआउट का कारण बनता है, और बाधाएं दृश्य को चारों ओर उछाल सकती हैं। (क्या यह एक बग या क्या महसूस करता है?) लेकिन अगर हम कोर एनीमेशन के साथ एक ही काम करते हैं (एक CABasicAnimation का उपयोग करना और एनीमेशन को दृश्य की परत पर लागू करना), लेआउट नहीं होता है, और यह ठीक काम करता है:
CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"transform"];
ba.autoreverses = YES;
ba.duration = 0.3;
ba.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];
[v.layer addAnimation:ba forKey:nil];
layerView
इसकी चौड़ाई कैसे पता चलती है? क्या यह इसके दाहिने हिस्से को किसी और चीज़ से चिपका रहा है?