स्विफ्ट में XIB फ़ाइल के साथ एक कस्टम UIView वर्ग को इनिशियलाइज़ / इंट्रस्ट कैसे करें


139

मेरे पास एक वर्ग है, MyClassजो एक उपवर्ग है UIView, जिसे मैं एक XIBफ़ाइल के साथ प्रारंभ करना चाहता हूं । मुझे यकीन नहीं है कि xib फाइल नामक इस क्लास को कैसे इनिशियलाइज़ किया जाएView.xib

class MyClass: UIView {

    // what should I do here? 
    //init(coder aDecoder: NSCoder) {} ?? 
}

5
iOS9 स्विफ्ट के लिए पूर्ण स्रोत कोड नमूना 2.0 उल्लेख github.com/karthikprabhuA/CustomXIBSwift और संबंधित धागा stackoverflow.com/questions/24857986/...
karthikPrabhu Alagu

जवाबों:


266

मैंने इस कोड का परीक्षण किया और यह बहुत अच्छा काम करता है:

class MyClass: UIView {        
    class func instanceFromNib() -> UIView {
        return UINib(nibName: "nib file name", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as UIView
    }    
}

आरंभ को देखें और नीचे की तरह इसका उपयोग करें:

var view = MyClass.instanceFromNib()
self.view.addSubview(view)

या

var view = MyClass.instanceFromNib
self.view.addSubview(view())

अद्यतन स्विफ्ट> = 3.x और स्विफ्ट> = 4.x

class func instanceFromNib() -> UIView {
    return UINib(nibName: "nib file name", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}

1
यह होना चाहिए var view = MyClass.instanceFromNib()और self.view.addSubview(view)के रूप में करने का विरोध किया var view = MyClass.instanceFromNibऔर self.view.addSubview(view())। उत्तर को बेहतर बनाने के लिए बस एक छोटा सा सुझाव :)
लोगान

1
मेरे मामले में बाद में आरंभिक रूप से देखें! अगर यह
स्वयं है ।view.addSubview

2
@Ezimet उस दृश्य के अंदर IBActions के बारे में क्या कहता है। उन्हें कहां संभालना है जैसे मेरे विचार में बटन है (xib) कि बटन के IBAction क्लिक घटना को कैसे संभालना है?
कादिर हुसैन

6
क्या यह केवल यूआईवीयूवाई के बजाय "मायक्लास" लौटना चाहिए?
केसोंग एक्सई

2
IBoutlets इस दृष्टिकोण में काम नहीं कर रहे हैं ... मुझे मिल रहा है: "यह वर्ग कुंजी के लिए महत्वपूर्ण मूल्य कोडिंग-अनुरूप नहीं है"
Radek Wilczak

82

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

यदि आप अपने Xib आउटलेट्स के लिए पूर्ण समर्थन चाहते हैं, तो अलग-अलग बंडल (फ्रेमवर्क में उपयोग!) और कहानी का अच्छा पूर्वावलोकन प्राप्त करें:

// NibLoadingView.swift
import UIKit

/* Usage: 
- Subclass your UIView from NibLoadView to automatically load an Xib with the same name as your class
- Set the class name to File's Owner in the Xib file
*/

@IBDesignable
class NibLoadingView: UIView {

    @IBOutlet weak var view: UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        nibSetup()
    }

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

    private func nibSetup() {
        backgroundColor = .clearColor()

        view = loadViewFromNib()
        view.frame = bounds
        view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        view.translatesAutoresizingMaskIntoConstraints = true

        addSubview(view)
    }

    private func loadViewFromNib() -> UIView {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: String(self.dynamicType), bundle: bundle)
        let nibView = nib.instantiateWithOwner(self, options: nil).first as! UIView

        return nibView
    }

}

हमेशा की तरह अपने xib का उपयोग करें, अर्थात आउटलेट्स को फ़ाइल स्वामी से कनेक्ट करें और फ़ाइल स्वामी वर्ग को अपनी कक्षा में सेट करें।

