সুইফটিতে নিব থেকে একটি ইউআইভিউ লোড করুন


148

এখানে আমার উদ্দেশ্য-সি কোড যা আমি আমার কাস্টমাইজড জন্য একটি নিব লোড করতে ব্যবহার করছি UIView:

-(id)init{

    NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"myXib" owner:self options:nil];
    return [subviewArray objectAtIndex:0];

}

সুইফটে সমমানের কোডটি কী?

উত্তর:


172

মূল সমাধান

  1. আমি সিমভিউ নামে একটি দ্বাদশ এবং ক্লাস তৈরি করেছি (সুবিধার্থে এবং পাঠযোগ্যতার জন্য একই নাম ব্যবহার করেছি)। আমি উভয়ই একটি ইউআইভিউয়ের উপর ভিত্তি করে তৈরি করেছি।
  2. দ্বাদশটিতে আমি "ফাইলের মালিক" ক্লাসটি সাম্যর ভিউতে (পরিচয় পরিদর্শকটিতে) পরিবর্তন করেছি।
  3. XIB ফাইলের শীর্ষ স্তরের দৃশ্যের সাথে এটি যুক্ত করে, সুবিধার জন্য এটির "ভিউ" নামকরণ করা হয়েছে) আমি সাম্ভিউ.উইউউইটে একটি ইউআইভিউ আউটলেট তৈরি করেছি। আমি তখন প্রয়োজন অনুসারে এক্সআইবি ফাইলের অন্যান্য নিয়ন্ত্রণগুলিতে অন্যান্য আউটলেটগুলি যুক্ত করেছি।
  4. সোমারভিউ.সুইফ্টে, আমি "আরআইডি উইথ কোড" ইনিশিয়ালাইজারের ভিতরে এক্সআইবি লোড করেছি। "স্ব" কে কিছু বরাদ্দ করার দরকার নেই। এক্সআইবি লোড হওয়ার সাথে সাথে শীর্ষ স্তরের দৃশ্য সহ সমস্ত আউটলেট সংযুক্ত হয়ে যায়। একমাত্র জিনিস অনুপস্থিত, ভিউ হায়ারার্কিতে শীর্ষের ভিউ যুক্ত করা:

class SomeView: UIView {
   required init(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
      NSBundle.mainBundle().loadNibNamed("SomeView", owner: self, options: nil)
      self.addSubview(self.view);    // adding the top level view to the view hierarchy
   }
   ...
}

নোট করুন যে এইভাবে আমি একটি ক্লাস পাই যা নিব থেকে নিজেকে লোড করে। আমি যখনই প্রকল্পে ইউআইভিউউ (ইন্টারফেস নির্মাতায় বা প্রোগ্রামমেটিকভাবে) ব্যবহার করতে পারি তখন আমি ক্লাস হিসাবে সামারভিউ ব্যবহার করতে পারি।

আপডেট - সুইফট 3 সিনট্যাক্স ব্যবহার করে

নিম্নলিখিত এক্সটেনশনে একটি xib লোড করা একটি উদাহরণ পদ্ধতি হিসাবে লেখা হয়, যা পরে উপরের মত একটি আরম্ভকারী দ্বারা ব্যবহার করা যেতে পারে:

extension UIView {

