वहाँ एक UIView आकार घटना है?


103

मेरे पास एक दृश्य है जिसमें इसमें चित्र की पंक्तियाँ और स्तंभ हैं।

यदि इस दृश्य का आकार बदल दिया जाता है, तो मुझे चित्रपट पदों को पुन: व्यवस्थित करने की आवश्यकता है।

यह दृश्य एक अन्य दृश्य का एक सबव्यू है जो रिसाइज़ हो जाता है।

क्या यह पता लगाने का कोई तरीका है कि इस दृश्य का आकार परिवर्तन कब किया जा रहा है?


दृश्य कब बदला जाता है? जब डिवाइस घूमता है, या जब उपयोगकर्ता मल्टी-टच का उपयोग करके इसे घुमाता है?
इवान मुलवस्की

जब उपयोगकर्ता किसी अन्य दृश्य (मास्टर दृश्य) पर एक बटन पर टैप करता है, तो यह दृश्य आकार बदल जाता है।
लाइव-लव

जवाबों:


98

जैसा कि Uli ने नीचे टिप्पणी की है, ऐसा करने का उचित तरीका layoutSubviewsछवि को ओवरराइड और लेआउट करना है।

यदि, किसी कारण से, आप उप-प्रकार और ओवरराइड नहीं कर सकते हैं layoutSubviews, तो अवलोकन boundsकरना चाहिए, भले ही गंदे होने पर भी काम करना चाहिए। इससे भी बदतर, अवलोकन के साथ एक जोखिम है - Apple UIKit कक्षाओं पर KVO के कामों की गारंटी नहीं देता है। Apple इंजीनियर के साथ यहां चर्चा पढ़ें: संबंधित वस्तु कब जारी होती है?

मूल उत्तर:

आप कुंजी-मान का उपयोग कर सकते हैं:

[yourView addObserver:self forKeyPath:@"bounds" options:0 context:nil];

और आवेदन:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (object == yourView && [keyPath isEqualToString:@"bounds"]) {
        // do your stuff, or better schedule to run later using performSelector:withObject:afterDuration:
    }
}

2
वास्तव में, सब-आउटिंग देना बिल्कुल वैसा ही है, जैसा कि लेआउटसुब्यू के लिए है, इसलिए आकार में परिवर्तन देखते हुए, जबकि कार्यात्मक, IMO खराब डिज़ाइन है।
उलिवात

@ साक्षी अच्छी तरह से वे इस सामान को बदलते रहते हैं। वैसे भी, अब आपको viewWillTransitionआदि आदि का उपयोग करना चाहिए
दान रोसेनस्टार्क

UIViewControllers के लिए viewWillTransition, UIView नहीं।
आर्मंड

क्या layoutSubviewsअभी भी एक अनुशंसित पद्धति का उपयोग किया जा रहा है , यदि दृश्य के वर्तमान आकार के आधार पर, अलग-अलग साक्षात्कारों को जोड़ने / हटाने की आवश्यकता है और विभिन्न बाधाओं को जोड़ने / हटाने की आवश्यकता है?
क्रिस प्रिंस

1
खैर, मुझे लगता है कि मैंने सिर्फ अपने मामले के लिए इसका जवाब दिया। जब मैं सेटअप (आकार पर निर्भर) करता हूं, तो मुझे सीमा के ओवरराइड की आवश्यकता होती है, यह काम करता है। जब मैं इसे लेआउट में करता हूँ तो यह नहीं होता है।
क्रिस प्रिंस

93

एक UIViewउपवर्ग में, संपत्ति पर्यवेक्षकों का उपयोग किया जा सकता है:

override var bounds: CGRect {
    didSet {
        // ...
    }
}

उपवर्ग के बिना, स्मार्ट की-पाथ के साथ की -वैल्यू अवलोकन करेंगे:

var boundsObservation: NSKeyValueObservation?

func beginObservingBounds() {
    boundsObservation = observe(\.bounds) { capturedSelf, _ in
        // ...
    }
}