उपयोग: NibLoadingView और समूह वर्ग के नाम से सिर्फ उपवर्ग अपने स्वयं के वर्ग देखें फ़ाइल के मालिक XIB फ़ाइल में

अब अतिरिक्त कोड की आवश्यकता नहीं है।

क्रेडिट जहां देय है: जीएच पर डेनहेडलेस से मामूली बदलाव के साथ यह भूल गया। माय गिस्ट: https://gist.github.com/winkelsdorf/16c481f274134718946328b6e2c9a4d8


8
यह समाधान ब्रेक कनेक्शन आउटलेट (क्योंकि यह एक subview के रूप लोड दृश्य कहते हैं) और बुला nibSetupसे init?(coder:)अनंत प्रत्यावर्तन का कारण होगा यदि embedding NibLoadingViewएक XIB में।
redent84

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

1
जैसा कि उल्लेख किया गया है "आउटलेट्स को फ़ाइल स्वामी से कनेक्ट करें और फ़ाइल स्वामी वर्ग को अपनी कक्षा में सेट करें।" आउटलेट्स को फ़ाइल स्वामी से कनेक्ट करें
यूसुफ एक्स

1
मैं xib से दृश्य लोड करने के लिए इस पद्धति का उपयोग करने के बारे में हमेशा असहज हूं। हम मूल रूप से एक दृश्य जोड़ रहे हैं जो कक्षा ए का एक उपवर्ग है, एक दृश्य में जो कक्षा ए का उपवर्ग भी है। क्या इस पुनरावृत्ति को रोकने के लिए कोई रास्ता नहीं है?
प्रजीत श्रेष्ठ

1
@PrajeetShrestha nibSetup () बैकग्राउंड रंग को ओवरराइड करने से .clearColor()- स्टोरीबोर्ड से लोड करने के बाद संभव है। लेकिन यह काम करना चाहिए अगर आप इसे तुरंत करने के बाद कोड द्वारा करते हैं। वैसे भी, जैसा कि कहा जाता है कि एक और अधिक सुंदर दृष्टिकोण प्रोटोकॉल आधारित है। तो यकीन है, यहाँ आप के लिए एक कड़ी है: github.com/AliSoftware/Reusable । मैं UITableViewCells के बारे में अब एक समान दृष्टिकोण का उपयोग कर रहा हूं (जो मैंने लागू होने से पहले मुझे पता चला था कि वास्तव में उपयोगी परियोजना है)। hth!
फ्रेडरिक विंकल्सडोर्फ

77

स्विफ्ट 2.0 के रूप में, आप एक प्रोटोकॉल एक्सटेंशन जोड़ सकते हैं। मेरी राय में, यह एक बेहतर दृष्टिकोण है क्योंकि रिटर्न प्रकार इसके Selfबजाय है UIView, इसलिए कॉलर को व्यू क्लास में जाने की आवश्यकता नहीं है।

import UIKit

protocol UIViewLoading {}
extension UIView : UIViewLoading {}

extension UIViewLoading where Self : UIView {

  // note that this method returns an instance of type `Self`, rather than UIView
  static func loadFromNib() -> Self {
    let nibName = "\(self)".characters.split{$0 == "."}.map(String.init).last!
    let nib = UINib(nibName: nibName, bundle: nil)
    return nib.instantiateWithOwner(self, options: nil).first as! Self
  }

}

4
यह चयनित उत्तर की तुलना में बेहतर समाधान है क्योंकि इसमें कास्टिंग की कोई आवश्यकता नहीं है और यह भविष्य में आपके द्वारा बनाए गए किसी भी अन्य यूविवि उपवर्गों में भी पुन: प्रयोज्य होगा।
user3344977

3
मैंने स्विफ्ट 2.1 और एक्सकोड 7.2.1 के साथ यह कोशिश की। इसने कुछ समय काम किया और एक म्यूटेक्स लॉक के साथ दूसरों पर अप्रत्याशित रूप से लटका होगा। कोड में सीधे इस्तेमाल की जाने वाली अंतिम दो लाइनें हर बार अंतिम पंक्ति के साथ काम करती हैंvar myView = nib.instantiate... as! myViewType
पॉल लिंसे