    @discardableResult   // 1
    func fromNib<T : UIView>() -> T? {   // 2
        guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else {    // 3
            // xib not loaded, or its top view is of the wrong type
            return nil
        }
        self.addSubview(contentView)     // 4
        contentView.translatesAutoresizingMaskIntoConstraints = false   // 5 
        contentView.layoutAttachAll(to: self)   // 6 
        return contentView   // 7
    }
}
  1. প্রত্যাবর্তনযোগ্য রিটার্ন মানটি ব্যবহার করা যেহেতু সমস্ত আউটলেট ইতিমধ্যে সংযুক্ত থাকে তখন ফিরে আসা ভিউর কলকারীর পক্ষে বেশিরভাগ আগ্রহী নয়।
  2. এটি একটি জেনেরিক পদ্ধতি যা ইউআইভিউ-র টাইপের একটি alচ্ছিক অবজেক্ট দেয়। যদি ভিউটি লোড করতে ব্যর্থ হয় তবে এটি শূন্য করে।
  3. বর্তমান শ্রেণীর উদাহরণ হিসাবে একই নামের সাথে একটি এক্সআইবি ফাইল লোড করার চেষ্টা করা হচ্ছে। যদি এটি ব্যর্থ হয় তবে শূন্যস্থানটি ফেরত দেওয়া হবে।
  4. শীর্ষ স্তরের দর্শনটি ভিউ হায়ারার্কিতে যুক্ত করা হচ্ছে।
  5. এই লাইনটি ধরে নেওয়া হয়েছে যে আমরা ভিউটি বিন্যাস করতে বাধা ব্যবহার করছি।
  6. এই পদ্ধতিটি শীর্ষ, নীচে, শীর্ষস্থানীয় এবং পিছনের সীমাবদ্ধতাগুলি যুক্ত করে - সমস্ত দিক থেকে "নিজের" সাথে সংযুক্তিটি দেখায় (বিস্তারিত দেখুন: https://stackoverflow.com/a/46279424/2274829 )
  7. শীর্ষ স্তরের দর্শন ফিরিয়ে দেওয়া

এবং কলার পদ্ধতিটি দেখতে এরকম হতে পারে:

final class SomeView: UIView {   // 1.
   required init?(coder aDecoder: NSCoder) {   // 2 - storyboard initializer
      super.init(coder: aDecoder)
      fromNib()   // 5.
   }
   init() {   // 3 - programmatic initializer
      super.init(frame: CGRect.zero)  // 4.
      fromNib()  // 6.
   }
   // other methods ...
}
  1. সোমারক্লাস হ'ল একটি ইউআইভিউ সাবক্লাস যা এর সামগ্রীটি সোমারক্লাস.ক্সিব ফাইল থেকে লোড করে। "চূড়ান্ত" কীওয়ার্ডটি .চ্ছিক।
  2. স্টোরিবোর্ডে যখন ভিউটি ব্যবহৃত হয় তার জন্য একটি প্রাথমিককরণ (আপনার স্টোরিবোর্ডের ভিউটির কাস্টম শ্রেণি হিসাবে সামার ক্লাস ব্যবহার করার কথা মনে রাখবেন)।
  3. প্রোগ্রামটিগতভাবে যখন ভিউটি তৈরি করা হয় তার জন্য একটি ইনিশিয়ালাইজার (উদাহরণস্বরূপ: "চলুন আমারভিউ = সামুভিউ ()")।
  4. অল-জিরো ফ্রেম ব্যবহার করা যেহেতু এই দৃশ্যটি অটো-লেআউটটি ব্যবহার করে তৈরি করা হয়েছে। নোট করুন যে একটি "init (ফ্রেম: সিজিআরেক্ট) {..}" পদ্ধতিটি স্বাধীনভাবে তৈরি হয় না, যেহেতু আমাদের প্রকল্পে অটো-লেআউটটি একচেটিয়াভাবে ব্যবহৃত হয়।
  5. & 6. এক্সটেনশনটি ব্যবহার করে xib ফাইলটি লোড হচ্ছে।

ক্রেডিট: এই সমাধানটিতে জেনেরিক এক্সটেনশন ব্যবহার নীচে রবার্টের উত্তরে অনুপ্রাণিত হয়েছিল।

সম্পাদনা এড়ানোর বিভ্রান্তির থেকে "contentView" থেকে "View" পরিবর্তন। অ্যারে সাবস্ক্রিপ্টকে ".ফার্স্ট" এও পরিবর্তন করা হয়েছে।


7
File's Ownerঘটনাস্থলে আঘাতের জন্য শ্রেণীর নাম নির্ধারণ করা হচ্ছে ... ধন্যবাদ!
অ্যাভিয়েল গ্রস

13
UIView, সম্পত্তি দৃশ্য নেই তাই self.view কলিং একটি ত্রুটি ঘটায়
Nastya Gorban

4
@ নাস্ট্যাগর্বাণ সেল্ফ.ভিউ প্রকৃতপক্ষে এই ক্ষেত্রে আউটলেট বৈশিষ্ট্যটিকে ("নাম হিসাবে দেখানো হয়েছে") নির্দেশ করে যা .Kib এর শীর্ষ স্তরের ভিউ থেকে সোমারভিউ.উইউফিটের সাথে সংযুক্ত GK100 that "ভিউ না থাকায় আউটলেটটি আপনাকে ত্রুটি দেবে" "NSView ক্লাসের সম্পত্তি আপনি বলতে হয়।
Ausiàs

3
নিব লোড করার সময় ক্রাশ হয়ে যাচ্ছি (loadNibName)।
এক্সকোড

11
পদ্ধতির অভ্যন্তরে নিব লোড fromNib()করার সাথে সাথে কলিং init(coder aDecoder: NSCoder)একটি অসীম লুপ তৈরি fromNib()করে:init(coder aDecoder: NSCoder)
ম্যাথু কওলি

334

আমার অবদান:

extension UIView {
    class func fromNib<T: UIView>() -> T {
        return Bundle(for: T.self).loadNibNamed(String(describing: T.self), owner: nil, options: nil)![0] as! T
    }
}

তারপরে এটিকে কল করুন:

let myCustomView: CustomView = UIView.fromNib()

..অথবা এমনকি:

let myCustomView: CustomView = .fromNib()

20
এখন পর্যন্ত সেরা উত্তর।
কোডিমেস

7
এখানে সেরা উত্তর। পরিষ্কার এবং সরল
মারকভিয়াস ড্রাগন

3
@ ইউচেঞ্জহং - আমি [0] এর চেয়ে বেশি পছন্দ করি fi আপনি যদি জোর করে এটি মোড়ানো করেন তবে এটি নিরাপদ হবে না। ... এবং এই প্রশ্নটি উত্থাপন করে: উপরের কয়েকটি সমাধান হিসাবে anচ্ছিককে কেন ফিরিয়ে দেওয়া হচ্ছে না? উত্তর: আপনি পারেন। কিছুতেই ভুল হয়নি। তবে ... এটি যদি কখনও শূন্য হয় তবে xib / শ্রেণির নাম মেলে না। এটি একটি বিকাশকারী ভুল এবং অবিলম্বে ধরা উচিত এবং কখনও এটি উত্পাদন করতে হবে না। এখানে আমি অ্যাপটিকে কিছু অদ্ভুত অবস্থায় ফেলে রেখে ক্র্যাশ করতে পছন্দ করব। শুধু আমার 2 সেন্ট / পছন্দ।
রবার্ট গুমসন

1
@ অ্যালেনলিলি - কাস্টমভিউ হিসাবে অনুমিত হিসাবে পদ্ধতিটি ইউআইভিউয়ের একটি স্থির এক্সটেনশন। এটি কাজ করে কারণ সংকলক সূক্ষ্ম ধরণের টিকাটি ব্যবহার করে টাইপ করে ers কাস্টমভিউ ইউআইভিউর একটি সাবক্লাস এবং প্রকারটি ইতিমধ্যে অনুমান করা হয়েছে, আমাদের এটি আবার অনুমান করার দরকার নেই, ইউআইভিউউকে আমার দ্বিতীয় উদাহরণে দেখানো হিসাবে বাদ দেওয়া যেতে পারে। এটি বলার পরে, আপনি স্পষ্টতই কলটি যেভাবে নামিয়েছিলেন তা করতে পারেন।
রবার্ট গুমসন

3
যখন .xib এর অভ্যন্তরে কাস্টম ভিউ ছিল তখন এই সমাধানটি আমার পক্ষে কার্যকর হয়নি। আমি এই অংশটি ঠিক করার পরামর্শ দেব: Bundle.main.loadNibName (স্ট্রিং (বর্ণনা: স্ব): মালিক: শূন্য, বিকল্পগুলি: শূন্য)! [0] হিসাবে! টি
নাদজেয়া

79

এখন -> Selfদ্রুত ফিরে আসতে সক্ষম হওয়া এটিকে কিছুটা সহজ করতে সহায়তা করে। সুইফট 5 এ সর্বশেষ কনফার্ম করা হয়েছে।

extension UIView {
    class func fromNib(named: String? = nil) -> Self {
        let name = named ?? "\(Self.self)"
        guard
            let nib = Bundle.main.loadNibNamed(name, owner: nil, options: nil)
            else { fatalError("missing expected nib named: \(name)") }
        guard
            /// we're using `first` here because compact map chokes compiler on
            /// optimized release, so you can't use two views in one nib if you wanted to
            /// and are now looking at this
            let view = nib.first as? Self
            else { fatalError("view of type \(Self.self) not found in \(nib)") }
        return view
    }
}

যদি তোমার .xib ফাইল এবং সাবক্লাস একই নামটি ভাগ করে, আপনি ব্যবহার করতে পারেন:

let view = CustomView.fromNib()

আপনার যদি কাস্টম নাম থাকে তবে ব্যবহার করুন:

let view = CustomView.fromNib(named: "special-case")

বিঃদ্রঃ:

যদি আপনি "আপনার টাইপ টাইপের দর্শনটি পাওয়া যায় নি .." ত্রুটিটি পেয়ে থাকেন তবে আপনি সেই ভিউটির শ্রেণিটি সেট করে নি .xib ফাইল

.xibফাইলটিতে আপনার ভিউ নির্বাচন করুন এবং চাপুন cmd + opt + 4এবং classইনপুটটিতে আপনার ক্লাসটি প্রবেশ করুন


1
আমি এটি এক্সকোড 7.1 বিটা 3 এর অধীনে কাজ করতে পারি না - এটি কোনও বিটা জিনিস কিনা তা নিশ্চিত নই তবে মূলত আমি সুইফটে একটি নিব থেকে সরাসরি একটি কাস্টম ভিউ তৈরির জন্য সর্বদাই চেষ্টা করেছি এবং আমি সর্বদা একই ফলাফল পাই: এটি যে শ্রেণীটি তৈরি করছে তা আউটলেটগুলির সাথে অনুগত কেভিসি নয়। এটি ভুল যে আমি কিছু করছি সে সম্পর্কে নিশ্চিত না তবে আমার ক্লাসটি বেশ সহজ এবং ফাইলটির মালিক সঠিক। আমি এটি সমস্ত সময় অবজেক্টিভ-সি এর অধীনে করতাম।
এচেলন

1
@ লোগান এটি আপনার কোডের সাথে সত্যিই সম্পর্কিত নয়, তবে ইমো কাস্টম ভিউগুলির স্টোরিবোর্ড / এক্সআইবি থেকে লোডিং সমর্থন করা উচিত। আমার মন্তব্যটি তাদের জন্য কেবল একটি বিজ্ঞপ্তি ছিল, যারা এই জাতীয় মতামত তৈরি করতে চান
নিকিতা টুক

1
দ্রষ্টব্য, এই ফাংশনটি কল করার দ্বিতীয় ফর্মটি ব্যবহার করার পরেও আমার এখনও সমস্যা আছে let myCustomView = UIView.fromNib() as? CustomView। এই ক্ষেত্রে, T.selfকরতে সমাধান করা UIViewবদলে CustomViewএবং এটি নিব এটি ব্যর্থ। আমি কেন নিশ্চিত তা নিশ্চিত নই - সম্ভবত কারণটির জন্য অনুমিত টাইপটিকে letফাংশনটি বলা হয় UIView?
এচেলন

2
এটি উল্লেখ করা গুরুত্বপূর্ণ যে আউটলেটগুলি হুক করার জন্য ফাইলের মালিককে ব্যবহার করার চেষ্টা করা (যেমনটি আমরা খুব আগের দিনগুলিতে করেছি) এটি ক্রাশের কারণ হতে পারে। আইবিতে, ফাইলের মালিক অবশ্যই শূন্য / ফাঁকা থাকতে হবে এবং এর পরিবর্তে আউটলেটগুলি ভিউ পর্যন্ত আপ করা উচিত।
এচেলন

1
@ এচেলন আপনি আমার দিন বাঁচিয়েছেন !!! আমি ফাইলের মালিক ব্যবহার করে আমার আউটলেটগুলি সংযুক্ত করেছি এবং পরিবর্তে দৃশ্যটি ব্যবহার করে এটি কাজ করে না।
জান শ্লারফ

19

কোড অনুসরণ করার চেষ্টা করুন।

var uiview :UIView?

self.uiview = NSBundle.mainBundle().loadNibNamed("myXib", owner: self, options: nil)[0] as? UIView

সম্পাদনা:

import UIKit

class TestObject: NSObject {

     var uiview:UIView?

    init()  {
        super.init()
       self.uiview = NSBundle.mainBundle().loadNibNamed("myXib", owner: self, options: nil)[0] as? UIView
    }


}

আমাকে এই পদ্ধতিটি অবজেক্ট ইনিশিয়ালাইজেশন পদ্ধতির অভ্যন্তরে কল করতে হবে যা সুইফটে ইনডি () রয়েছে।
বাগসফ্লায়ার

12

সুইফট 4 প্রোটোকল এক্সটেনশানস

public protocol NibInstantiatable {

    static func nibName() -> String

}

extension NibInstantiatable {

    static func nibName() -> String {
        return String(describing: self)
    }

}

extension NibInstantiatable where Self: UIView {

    static func fromNib() -> Self {

        let bundle = Bundle(for: self)
        let nib = bundle.loadNibNamed(nibName(), owner: self, options: nil)

        return nib!.first as! Self

    }

}

গ্রহণ

class MyView: UIView, NibInstantiatable {

}

এই বাস্তবায়ন অনুমান করে যে নিআইবির একই নাম ইউআইভিউ ক্লাস। যাত্রা। MyView.xib। আপনি ডিফল্ট প্রোটোকল এক্সটেনশন প্রয়োগের চেয়ে আলাদা নাম ফিরে পেতে মাইভিউতে নিবনেম () প্রয়োগ করে এই আচরণটি পরিবর্তন করতে পারেন।

এক্সবিতে ফাইলগুলির মালিক মাইভিউ এবং রুট ভিউ ক্লাসটি মাইভিউ।

ব্যবহার

let view = MyView.fromNib()

3
এটি এখন পর্যন্ত সবচেয়ে মার্জিত, সহজ সমাধান এবং কেন এটি গ্রহণযোগ্য উত্তর নয় তা আমার কোনও ধারণা নেই!
ঘোড়া 7

@ horseshoe7 কারণ এটি প্রশ্নের 4 বছর পরে লেখা হয়েছে।
ফ্রিবিবি

11

আমি নিম্নলিখিত কোড দ্বারা সুইফট দিয়ে এটি অর্জন করেছি:

class Dialog: UIView {
    @IBOutlet var view:UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.frame = UIScreen.mainScreen().bounds
        NSBundle.mainBundle().loadNibNamed("Dialog", owner: self, options: nil)
        self.view.frame = UIScreen.mainScreen().bounds
        self.addSubview(self.view)
    }

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

আপনার XIB সংযোগ করতে ভুলবেন না দৃশ্য থেকে নালী দৃশ্য দ্রুতগতি সংজ্ঞায়িত নালী। কোনও অতিরিক্ত আউটলেট সংযোগ শুরু করতে আপনি নিজের কাস্টম শ্রেণীর নামের প্রথম প্রতিক্রিয়াকারী সেট করতে পারেন।

আশাকরি এটা সাহায্য করবে!


10

এক্সকোড 7 বিটা 4, সুইফট 2.0 এবং আইওএস 9 এসডিকে পরীক্ষিত। নিম্নলিখিত কোডটি ইউআইভিউতে এক্সিবকে নিয়োগ করবে। আপনি স্টোরিবোর্ডে এই কাস্টম এক্সিব ভিউটি ব্যবহার করতে পারবেন এবং আইবিউটলেট অবজেক্টটিতেও অ্যাক্সেস করতে পারবেন।

import UIKit

@IBDesignable class SimpleCustomView:UIView
{
    var view:UIView!;

    @IBOutlet weak var lblTitle: UILabel!

   @IBInspectable var lblTitleText : String?
        {
        get{
            return lblTitle.text;
        }
        set(lblTitleText)
        {
            lblTitle.text = lblTitleText!;
        }
    }

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

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        loadViewFromNib ()
    }
    func loadViewFromNib() {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: "SimpleCustomView", bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
        view.frame = bounds
        view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        self.addSubview(view);



    }


}