2
@ क्या आप ऐसा क्यों सोचते हैं?
रुडोल्फ एडमकोविक्स

लोड फ्रेम में परिवर्तन होता है, लेकिन ऐसा लगता है कि सीमा नहीं है (मुझे पता है कि यह अजीब है और शायद मैं कुछ गलत कर रहा हूं)
अली

3
@ अलि: जैसा कि यहां कई बार उल्लेख किया गया है: frameएक व्युत्पन्न और रनटाइम गणना की गई संपत्ति है। इसे ओवरराइड न करें, जब तक कि आपके पास ऐसा करने के लिए बहुत स्मार्ट और जानने का कारण न हो। अन्यथा: उपयोग boundsया (और भी बेहतर) layoutSubviews
Auco

3
सर्कल बनाने के लिए इस तरह का एक शानदार तरीका। धन्यवाद! override var bounds: CGRect { didSet { layer.cornerRadius = bounds.size.width / 2 }}
सिंपलजी जूल 12'16

4
पता लगाना boundsया frameबदलना काम करने की गारंटी नहीं है, इस पर निर्भर करता है कि आपने अपना दृष्टिकोण पदानुक्रम में कहां रखा है। मैं layoutSubviewsइसके बजाय ओवरराइड करता हूं । इसे और इस जवाब को देखें ।
हुआथैम

31

UIView का उपवर्ग बनाएं, और लेआउट को देखें


11
इसके साथ परेशानी यह है कि साक्षात्कार न केवल उनके आकार को बदल सकते हैं, बल्कि वे उस आकार को बदल सकते हैं। जब UIView एनीमेशन चलाता है, तो वह हर बार लेआउटसुब्यू नहीं कहता है।
डेविड जेस्के

1
@DavidJeske UIViewAnimationOptions में UIViewAnimationOptionLayoutSubviews नामक विकल्प है। मुझे लगता है कि यह मदद कर सकता है। :)
Neal.Marlin

8

स्विफ्ट 4 कीपथ केवीओ - यह है कि मैं ऑटोरोटेट का पता लगाता हूं और आईपैड साइड पैनल पर जा रहा हूं। किसी भी दृश्य पर काम करना चाहिए। UIView की परत का निरीक्षण करना था।

private var observer: NSKeyValueObservation?

override func viewDidLoad() {
    super.viewDidLoad()
    observer = view.layer.observe(\.bounds) { object, _ in
        print(object.bounds)
    }
    // ...
}
override func viewWillDisappear(_ animated: Bool) {
    observer?.invalidate()
    //...
}

इस समाधान ने मेरे लिए काम किया। मैं स्विफ्ट के लिए नया हूं और आपके द्वारा उपयोग किए जाने वाले \ _। सीमा सिंटैक्स पर मैं अनिश्चित हूं। इसका सबसे सही मतलब क्या है?
WBuck


.layerचाल चली! क्या आप जानते हैं कि view.observeकाम करना क्यों काम नहीं करता है?
d4Rk

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

