UIView उपवर्ग के लिए उचित अभ्यास?


158

मैं कुछ कस्टम UIView- आधारित इनपुट नियंत्रणों पर काम कर रहा हूं, और मैं दृश्य स्थापित करने के लिए उचित अभ्यास का पता लगाने की कोशिश कर रहा हूं। जब एक UIViewController के साथ काम करते हैं, तो यह loadViewऔर संबंधित viewWill, viewDidविधियों का उपयोग करने के लिए काफी सरल है , लेकिन जब एक UIView को उप-वर्ग करते हैं `awakeFromNib, तो मेरे पास निकटतम मैथोड हैं drawRect, और layoutSubviews। (मैं सेटअप और फाड़ कॉलबैक के संदर्भ में सोच रहा हूं।) मेरे मामले में, मैं अपने फ्रेम और आंतरिक विचारों को स्थापित कर layoutSubviewsरहा हूं, लेकिन मैं ऑनस्क्रीन कुछ भी नहीं देख रहा हूं।

यह सुनिश्चित करने का सबसे अच्छा तरीका क्या है कि मेरे विचार में सही ऊंचाई और चौड़ाई है जो मैं चाहता हूं कि यह हो? (मेरा प्रश्न इस बात पर ध्यान दिए बिना लागू होता है कि क्या मैं ऑटोलेयूट का उपयोग कर रहा हूँ, हालाँकि इसके दो उत्तर हो सकते हैं।) क्या उचित "सर्वोत्तम अभ्यास" है?

जवाबों:


298

Apple ने स्पष्ट रूप से परिभाषित किया कि कैसे UIViewडॉक्टर में उपवर्ग का उपयोग करें।

नीचे दी गई सूची देखें, विशेष रूप से एक नज़र डालें initWithFrame:और layoutSubviews। पूर्व का उद्देश्य आपके फ्रेम को सेटअप करना है UIViewजबकि उत्तरार्द्ध का उद्देश्य फ्रेम और इसके सबव्यू के लेआउट को सेटअप करना है।

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

अंत में, यदि आप अपने UIViewको एक निब (या स्टोरीबोर्ड) से लोड करते हैं, तो आपके पास awakeFromNibकस्टम फ्रेम और लेआउट इनिशियलाइज़ेशन करने का अवसर भी है , क्योंकि जब awakeFromNibयह कहा जाता है तो यह गारंटी दी जाती है कि पदानुक्रम में हर दृश्य अनारक्षित और आरंभिक है।

के डॉक्टर से NSNibAwaking(अब के डॉक्टर द्वारा superseded awakeFromNib):

अन्य वस्तुओं के लिए संदेश awakeFromNib के भीतर से सुरक्षित रूप से भेजे जा सकते हैं - जिस समय तक यह आश्वासन दिया जाता है कि सभी ऑब्जेक्ट अनारक्षित और आरंभिक हैं (हालांकि जरूरी नहीं कि जागृत हो, निश्चित रूप से)

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

प्रलेखन से सीधे :

ओवरराइड करने के तरीके

प्रारंभ

  • initWithFrame:यह अनुशंसा की जाती है कि आप इस विधि को लागू करें। आप इस विधि के अलावा या इसके बजाय कस्टम आरंभीकरण विधियों को भी लागू कर सकते हैं।

  • initWithCoder: यदि आप एक इंटरफ़ेस बिल्डर nib फ़ाइल से अपना दृश्य लोड करते हैं तो इस पद्धति को लागू करें और आपके दृश्य को कस्टम इनिशियलाइज़ेशन की आवश्यकता है।

  • layerClassइस पद्धति को केवल तभी लागू करें जब आप चाहते हैं कि आपका दृष्टिकोण इसके बैकिंग स्टोर के लिए एक अलग कोर एनीमेशन परत का उपयोग करे। उदाहरण के लिए, यदि आप अपने ड्राइंग को करने के लिए OpenGL ES का उपयोग कर रहे हैं, तो आप इस पद्धति को ओवरराइड करना चाहेंगे और CAEAGLLIT कक्षा को वापस करेंगे।

आरेखण और मुद्रण

  • drawRect:यदि आपका दृश्य कस्टम सामग्री खींचता है तो इस विधि को लागू करें। यदि आपका दृष्टिकोण कोई कस्टम ड्राइंग नहीं करता है, तो इस पद्धति को ओवरराइड करने से बचें।

  • drawRect:forViewPrintFormatter: इस विधि को केवल तभी लागू करें जब आप मुद्रण के दौरान अपने दृश्य की सामग्री को अलग तरह से खींचना चाहते हैं।

प्रतिबन्ध

  • requiresConstraintBasedLayout यदि आपके दृश्य वर्ग को ठीक से काम करने के लिए बाधाओं की आवश्यकता है तो इस वर्ग पद्धति को लागू करें।

  • updateConstraints यदि आपके दृश्य में आपके साक्षात्कारों के बीच कस्टम अवरोध बनाने की आवश्यकता है, तो इस पद्धति को लागू करें।

  • alignmentRectForFrame:, frameForAlignmentRect:इन तरीकों को लागू करने के लिए ओवरराइड करें कि आपके विचार अन्य विचारों से कैसे जुड़े हैं।

ख़ाका

  • sizeThatFits:इस विधि को लागू करें यदि आप चाहते हैं कि आपके दृश्य का आकार अलग-अलग डिफ़ॉल्ट आकार का हो, तो यह सामान्य रूप से संचालन के दौरान होगा। उदाहरण के लिए, आप अपने दृष्टिकोण को उस बिंदु पर सिकुड़ने से रोकने के लिए इस पद्धति का उपयोग कर सकते हैं, जहां साक्षात्कार सही ढंग से प्रदर्शित नहीं किए जा सकते।

  • layoutSubviews इस विधि को लागू करें यदि आपको अपने साक्षात्कारों के लेआउट पर अधिक सटीक नियंत्रण की आवश्यकता है, तो या तो बाधा या ऑटोरेस्पिरिंग व्यवहार प्रदान करते हैं।

  • didAddSubview:, willRemoveSubview:इन विधियों को लागू करने के रूप में अतिरिक्त और साक्षात्कार के निष्कासन को ट्रैक करने की जरूरत है।

  • willMoveToSuperview:, didMoveToSuperviewअपने दृश्य पदानुक्रम में वर्तमान दृश्य की गति को ट्रैक करने के लिए आवश्यकतानुसार इन विधियों को लागू करें।

  • willMoveToWindow:, didMoveToWindowइन तरीकों को लागू करने के लिए एक अलग विंडो में अपने दृश्य के आंदोलन को ट्रैक करने की आवश्यकता है।

घटना से निपटना:

  • touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:, touchesCancelled:withEvent:यदि आप सीधे संपर्क के ईवेंट प्रबंधित करने की जरूरत है इन तरीकों को लागू करें। (जेस्चर-आधारित इनपुट के लिए, जेस्चर पहचानकर्ताओं का उपयोग करें।)

  • gestureRecognizerShouldBegin: इस विधि को लागू करें यदि आपका दृश्य सीधे घटनाओं को छूता है और अतिरिक्त कार्रवाई को ट्रिगर करने से संलग्न इशारों को पहचानने से रोकना चाहता है।


के बारे में क्या - (शून्य) setFrame: (CGRect) फ्रेम?
22

अच्छी तरह से आप निश्चित रूप से इसे ओवरराइड कर सकते हैं, लेकिन किस उद्देश्य से?
गैब्रिएल पेट्रोनेला

लेआउट आकार / स्थान बदलने के लिए कभी भी फ्रेम आकार या स्थान परिवर्तन
pfrank

1
किस बारे में layoutSubviews?
गैब्रियल पेट्रोनेला

से stackoverflow.com/questions/4000664/... , "इस के साथ दिक्कत यह है कि subviews केवल उनके आकार को बदल नहीं सकते, लेकिन वे कहते हैं कि आकार परिवर्तन चेतन कर सकते हैं। जब UIView एनीमेशन चलता है, यह layoutSubviews हर बार फोन नहीं है।" हालांकि इसे व्यक्तिगत रूप से नहीं परखा गया
pfrank

38

यह अभी भी Google में उच्च स्तर पर आता है। नीचे स्विफ्ट के लिए एक अद्यतन उदाहरण है।

didLoadसमारोह आप अपने सभी कस्टम प्रवर्तन कोड डाल सकते हैं। जैसा कि दूसरों ने उल्लेख किया है, didLoadतब बुलाया जाएगा जब कोई दृश्य प्रोग्रामेटिक रूप से बनाया जाता है init(frame:)या जब XIB डिजायरलाइज़र आपके विचार से XIB टेम्पलेट को मर्ज करता हैinit(coder:)

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

import UIKit

class MyView: UIView {
  //-----------------------------------------------------------------------------------------------------
  //Constructors, Initializers, and UIView lifecycle
  //-----------------------------------------------------------------------------------------------------
  override init(frame: CGRect) {
      super.init(frame: frame)
      didLoad()
  }

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    didLoad()
  }

  convenience init() {
    self.init(frame: CGRectZero)
  }

  func didLoad() {
    //Place your initialization code here

    //I actually create & place constraints in here, instead of in
    //updateConstraints
  }

  override func layoutSubviews() {
     super.layoutSubviews()

     //Custom manually positioning layout goes here (auto-layout pass has already run first pass)
  }

  override func updateConstraints() {
    super.updateConstraints()

    //Disable this if you are adding constraints manually
    //or you're going to have a 'bad time'
    //self.translatesAutoresizingMaskIntoConstraints = false

    //Add custom constraint code here
  }
}

क्या आप बता सकते हैं कि कब / क्यों आप अपने init प्रक्रिया और लेआउट से बुलाए गए तरीके और लेआउट के बीच लेआउट बाधा कोड को विभाजित करेंगे और अपडेट करें? ऐसा लगता है कि वे लेआउट कोड रखने के लिए सभी तीन संभावित उम्मीदवार स्थान हैं। तो आप कैसे जानते हैं कि कब / क्या / क्यों तीनों के बीच लेआउट कोड को विभाजित करना है?
क्ले एलिस

3
मैं कभी भी अपडेट का उपयोग नहीं करता हूं। updateConstraints अच्छा हो सकता है क्योंकि आप जानते हैं कि आपका दृष्टिकोण पदानुक्रम पूरी तरह से init पर सेट किया गया था, इसलिए आप पदानुक्रम में नहीं दो विचारों के बीच एक बाधा जोड़कर एक अपवाद नहीं उठा सकते हैं :) लेआउटसुब्यू में कभी भी संशोधन नहीं करना चाहिए; यह आसानी से एक अनंत पुनरावृत्ति का कारण बन सकता है क्योंकि लेआउट पास के दौरान बाधाओं को 'अमान्य' कर दिया जाता है तो लेआउटसुब्यू कहा जाता है। मैनुअल लेआउट सेटअप (जैसा कि सीधे फ्रेम सेट करने में, जो आपको शायद ही कभी करना चाहिए जब तक कि प्रदर्शन के कारणों के लिए) लेआउटसुब्यू में न चला जाए। व्यक्तिगत रूप से, मैं init में कमी निर्माण जगह
एसईओ

कस्टम रेंडरिंग कोड के लिए, क्या हमें drawविधि को ओवरराइड करना चाहिए ?
पेट्रस थेरॉन

14

Apple प्रलेखन में एक अच्छा सारांश है , और यह iTunes पर उपलब्ध मुफ्त स्टैनफोर्ड पाठ्यक्रम में अच्छी तरह से कवर किया गया है। मैं अपना TL प्रस्तुत करता हूं; DR संस्करण यहां:

यदि आपकी कक्षा में अधिकतर साक्षात्कार होते हैं, तो उन्हें आवंटित करने का सही initतरीका विधियों में है। विचारों के लिए, दो अलग-अलग initविधियाँ हैं, जिन्हें कॉल किया जा सकता है, यह इस बात पर निर्भर करता है कि आपका दृश्य कोड से या किसी नीब / स्टोरीबोर्ड से त्वरित किया जा रहा है। मैं क्या मेरे अपने बारे में है setupविधि, और फिर इसे दोनों से फोन initWithFrame:और initWithCoder:तरीकों।

यदि आप कस्टम ड्राइंग कर रहे हैं, तो आप वास्तव drawRect:में आपके विचार में ओवरराइड करना चाहते हैं। यदि आपका कस्टम दृश्य अधिकतर साक्षात्कारों के लिए एक कंटेनर है, हालांकि, आपको शायद ऐसा करने की आवश्यकता नहीं होगी।

केवल ओवरराइड करें layoutSubViewsयदि आप चित्र या लैंडस्केप ओरिएंटेशन में शामिल होने के आधार पर कुछ जोड़ने या हटाने के लिए कुछ करना चाहते हैं। अन्यथा, आपको इसे अकेले छोड़ने में सक्षम होना चाहिए।


मैं आपके उत्तर का उपयोग दृश्य को बदलने के लिए करता हूं (जो कि जाग रहा है) यह सब-व्यू के फ्रेम में है layoutSubViews, इसने काम किया।
विमान

1

layoutSubviews बच्चे के विचारों पर फ्रेम सेट करने के लिए है, न कि दृश्य पर।

के लिए UIView, निर्दिष्ट कंस्ट्रक्टर आम तौर पर है initWithFrame:(CGRect)frameऔर आपको फ्रेम को वहां (या initWithCoder:) में सेट करना चाहिए , संभवतः फ्रेम वैल्यू में पास की अनदेखी करना। आप एक अलग कंस्ट्रक्टर भी प्रदान कर सकते हैं और वहां फ्रेम सेट कर सकते हैं।


क्या आप इसे और अधिक विस्तार से ले सकते हैं? मुझे आपके मत का पता नहीं था। किसी दृश्य का उप-दृश्य सेट करने के लिए कैसे? दृश्य हैawakeFromNib
विमान '

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