প্রোগ্র্যাম্যাটিকভাবে কাস্টমভিউ অ্যাক্সেস করুন

self.customView =  SimpleCustomView(frame: CGRectMake(100, 100, 200, 200))
        self.view.addSubview(self.customView!);

উত্স কোড - https://github.com/karthikprabhuA/CustomXIBSwift


9

আপনার প্রকল্পে কাস্টম মতামত প্রচুর থাকলে আপনি শ্রেণীর মতো তৈরি করতে পারেন UIViewFromNib

সুইফট 2.3

class UIViewFromNib: UIView {

    var contentView: UIView!

    var nibName: String {
        return String(self.dynamicType)
    }

    //MARK:
    override init(frame: CGRect) {
        super.init(frame: frame)

        loadViewFromNib()
    }

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

        loadViewFromNib()
    }

    //MARK:
    private func loadViewFromNib() {
        contentView = NSBundle.mainBundle().loadNibNamed(nibName, owner: self, options: nil)[0] as! UIView
        contentView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        contentView.frame = bounds
        addSubview(contentView)
    }
}

সুইফট 3

class UIViewFromNib: UIView {

    var contentView: UIView!

    var nibName: String {
        return String(describing: type(of: self))
    }

    //MARK:
    override init(frame: CGRect) {
        super.init(frame: frame)

        loadViewFromNib()
    }

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