@ jr-root-cs आपके संपादन में टाइपो / त्रुटियां हैं, मुझे इसे वापस लेना था। और वैसे भी कृपया मौजूदा उत्तरों में कोड न जोड़ें। इसके बजाय, एक टिप्पणी करें; या अपने स्वयं के उत्तर में अपना संस्करण जोड़ें । धन्यवाद।
एरिक आया

मैंने कोड पोस्ट किया था जिसे मैंने अपने प्रोजेक्ट में Swift 3(XCode 8.0 बीटा 6) का उपयोग करके समस्याओं के बिना खोला और परीक्षण किया था । टाइपो में था Swift 2। जब यह उत्तर अच्छा हो, तो इसका एक और उत्तर क्यों होना चाहिए और उपयोगकर्ताओं को यह पसंद आएगा कि जब वे XC8
jr.root.cs का

1
@ jr.root.cs हाँ यह उत्तर अच्छा है, इसीलिए किसी को भी इसमें बदलाव नहीं करना चाहिए। यह सैम का जवाब है, आपका नहीं। यदि आप इस पर टिप्पणी करना चाहते हैं, तो एक टिप्पणी छोड़ दें; यदि आप एक नया / अद्यतन संस्करण पोस्ट करना चाहते हैं, तो इसे अपनी पोस्ट में करें । संपादन टाइपो / इंडेंटेशन / टैग को ठीक करने के लिए हैं जो आपके संस्करणों को अन्य लोगों के पोस्ट में जोड़ने के लिए नहीं हैं। धन्यवाद।
एरिक आया

37

और यह स्विफ्ट 3.0 पर फ्रेडरिक का जवाब है

/*
 Usage:
 - make your CustomeView class and inherit from this one
 - in your Xib file make the file owner is your CustomeView class
 - *Important* the root view in your Xib file must be of type UIView
 - link all outlets to the file owner
 */
@IBDesignable
class NibLoadingView: UIView {

    @IBOutlet weak var view: UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        nibSetup()
    }

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

    private func nibSetup() {
        backgroundColor = .clear

        view = loadViewFromNib()
        view.frame = bounds
        view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.translatesAutoresizingMaskIntoConstraints = true

        addSubview(view)
    }

    private func loadViewFromNib() -> UIView {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
        let nibView = nib.instantiate(withOwner: self, options: nil).first as! UIView

        return nibView
    }
}

31

जिब से दृश्य लोड करने का सार्वभौमिक तरीका:

उदाहरण:

let myView = Bundle.loadView(fromNib: "MyView", withType: MyView.self)

कार्यान्वयन:

extension Bundle {

    static func loadView<T>(fromNib name: String, withType type: T.Type) -> T {
        if let view = Bundle.main.loadNibNamed(name, owner: nil, options: nil)?.first as? T {
            return view
        }

        fatalError("Could not load view with type " + String(describing: type))
    }
}

सबसे अच्छा जवाब मुझे आउटपुट व्यू के रूप में
यूविवि

26

स्विफ्ट 3 उत्तर: मेरे मामले में, मैं अपनी कस्टम क्लास में एक आउटलेट रखना चाहता था जिसे मैं संशोधित कर सकता था:

class MyClassView: UIView {
    @IBOutlet weak var myLabel: UILabel!

    class func createMyClassView() -> MyClass {
        let myClassNib = UINib(nibName: "MyClass", bundle: nil)
        return myClassNib.instantiate(withOwner: nil, options: nil)[0] as! MyClassView
    }
}

जब .xib में हो, तो सुनिश्चित करें कि कस्टम क्लास फ़ील्ड MyClassView है। फ़ाइल के स्वामी के साथ परेशान मत करो।

सुनिश्चित करें कि कस्टम क्लास MyClassView है

यह भी सुनिश्चित करें कि आप MyClassView में लेबल से आउटलेट कनेक्ट करें: MyLabel के लिए आउटलेट