यह मेरे लिए एक महान जवाब है। मेरा मामला यह है कि मैं अपने विचारों को रखने के लिए ऑटोलेयूट का उपयोग कर रहा हूं। लेकिन UICollectionViewFlowLayout आपको एक स्पष्ट आइटम देने के लिए मजबूर करता है। लेकिन जब आपका संग्रह दृश्य आकार बदलता है (जैसे कि मेरे मामले में जब मैं AutoLayout के साथ टूलबार दिखा रहा हूं) - आइटमसाइज समान रहता है और फेंकता है = [पर्यवेक्षक सबसे साफ दृष्टिकोण है जो मुझे अब तक मिला है। और सबसे अच्छा एक !!
यिट्ज़चेक

7

आप UIView का उपवर्ग बना सकते हैं और ओवरराइड कर सकते हैं

setFrame: (CGRect) फ्रेम

तरीका। यह वह विधि है जिसे दृश्य के फ्रेम (अर्थात आकार) में परिवर्तित किया जाता है। कुछ इस तरह से करें:

- (void) setFrame:(CGRect)frame
{
  // Call the parent class to move the view
  [super setFrame:frame];

  // Do your custom code here.
}

समझदार और कार्यात्मक। अच्छा निर्णय।
एल जोर्को

1
FYI करें यह UIImageView उपवर्ग के लिए काम नहीं करता है। यहाँ अधिक जानकारी: stackoverflow.com/questions/19216684/…
विलियम एंट्रीकेन

इसके अलावा, setFrame:मेरे पर आमंत्रित नहीं किया गया UITextViewautorotation की वजह से आकार बदलना जबकि दौरान उपवर्ग layoutSubviews:था। नोट: मैं ऑटो लेआउट और iOS 7.0 का उपयोग कर रहा हूं।
ma11hew28

3
कभी ओवरराइड न करें setFrame:frameएक व्युत्पन्न संपत्ति है। मेरा जवाब देखिए
अदलई होलर

7

बहुत पुराना है, लेकिन अभी भी एक अच्छा सवाल है। Apple के सैंपल कोड में, और उनके कुछ निजी UIView उपवर्गों में, वे ओवरराइड सेट करते हैं जैसे मोटे तौर पर:

-(void)setBounds:(CGRect)newBounds {
    BOOL const isResize = !CGSizeEqualToSize(newBounds.size, self.bounds.size);
    if (isResize) [self prepareToResizeTo:newBounds.size]; // probably saves 
    [super setBounds:newBounds];
    if (isResize) [self recoverFromResizing];
}

ओवरराइडिंग setFrame:एक अच्छा विचार नहीं है। frameसे लिया गया है center, boundsऔर transform, इसलिए आईओएस जरूरी कॉल नहीं करेगा setFrame:


2
यह सच है (सिद्धांत में)। हालाँकि, setBounds:फ़्रेम प्रॉपर्टी सेट करते समय (कम से कम iOS 7.1 पर) सेट नहीं किया जाता है। यह अतिरिक्त संदेश से बचने के लिए जोड़ा गया अनुकूलन Apple हो सकता है।
nschum

1
... और एप्पल के खराब डिजाइन अपने स्वयं के एक्सेसरों को कॉल करने के लिए नहीं।
12x पर ऑक्सडरिक

1
वास्तव में, दोनों frame और boundsदृश्य की अंतर्निहित से प्राप्त कर रहे CALayer; वे केवल परत के गेट के माध्यम से कॉल करते हैं। और setFrame:परत के फ्रेम को setBounds:सेट करता है , जबकि परत की सीमा निर्धारित करता है। तो आप बस एक या दूसरे को ओवरराइड नहीं कर सकते। इसके अलावा, layoutSubviewsअत्यधिक कहा जाता है (न कि केवल ज्यामिति परिवर्तनों पर), इसलिए यह हमेशा एक अच्छा विकल्प भी नहीं हो सकता है। अभी भी देख रहे हैं ...
big_m

-3

यदि आप एक UIViewController उदाहरण में हैं, तो ओवरराइडिंग viewDidLayoutSubviewsचाल करता है।

override func viewDidLayoutSubviews() {
    // update subviews
}

UIView आकार की जरूरत है, न कि UIViewController।
गैस्टोन एंटोनियो मोंटेस

@ GastónAntonioMontes इसके लिए धन्यवाद! आपने UIViewउदाहरणों और UIViewControllerउदाहरणों के बीच संबंध देखा होगा । इसलिए यदि आपके पास UIViewकोई वीसी अटैच नहीं है, तो अन्य उत्तर बहुत अच्छे हैं, लेकिन अगर आप वीसी के साथ संलग्न होना चाहते हैं, तो यह आपका आदमी है। क्षमा करें यह आपके मामले पर लागू नहीं है।
बजे डैन रोसेनस्टार्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.