        loadViewFromNib()
    }

    //MARK:
    func loadViewFromNib() {
        contentView = Bundle.main.loadNibNamed(nibName, owner: self, options: nil)?[0] as! UIView
        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        contentView.frame = bounds
        addSubview(contentView)
    }
}

এবং প্রতিটি শ্রেণীতে কেবল উত্তরাধিকার সূত্রে প্রাপ্ত UIViewFromNib, ফাইলের আলাদা আলাদা নাম nibNameথাকলে আপনি সম্পত্তি ওভাররাইড করতে পারেন .xib:

class MyCustomClass: UIViewFromNib {

}

8

উপরের সমাধানগুলিতে বিল্ডিং।

এটি সমস্ত প্রকল্পের বান্ডিল জুড়ে কাজ করবে এবং নিব () থেকে কল করার সময় জেনেরিকের প্রয়োজন হবে না।

সুইফট 2

extension UIView {

    public class func fromNib() -> Self {
        return fromNib(nil)
    }

    public class func fromNib(nibName: String?) -> Self {

        func fromNibHelper<T where T : UIView>(nibName: String?) -> T {
            let bundle = NSBundle(forClass: T.self)
            let name = nibName ?? String(T.self)
            return bundle.loadNibNamed(name, owner: nil, options: nil)?.first as? T ?? T()
        }
        return fromNibHelper(nibName)
    }
}

সুইফট 3

extension UIView {

    public class func fromNib() -> Self {
        return fromNib(nibName: nil)
    }