इसे तुरंत करने के लिए:

let myClassView = MyClassView.createMyClassView()
myClassView.myLabel.text = "Hello World!"

मैं वापस "MyClas" nib को लोड करता हूं, लेकिन दृश्य आउटलेट सेट नहीं किया गया था। "" यदि स्वामी सेट नहीं है
jcharch

22

स्विफ्ट 4

यहाँ मेरे मामले में मुझे उस कस्टम दृश्य में डेटा पास करना है, इसलिए मैं दृश्य को तुरंत करने के लिए स्थैतिक फ़ंक्शन बनाता हूं।

  1. UIView एक्सटेंशन बनाएं

    extension UIView {
        class func initFromNib<T: UIView>() -> T {
            return Bundle.main.loadNibNamed(String(describing: self), owner: nil, options: nil)?[0] as! T
        }
    }
  2. MyCustomView बनाएं

    class MyCustomView: UIView {
    
        @IBOutlet weak var messageLabel: UILabel!
    
        static func instantiate(message: String) -> MyCustomView {
            let view: MyCustomView = initFromNib()
            view.messageLabel.text = message
            return view
        }
    }
  3. कस्टम क्लास को .xib फ़ाइल में MyCustomView में सेट करें। यदि आवश्यक हो तो आउटलेट कनेक्ट करें। यहां छवि विवरण दर्ज करें

  4. तात्कालिक दृश्य

    let view = MyCustomView.instantiate(message: "Hello World.")

यदि कस्टम दृश्य में बटन हैं, तो हम विभिन्न दृश्य नियंत्रकों में उनके कार्यों को कैसे संभाल सकते हैं?
जयंत रावत

आप प्रोटोकॉल-प्रतिनिधि का उपयोग कर सकते हैं। यहां एक नज़र डालें stackoverflow.com/questions/29602612/…
mnemonic23

यह xib में एक छवि लोड करने में विफल रहा, निम्न त्रुटि हो रही है। पहचानकर्ता "परीक्षण" परीक्षण के साथ बंडल में एक नीब से संदर्भित " IBBrokenImage " छवि लोड नहीं कर सका
रवि राजा जांगिड़

-4
override func draw(_ rect: CGRect) 
{
    AlertView.layer.cornerRadius = 4
    AlertView.clipsToBounds = true

    btnOk.layer.cornerRadius = 4
    btnOk.clipsToBounds = true   
}

class func instanceFromNib() -> LAAlertView {
    return UINib(nibName: "LAAlertView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! LAAlertView
}

@IBAction func okBtnDidClicked(_ sender: Any) {

    removeAlertViewFromWindow()

    UIView.animate(withDuration: 0.4, delay: 0.0, options: .allowAnimatedContent, animations: {() -> Void in
        self.AlertView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)

    }, completion: {(finished: Bool) -> Void in
        self.AlertView.transform = CGAffineTransform.identity
        self.AlertView.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)
        self.AlertView.isHidden = true
        self.AlertView.alpha = 0.0

        self.alpha = 0.5
    })
}


func removeAlertViewFromWindow()
{
    for subview  in (appDel.window?.subviews)! {
        if subview.tag == 500500{
            subview.removeFromSuperview()
        }
    }
}


public func openAlertView(title:String , string : String ){

    lblTital.text  = title
    txtView.text  = string

    self.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
    appDel.window!.addSubview(self)


    AlertView.alpha = 1.0
    AlertView.isHidden = false

    UIView.animate(withDuration: 0.2, animations: {() -> Void in
        self.alpha = 1.0
    })
    AlertView.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)

    UIView.animate(withDuration: 0.3, delay: 0.2, options: .allowAnimatedContent, animations: {() -> Void in
        self.AlertView.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)

    }, completion: {(finished: Bool) -> Void in
        UIView.animate(withDuration: 0.2, animations: {() -> Void in
            self.AlertView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)

        })
    })


}

खराब स्वरूपित कोड, कोई स्पष्टीकरण नहीं है, इसलिए डाउनवोट।
जे डो

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