    public class func fromNib(nibName: String?) -> Self {
        func fromNibHelper<T>(nibName: String?) -> T where T : UIView {
            let bundle = Bundle(for: T.self)
            let name = nibName ?? String(describing: T.self)
            return bundle.loadNibNamed(name, owner: nil, options: nil)?.first as? T ?? T()
        }
        return fromNibHelper(nibName: nibName)
    }
}

এটি ব্যবহার করা যেতে পারে:

let someView = SomeView.fromNib()

বা এই মত:

let someView = SomeView.fromNib("SomeOtherNibFileName")

6

সুইফট 4

".প্রথম হিসাবে? কাস্টমভিউ" লিখতে ভুলবেন না

if let customView = Bundle.main.loadNibNamed("myXib", owner: self, options: nil)?.first as? CustomView {    
    self.view.addSubview(customView)
    }

আপনি যদি কোথাও ব্যবহার করতে চান

সেরা সমাধান রবার্ট গুমসন এর উত্তর।

extension UIView {
    class func fromNib<T: UIView>() -> T {
        return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)![0] as! T
    }
}

তারপরে এটিকে কল করুন:

let myCustomView: CustomView = UIView.fromNib()

5
let subviewArray = NSBundle.mainBundle().loadNibNamed("myXib", owner: self, options: nil)
return subviewArray[0]

কিন্তু সুইফ্টের init () এ, কোনও ফেরত মান নেই। আমি ইউআইভিউয়ের সূচনাতে লোডনিবনেড কল করতে হবে তা উল্লেখ করতে ভুলে গিয়েছিলাম forgot
বাগশুফায়ার

"রিটার্নের মূল্য নেই" বলতে কী বোঝ? selfসমস্ত initপদ্ধতি থেকে
স্পষ্টতই

1
আমার অর্থ হ'ল আমি init পদ্ধতির অভ্যন্তরে লোডনাইব নামক ডাকছি। লোড হওয়া ইউআইভিউউভকে ওবিজেসি-তে স্বতন্ত্রিত করা হয়েছে। কিন্তু দ্রুত, এটি না।
বাগসফ্লায়ার

5

সুইফ্টের সাথে এটি করার একটি দুর্দান্ত উপায় হ'ল এনুম ব্যবহার করা।

enum Views: String {
    case view1 = "View1" // Change View1 to be the name of your nib
    case view2 = "View2" // Change View2 to be the name of another nib

    func getView() -> UIView? {
        return NSBundle.mainBundle().loadNibNamed(self.rawValue, owner: nil, options: nil).first as? UIView
    }
}

তারপরে আপনার কোডে আপনি কেবল ব্যবহার করতে পারেন:

let view = Views.view1.getView()

2
মনে রাখবেন যে আপনি যদি খালি নিব ফাইল বা কোনও ইউআইভিউ রুট নোডের সাথে একটি নিব ফাইল দিয়ে এটি করেন তবে আপনি ক্র্যাশ হয়ে যাবেন কারণ আপনি স্যানিটি পরীক্ষা করে অ্যারের আকার বা পজিশনে উপাদানটি 0 করছেন না
ম্যাথু কওলি

4

আমি এই সমাধানটি পছন্দ করি (@ জি কে 100 যদি উত্তরের ভিত্তিতে):

  1. আমি সিমভিউ নামে একটি দ্বাদশ এবং ক্লাস তৈরি করেছি (সুবিধার্থে এবং পাঠযোগ্যতার জন্য একই নাম ব্যবহার করেছি)। আমি উভয়ই একটি ইউআইভিউয়ের উপর ভিত্তি করে তৈরি করেছি।
  2. দ্বাদশটিতে আমি "ফাইলের মালিক" ক্লাসটি সাম্যর ভিউতে (পরিচয় পরিদর্শকটিতে) পরিবর্তন করেছি।
  3. XIB ফাইলের শীর্ষ স্তরের দৃশ্যের সাথে এটি যুক্ত করে, সুবিধার জন্য এটির "ভিউ" নামকরণ করা হয়েছে) আমি সাম্ভিউ.উইউউইটে একটি ইউআইভিউ আউটলেট তৈরি করেছি। আমি তখন প্রয়োজন অনুসারে এক্সআইবি ফাইলের অন্যান্য নিয়ন্ত্রণগুলিতে অন্যান্য আউটলেটগুলি যুক্ত করেছি।
  4. SomeView.swift, আমি ভিতরে XIB লোড initবা init:frame: CGRectসূচনাকারী। "স্ব" কে কিছু বরাদ্দ করার দরকার নেই। এক্সআইবি লোড হওয়ার সাথে সাথে শীর্ষ স্তরের দৃশ্য সহ সমস্ত আউটলেট সংযুক্ত হয়ে যায়। একমাত্র জিনিসটি অনুপস্থিত, হ'ল হাইয়ারার্কিতে শীর্ষের ভিউ যুক্ত করা:

    class SomeView: UIView {
      override init(frame: CGRect) {
        super.init(frame: frame)
        NSBundle.mainBundle().loadNibNamed("SomeObject", owner: self, options: nil)
        self.addSubview(self.view);    // adding the top level view to the view hierarchy
      }
    
      required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        NSBundle.mainBundle().loadNibNamed("SomeObject", owner: self, options: nil)
        self.addSubview(self.view);    // adding the top level view to the view hierarchy
      }
    
    
      ...
    }

আমি ফ্রেম দিয়ে init ব্যবহার করতে পছন্দ করি তাই আমি এটিকে উপড়ে ফেলেছি! একটি বিষয় লক্ষণীয় ... self.view.frame = ফ্রেম যুক্ত করুন যদি আপনি যে ফ্রেমটি পাশ করেন তার সাথে মিলটি দেখতে চান
মাইক ই

3

লোগানের উত্তরের সুইফ্ট 3 সংস্করণ

extension UIView {
    public class func fromNib(nibName: String? = nil) -> Self {
        return fromNib(nibName: nibName, type: self)
    }

    public class func fromNib<T: UIView>(nibName: String? = nil, type: T.Type) -> T {
        return fromNib(nibName: nibName, type: T.self)!
    }

    public class func fromNib<T: UIView>(nibName: String? = nil, type: T.Type) -> T? {
        var view: T?
        let name: String

        if let nibName = nibName {
            name = nibName
        } else {
            name = self.nibName
        }

        if let nibViews = Bundle.main.loadNibNamed(name, owner: nil, options: nil) {
            for nibView in nibViews {
                if let tog = nibView as? T {
                    view = tog
                }
            }
        }

        return view
    }

    public class var nibName: String {
        return "\(self)".components(separatedBy: ".").first ?? ""
    }

    public class var nib: UINib? {
        if let _ = Bundle.main.path(forResource: nibName, ofType: "nib") {
            return UINib(nibName: nibName, bundle: nil)
        } else {
            return nil
        }
    }
}

3

একটি প্রোটোকল এবং প্রোটোকল এক্সটেনশন (সুইফট 4.2) ব্যবহার করে প্রোগ্রামটি ভিউ লোড করার একটি পরিষ্কার এবং ঘোষিত উপায় way

protocol XibLoadable {
    associatedtype CustomViewType
    static func loadFromXib() -> CustomViewType
}

extension XibLoadable where Self: UIView {
    static func loadFromXib() -> Self {
        let nib = UINib(nibName: "\(self)", bundle: Bundle(for: self))
        guard let customView = nib.instantiate(withOwner: self, options: nil).first as? Self else {
            // your app should crash if the xib doesn't exist
            preconditionFailure("Couldn't load xib for view: \(self)")
        }
        return customView
    }
}

এবং আপনি এটি এর মতো ব্যবহার করতে পারেন:

// don't forget you need a xib file too
final class MyView: UIView, XibLoadable { ... }

// and when you want to use it
let viewInstance = MyView.loadFromXib()

কিছু অতিরিক্ত বিবেচনা :

  1. আপনার কাস্টম ভিউয়ের এক্সিব ফাইলটিতে ভিউ'র Custom Classসেট (এবং সেখান থেকে আউটলেটগুলি / ক্রিয়া সেট করা আছে) আছে, তা ফাইলের মালিকের নয় তা নিশ্চিত করুন।
  2. আপনি এই প্রোটোকল / এক্সটেনশনটি আপনার কাস্টম ভিউ বা অভ্যন্তরীণ বাহ্যিকভাবে ব্যবহার করতে পারেন। আপনার ভিউটি আরম্ভ করার সময় আপনার যদি অন্য কোনও সেটআপ কাজ থাকে তবে আপনি অভ্যন্তরীণভাবে এটি ব্যবহার করতে চাইতে পারেন।
  3. আপনার কাস্টম ভিউ ক্লাস এবং এক্সিব ফাইলের একই নাম থাকা দরকার।

2

আমি কেবল এইভাবে করি:

if let myView = UINib.init(nibName: "MyView", bundle: nil).instantiate(withOwner: self)[0] as? MyView {
// Do something with myView
}

এই নমুনাটি মূল বান্ডলে নিব "মাইভিউ.অক্সিব" এ প্রথম দৃশ্য ব্যবহার করে। তবে আপনি সূচক, নিব নাম, বা বান্ডিল (ডিফল্টরূপে মূল) হয় আলাদা করতে পারেন।

আমি ভিউ ডিআইডি পদ্ধতিতে দৃষ্টিভঙ্গি জাগ্রত করতাম বা উপরের সমাধানগুলির মতো জেনেরিক পদ্ধতি তৈরি করতাম (যা উপায় দ্বারা স্মার্ট) তবে আমি এটি আর করি না।

একই ভিউ যুক্তি এবং কোড রাখার সময় আমি বিভিন্ন লেআউট বা বৈশিষ্ট্য ব্যবহার করতে পারি।

আমি কোনও কারখানার অবজেক্ট (সাধারণত ভিউ কনট্রোলার যা দৃশ্যটি ব্যবহার করবে) এটি তার প্রয়োজন হিসাবে এটি তৈরি করতে সহজ মনে করি। কখনও কখনও আপনার কোনও মালিকের প্রয়োজন হয় (সাধারণত যখন তৈরির দৃশ্যটি স্রষ্টার সাথে সংযুক্ত থাকে তবে কখনও কখনও না ..)

এ কারণেই সম্ভবত অ্যাপল initFromNibতার ইউআইভিউ ক্লাসে কোনও পদ্ধতি অন্তর্ভুক্ত করেনি ...

স্থল স্তরের উদাহরণ গ্রহণ করার জন্য, আপনি কীভাবে জন্মগ্রহণ করেন তা জানেন না। আপনি সবে জন্মগ্রহণ করেছেন। মতামতও তাই;)


2

আপনাকে যা করতে হবে তা হ'ল আপনার UIViewক্লাসে কল আরম্ভ পদ্ধতি ।

সেভাবে করুন:

class className: UIView {

    @IBOutlet var view: UIView!

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

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

    func setup() {
        UINib(nibName: "nib", bundle: nil).instantiateWithOwner(self, options: nil)
        addSubview(view)
        view.frame = self.bounds
    }
}

এখন, আপনি যদি ভিউ কন্ট্রোলারে সাব ভিউ হিসাবে এই ভিউটি যুক্ত করতে চান, তবে কন্ট্রোলারস সুইট ফাইলটিতে এমনভাবে করুন:

self.view.addSubview(className())

এটি দুর্দান্ত উত্তর তবে কিছু ভুল আছে, আমি এটি সম্পাদনা করব।
C0mrad

আমি যেভাবে প্রয়োগ করেছি এটি। তবে আপনি এটি উন্নত করতে পারেন। অগ্রিম ধন্যবাদ C0mrad
আলাপ আনেরাও

1

উপরের কিছু উত্তরের মতো তবে আরও সুসংগত সুইফট 3 ইউআইভিউ এক্সটেনশন:

extension UIView {
    class func fromNib<A: UIView> (nibName name: String, bundle: Bundle? = nil) -> A? {
        let bundle = bundle ?? Bundle.main
        let nibViews = bundle.loadNibNamed(name, owner: self, options: nil)
        return nibViews?.first as? A
    }

    class func fromNib<T: UIView>() -> T? {
        return fromNib(nibName: String(describing: T.self), bundle: nil)
    }
}

যা স্বনির্ভর নামের একটি স্ব থেকেও অন্যান্য নিবস / বান্ডিল থেকে ক্লাস লোড করতে সক্ষম হওয়ার সুবিধা দেয়।


1

আপনি স্টোরিবোর্ডের মাধ্যমে এটি করতে পারেন, দেখার জন্য কেবল সঠিক সীমাবদ্ধতা যুক্ত করুন। আপনি নিজের থেকে যে কোনও ভিউ সাবক্ল্যাসিং করে সহজেই এটি করতে পারেন যাক BaseView:

উদ্দেশ্য গ

BaseView.h


/*!
 @class BaseView
 @discussion Base View for getting view from xibFile
 @availability ios7 and later
 */
@interface BaseView : UIView

@end


BaseView.m


#import "BaseView.h"

@implementation BaseView

#pragma mark - Public

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        [self prepareView];
    }
    return self;
}

#pragma mark - LifeCycle

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self prepareView];
    }
    return self;
}

#pragma mark - Private

- (void)prepareView
{
    NSArray *nibsArray = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
    UIView *view = [nibsArray firstObject];

    view.translatesAutoresizingMaskIntoConstraints = NO;
    [self addSubview:view];
    [self addConstraintsForView:view];
}

#pragma mark - Add constraints

- (void)addConstraintsForView:(UIView *)view
{
    [self addConstraints:@[[NSLayoutConstraint constraintWithItem:view
                                                        attribute:NSLayoutAttributeBottom
                                                        relatedBy:NSLayoutRelationEqual
                                                           toItem:self attribute:NSLayoutAttributeBottom
                                                       multiplier:1.0
                                                         constant:0],
                           [NSLayoutConstraint constraintWithItem:view
                                                        attribute:NSLayoutAttributeTop
                                                        relatedBy:NSLayoutRelationEqual
                                                           toItem:self attribute:NSLayoutAttributeTop
                                                       multiplier:1.0
                                                         constant:0],
                           [NSLayoutConstraint constraintWithItem:view
                                                        attribute:NSLayoutAttributeLeft
                                                        relatedBy:NSLayoutRelationEqual
                                                           toItem:self attribute:NSLayoutAttributeLeft
                                                       multiplier:1.0
                                                         constant:0],
                           [NSLayoutConstraint constraintWithItem:view
                                                        attribute:NSLayoutAttributeRight
                                                        relatedBy:NSLayoutRelationEqual
                                                           toItem:self attribute:NSLayoutAttributeRight
                                                       multiplier:1.0
                                                         constant:0]
                           ]];
}

@end

সুইফট 4

import UIKit

class BaseView : UIView {

    // MARK: - LifeCycle

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

        prepareView()
    }

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

        prepareView()
    }

    internal class func xibName() -> String {
        return String(describing: self)
    }

    // MARK: - Private
    fileprivate func prepareView() {
        let nameForXib = BaseView.xibName()
        let nibs = Bundle.main.loadNibNamed(nameForXib, owner: self, options: nil)
        if let view = nibs?.first as? UIView {
            view.backgroundColor = UIColor.clear
            view.translatesAutoresizingMaskIntoConstraints = false
            addSubviewWithConstraints(view, offset: false)
        }
    }
}

UIView+Subview


public extension UIView {
    // MARK: - UIView+Extensions

    public func addSubviewWithConstraints(_ subview:UIView, offset:Bool = true) {
        subview.translatesAutoresizingMaskIntoConstraints = false
        let views = [
            "subview" : subview
        ]
        addSubview(subview)

        var constraints = NSLayoutConstraint.constraints(withVisualFormat: offset ? "H:|-[subview]-|" : "H:|[subview]|", options: [.alignAllLeading, .alignAllTrailing], metrics: nil, views: views)
        constraints.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: offset ? "V:|-[subview]-|" : "V:|[subview]|", options: [.alignAllTop, .alignAllBottom], metrics: nil, views: views))
        NSLayoutConstraint.activate(constraints)
    }
}

আমি 2 রূপগুলি কীভাবে সীমাবদ্ধতাগুলি যুক্ত করতে পারি - সাধারণ এবং ভিজ্যুয়াল বিন্যাসের ভাষার মধ্যে - আপনার পছন্দসই নির্বাচন করুন :)

এছাড়াও, ডিফল্টরূপে ধরে নেওয়া হয়েছিল যে xibনামটির বাস্তবায়ন শ্রেণীর নাম হিসাবে একই নাম রয়েছে। যদি না - কেবল পরিবর্তন করুনxibName পরামিতি ।

আপনি যদি নিজের দৃষ্টিভঙ্গিটি থেকে সাবক্লাস করেন BaseView- আপনি সহজেই কোনও ভিউ রাখতে পারেন এবং আইবিতে শ্রেণি নির্দিষ্ট করতে পারেন।


1
class func loadFromNib<T: UIView>() -> T {
    let nibName = String(describing: self)
    return Bundle.main.loadNibNamed(nibName, owner: nil, options: nil)![0] as! T
}

0

লোগানের উত্তরের উপর ভিত্তি করে আরও শক্তিশালী সংস্করণ

extension UIView {
    public class func fromNib(nibName: String? = nil) -> Self {
        return fromNib(nibName: nibName, type: self)
    }

    public class func fromNib<T: UIView>(nibName: String? = nil, type: T.Type) -> T {
        return fromNib(nibName: nibName, type: T.self)!
    }

    public class func fromNib<T: UIView>(nibName: String? = nil, type: T.Type) -> T? {
        var view: T?
        let name: String

        if let nibName = nibName {
            name = nibName
        } else {
            name = self.nibName
        }

        if let nibViews = nibBundle.loadNibNamed(name, owner: nil, options: nil) {
            if nibViews.indices.contains(nibIndex), let tog = nibViews[nibIndex] as? T {
                view = tog
            }
        }

        return view
    }

    public class var nibName: String {
        return "\(self)".components(separatedBy: ".").first ?? ""
    }

    public class var nibIndex: Int {
        return 0
    }

    public class var nibBundle: Bundle {
        return Bundle.main
    }
}

এবং আপনি মত ব্যবহার করতে পারেন

class BaseView: UIView {
    override class var nibName: String { return "BaseView" }
    weak var delegate: StandardStateViewDelegate?
}

class ChildView: BaseView {
    override class var nibIndex: Int { return 1 }
}

0

সবচেয়ে সুবিধাজনক বাস্তবায়ন। আপনার শ্রেণীর অবজেক্টে সরাসরি ফিরে আসতে আপনার দুটি পদ্ধতির দরকার, ইউআইভিউ নয়।

  1. viewId একটি হিসাবে চিহ্নিত শ্রেণীওভাররাইডকে অনুমতি দিয়ে
  2. আপনার .xib শীর্ষ স্তরের একাধিক ভিউ ধারণ করতে পারে, এই পরিস্থিতিটিও সঠিকভাবে পরিচালনা করা হয়।

extension UIView {

class var viewId: String {
    return String(describing: self)
}

static func instance(from bundle: Bundle? = nil, nibName: String? = nil,
                    owner: Any? = nil, options: [AnyHashable : Any]? = nil) -> Self? {

    return instancePrivate(from: bundle ?? Bundle.main,
                           nibName: nibName ?? viewId,
                           owner: owner,
                           options: options)
}

private static func instancePrivate<T: UIView>(from bundle: Bundle, nibName: String,
                                              owner: Any?, options: [AnyHashable : Any]?) -> T? {

    guard
        let views = bundle.loadNibNamed(nibName, owner: owner, options: options),
        let view = views.first(where: { $0 is T }) as? T else { return nil }

    return view
}
}

উদাহরণ:

guard let customView = CustomView.instance() else { return }

//Here customView has CustomView class type, not UIView.
print(customView is CustomView) // true

0

যদি আপনি চান যে সুইফট ইউআইভিউ সাবক্লাসটি সম্পূর্ণরূপে স্বয়ংসম্পূর্ণ থাকে এবং কোনও এনআইবি ব্যবহারের বাস্তবায়ন বিশদটি প্রকাশ না করেই init বা init (ফ্রেম :) ব্যবহার করে ইনস্ট্যান্ট করার ক্ষমতা থাকে তবে আপনি এটি অর্জনের জন্য একটি প্রোটোকল এক্সটেনশন ব্যবহার করতে পারেন। এই সমাধানটি অন্যান্য অনেকগুলি সমাধানের পরামর্শ অনুসারে নেস্টেড ইউআইভিউ হায়ারার্কিকে এড়িয়ে চলে।

public class CustomView: UIView {

    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var valueLabel: UILabel!

    public convenience init() {
        self.init(frame: CGRect.zero)
    }

    public override convenience init(frame: CGRect) {
        self.init(internal: nil)
        self.frame = frame
    }

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

    fileprivate func commonInit() {
    }
}

fileprivate protocol _CustomView {
}

extension CustomView: _CustomView {
}

fileprivate extension _CustomView {

    // Protocol extension initializer - has the ability to assign to self, unlike
    // class initializers. Note that the name of this initializer can be anything
    // you like, here we've called it init(internal:)

    init(internal: Int?) {
        self = Bundle.main.loadNibNamed("CustomView", owner:nil, options:nil)![0] as! Self;
    }
}

0
  let bundle = Bundle(for: type(of: self))
   let views = bundle.loadNibNamed("template", owner: self, options: nil)
    self.view.addSubview(views?[0] as! UIView)

কোড শুধুমাত্র উত্তর নিরুৎসাহিত করা হয়। এটি কীভাবে সমস্যাটি সমাধান করে বা বিদ্যমান উত্তরগুলির থেকে এটি কীভাবে পৃথক হয় সে সম্পর্কে কিছু ব্যাখ্যা যুক্ত করুন। পর্যালোচনা থেকে
নিক

0

আমি নীচের এক্সটেনশন পছন্দ

extension UIView {
    class var instanceFromNib: Self {
        return Bundle(for: Self.self)
            .loadNibNamed(String(describing: Self.self), owner: nil, options: nil)?.first as! Self
    }
}

এটির এবং শীর্ষ উত্তরের এক্সটেনশনের মধ্যে পার্থক্য হ'ল আপনার এটিকে একটি ধ্রুবক বা পরিবর্তনশীল সংরক্ষণ করার দরকার নেই।

class TitleView: UIView { }

extension UIView {
    class var instanceFromNib: Self {
        return Bundle(for: Self.self)
            .loadNibNamed(String(describing: Self.self), owner: nil, options: nil)?.first as! Self
    }
}

self.navigationItem.titleView = TitleView.instanceFromNib

আপনি Xcode এর কোন সংস্করণ ব্যবহার করছেন? আপনি XCode এর সর্বশেষতম সংস্করণ ব্যবহার করছেন তা নিশ্চিত করুন। এক্সকোড 11.5 (তারিখের মতো সর্বশেষতম সংস্করণ) দিয়ে আমার জন্য দুর্দান্ত কাজ করে।
আইকোডার

0
    let nibs = Bundle.main.loadNibNamed("YourView", owner: nil, options: nil)
    let shareView = nibs![0] as! ShareView
    self.view.addSubview(shareView)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.