স্টোরিবোর্ডে একটি বাহ্যিক এক্সিব ফাইল থেকে ভিউ লোড করুন


131

আমি স্টোরিবোর্ডে একাধিক ভিউকন্ট্রোলার জুড়ে একটি ভিউ ব্যবহার করতে চাই। সুতরাং, আমি বাহ্যিক xib এ ভিউ ডিজাইন করার বিষয়ে ভেবেছিলাম যাতে প্রতিটি ভিউকন্ট্রোলারে পরিবর্তনগুলি প্রতিফলিত হয়। তবে কীভাবে একজন স্টোরবোর্ডে কোনও বহিরাগত এক্সিব থেকে একটি ভিউ লোড করতে পারে এবং এটি কি সম্ভব? যদি এটি না হয়, তবে পরিস্থিতি অব্যাহত রাখতে অন্য কোন বিকল্পগুলি ব্যবহারযোগ্য?



1
এই ভিডিওটি দেখুন: youtube.com/watch?v=o3MawJVxTgk
malhobayyeb

উত্তর:


132

আমার পুরো উদাহরণটি এখানে , তবে আমি নীচে একটি সংক্ষিপ্তসার সরবরাহ করব।

বিন্যাস

আপনার প্রকল্পে একই নামের সাথে একটি .swift এবং .xib ফাইল যুক্ত করুন। .Xib ফাইলটিতে আপনার কাস্টম ভিউ লেআউট (অটো লেআউট সীমাবদ্ধতা ব্যবহার করে) থাকে।

এক্সফিল ফাইলটির মালিক সুইফট ফাইলটি তৈরি করুন।

এখানে চিত্র বর্ণনা লিখুন কোড

.Swift ফাইলটিতে নিম্নলিখিত কোডটি যুক্ত করুন এবং .xib ফাইল থেকে আউটলেট এবং ক্রিয়াগুলি হুক আপ করুন।

import UIKit
class ResuableCustomView: UIView {

    let nibName = "ReusableCustomView"
    var contentView: UIView?

    @IBOutlet weak var label: UILabel!
    @IBAction func buttonTap(_ sender: UIButton) {
        label.text = "Hi"
    }

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

        guard let view = loadViewFromNib() else { return }
        view.frame = self.bounds
        self.addSubview(view)
        contentView = view
    }

    func loadViewFromNib() -> UIView? {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: nibName, bundle: bundle)
        return nib.instantiate(withOwner: self, options: nil).first as? UIView
    }
}

এটা ব্যবহার করো

আপনার স্টোরিবোর্ডের যে কোনও জায়গায় আপনার কাস্টম ভিউটি ব্যবহার করুন। কেবলমাত্র একটি যুক্ত করুন UIViewএবং আপনার কাস্টম শ্রেণীর নামটিতে শ্রেণীর নাম সেট করুন।

এখানে চিত্র বর্ণনা লিখুন


3
এটি কি লোডনিবনেড কল ইন্ডি (কোডার :) নয়? আপনার পদ্ধতির সাথে মানিয়ে নেওয়ার চেষ্টা করে আমার ক্রাশ হয়েছে।
ফিশম্যান

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

7
ক্রাশ হওয়ার আর একটি সাধারণ কারণ ফাইলের মালিকের কাছে কাস্টম ভিউ সেট করা নয় । আমার উত্তরে লাল বৃত্তটি দেখুন।
সুরগাচ

5
হ্যাঁ আমি ফাইলের মালিকের পরিবর্তে রুট ভিউয়ের ক্লাস সেট করেছিলাম এবং এটি অসীম লুপের কারণ হয়ে দাঁড়িয়েছিল।
ডিভাইস 1

2
স্ব.অ্যাডসুবউভিউ (দেখুন) এর আগে ভিউ.আউটোরসাইজিংমাস্ক = [.ফ্লেক্সিব্লুথ, .ফ্লেক্সিবলহাইট] লাইন যুক্ত করার পরে এটি পুরোপুরি কাজ করছে।
প্রমোদ তপানিয়া

69

কিছুক্ষণের জন্য ক্রিস্টোফার স্বাসীর দৃষ্টিভঙ্গি ছিল আমার সেরা পন্থা। আমি আমার দলের কয়েকজন সিনিয়র দেবকে এটি সম্পর্কে জিজ্ঞাসা করেছি এবং তাদের মধ্যে একটির সঠিক সমাধান রয়েছে ! এটি ক্রিস্টোফার স্বাসে এত স্পষ্টভাবে সম্বোধন করে এমন প্রতিটি উদ্বেগকে সন্তুষ্ট করে এবং এতে বয়লারপ্লেট সাবক্লাস কোডের প্রয়োজন হয় না (তাঁর পদ্ধতির সাথে আমার মূল উদ্বেগ)। নেই এক gotcha কিন্তু তুলনায় এটি মোটামুটি স্বজ্ঞাত এবং বাস্তবায়ন করা সহজ যে অন্য।

  1. আপনার এক্সিব নিয়ন্ত্রণ করতে একটি। সুইড ফাইলটিতে একটি কাস্টম ইউআইভিউ ক্লাস তৈরি করুন। অর্থাতMyCustomClass.swift
  2. একটি .xib ফাইল তৈরি করুন এবং এটি আপনার পছন্দ মতো স্টাইল করুন। অর্থাতMyCustomClass.xib
  3. File's Owner.Xib ফাইলটিকে আপনার কাস্টম শ্রেণি হতে সেট করুন ( MyCustomClass)
  4. Gotcha: ছেড়ে classমান (অধীনে identity Inspector.xib ফাইল ফাঁকা অবস্থানে আপনার কাস্টম দৃশ্য জন্য)। সুতরাং আপনার কাস্টম ভিউতে কোনও নির্দিষ্ট শ্রেণি নেই, তবে এতে একটি নির্দিষ্ট ফাইলের মালিক থাকবে।
  5. আপনার আউটলেটগুলি যেমন আপনি সাধারণত ব্যবহার করতে চান তেমনভাবে আপ করুন Assistant Editor
    • দ্রষ্টব্য: আপনি যদি সন্ধান করেন তবে Connections Inspectorলক্ষ্য করবেন যে আপনার রেফারেন্সিং আউটলেটগুলি আপনার কাস্টম ক্লাসটি (যেমন MyCustomClass) উল্লেখ করে না, বরং রেফারেন্স করে File's Owner। যেহেতু File's Ownerআপনার কাস্টম শ্রেণি হিসাবে নির্দিষ্ট করা হয়েছে, আউটলেটগুলি হুক আপ হবে এবং যথাযথভাবে কাজ করবে।
  6. ক্লাস স্টেটমেন্টের আগে আপনার কাস্টম ক্লাসে @IBDesignable রয়েছে তা নিশ্চিত করুন।
  7. আপনার কাস্টম ক্লাসটি NibLoadableনীচে উল্লিখিত প্রোটোকলের সাথে সামঞ্জস্য করুন ।
    • দ্রষ্টব্য: যদি আপনার কাস্টম শ্রেণীর .swiftফাইলের নামটি আপনার .xibফাইলের নামের থেকে আলাদা হয় , তবে nibNameসম্পত্তিটিকে আপনার ফাইলের নাম হিসাবে সেট .xibকরুন।
  8. প্রয়োগ required init?(coder aDecoder: NSCoder)এবং নীচের উদাহরণ মত override init(frame: CGRect)কল setupFromNib()
  9. আপনার পছন্দসই স্টোরিবোর্ডে একটি ইউআইভিউ যুক্ত করুন এবং শ্রেণিকে আপনার কাস্টম শ্রেণীর নাম (যেমন MyCustomClass) হিসাবে সেট করুন।
  10. এটি আপনার বিস্ময় এবং বিস্ময়ের সাথে স্টোরিবোর্ডে .xib আঁকায় আইবি ডিজাইনযোগ্যকে অ্যাকশনে দেখুন।

আপনি উল্লেখ করতে চাইবেন যে প্রোটোকল এখানে:

public protocol NibLoadable {
    static var nibName: String { get }
}

public extension NibLoadable where Self: UIView {

    public static var nibName: String {
        return String(describing: Self.self) // defaults to the name of the class implementing this protocol.
    }

    public static var nib: UINib {
        let bundle = Bundle(for: Self.self)
        return UINib(nibName: Self.nibName, bundle: bundle)
    }

    func setupFromNib() {
        guard let view = Self.nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error loading \(self) from nib") }
        addSubview(view)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
        view.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
        view.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
        view.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
    }
}

এবং এখানে MyCustomClassপ্রোটোকল প্রয়োগ করে এমন একটি উদাহরণ দেওয়া হয়েছে (.xib ফাইলটির নামকরণের সাথে MyCustomClass.xib):

@IBDesignable
class MyCustomClass: UIView, NibLoadable {

    @IBOutlet weak var myLabel: UILabel!

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

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

}

দ্রষ্টব্য: আপনি যদি classগোটচাটি মিস করেন এবং আপনার .xib ফাইলের ভিতরে থাকা মানটিকে আপনার কাস্টম শ্রেণিতে পরিণত করেন, তবে এটি স্টোরিবোর্ডে আঁকবে না এবং EXC_BAD_ACCESSঅ্যাপটি চালানোর সময় আপনি একটি ত্রুটি পাবেন কারণ এটি একটি অসীম লুপে আটকে যায় it নীব থেকে ক্লাস আরম্ভ করার চেষ্টা করে সেই init?(coder aDecoder: NSCoder)পদ্ধতিটি ব্যবহার করে যা আবার কল করে Self.nib.instantiateএবং initআবার কল করে ।


2
এখানে এটির জন্য আরেকটি দুর্দান্ত পদ্ধতির কথা, তবে আমি মনে করি যে উপরেরটিটি
বেন প্যাচ

4
আপনার উপরে উল্লিখিত পদ্ধতিটি নিখুঁতভাবে কাজ করে এবং সরাসরি স্টোরিবোর্ডে লাইভ পূর্বরূপ প্রয়োগ করে। এটি একেবারে সহজ এবং দুর্দান্ত, বড়!
ইগোর লিওনোভিচ

1
এফওয়াইআই: এই সমাধানটিতে সীমাবদ্ধ সংজ্ঞাটি ব্যবহার করে setupFromNib()XIB- তৈরি দর্শনগুলি সহ অটো-সাইজিং টেবিল ভিউ সেলগুলি সহ কিছু অদ্ভুত অটো-লেআউট সমস্যা সমাধান করার জন্য মনে হয়।
গ্যারি

1
এখন পর্যন্ত সেরা সমাধান! আমি @IBDesignableসামঞ্জস্য পছন্দ। কোনও ইউআইভিউ ফাইল যুক্ত করার সময় কেন Xcode বা UIKit ডিফল্ট হিসাবে এর মতো কিছু সরবরাহ করে না তা বিশ্বাস করা যায় না।
fl034

1
এটি একটি কাজ করে মনে হচ্ছে না .. আমি যখনই আমার .xib ফাইলের মধ্যে ফাইলের মালিক সেট করি তখন এটি কাস্টম ক্লাস সেট করে।
drewster

32

ধরে নিই যে আপনি একটি xib তৈরি করেছেন যা আপনি ব্যবহার করতে চান:

1) ইউআইভিউর একটি কাস্টম সাবক্লাস তৈরি করুন (আপনি ফাইল -> নতুন -> ফাইল ... -> কোকো টাচ ক্লাসে যেতে পারেন sure নিশ্চিত করুন যে "সাবক্লাস:" "" ইউআইভিউ ")।

2) xib উপর ভিত্তি করে এমন একটি ভিউ যোগ করুন যা প্রাথমিকভাবে এই ভিউটির সাবউউ হিসাবে।

ওবজে-সি তে

-(id)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super initWithCoder:aDecoder]) {
        UIView *xibView = [[[NSBundle mainBundle] loadNibNamed:@"YourXIBFilename"
                                                              owner:self
                                                            options:nil] objectAtIndex:0];
        xibView.frame = self.bounds;
        xibView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        [self addSubview: xibView];
    }
    return self;
}

সুইফট 2-এ

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    let xibView = NSBundle.mainBundle().loadNibNamed("YourXIBFilename", owner: self, options: nil)[0] as! UIView
    xibView.frame = self.bounds
    xibView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
    self.addSubview(xibView)
}

সুইফ্ট 3 এ

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    let xibView = Bundle.main.loadNibNamed("YourXIBFilename", owner: self, options: nil)!.first as! UIView
    xibView.frame = self.bounds
    xibView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    self.addSubview(xibView)
}

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


xibView.frame = self.frame;হওয়া উচিত xibView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);, অন্যথায় xibView এর স্টেটবোর্ডে ভিউটি যুক্ত করার পরে একটি অফসেট থাকবে।
বেবিপাণ্ডা

পার্টিতে দেরি হয়ে গেছে তবে মনে হচ্ছে তিনি এটিকে xibView.frame = self.bound এ পরিবর্তন করেছেন যা অফসেট ছাড়াই একটি ফ্রেম
Heavy_Bullet

20
অসীম পুনরাবৃত্তির কারণে ক্রাশের ফলাফল। নিব লোড করা সাবক্লাসের আরেকটি উদাহরণ তৈরি করে।
ডেভিড

2
এক্সবিউ ভিউয়ের ক্লাসটি এই নতুন সাবক্লাসের মতো হওয়া উচিত নয়। Xib যদি মাই ক্লাস হয় তবে আপনি এই নতুন ক্লাসটি মাইক্লাসকন্টেইনার তৈরি করতে পারেন।
ব্যবহারকারী 1021430

উপরের সমাধানটি অসীম পুনরাবৃত্তিতে ক্রাশ হবে।
জেবারোস 35

27

আমি সর্বদা "এটিকে একটি সাবউইউ হিসাবে যুক্ত করুন" সমাধানটি অসন্তুষ্টির সাথে খুঁজে পেয়েছি, এটি দেখতে (1) অটোলেআউট, (2) @IBInspectableএবং (3) আউটলেটগুলির সাথে স্ক্রু হিসাবে রয়েছে । পরিবর্তে, আমি আপনাকে যাদু awakeAfter:, একটি NSObjectপদ্ধতির সাথে পরিচয় করিয়ে দিন ।

awakeAfterআপনাকে কোনও এনআইবি / স্টোরিবোর্ড থেকে সম্পূর্ণ আলাদাভাবে আলাদাভাবে অবজেক্টটি জাগিয়ে তুলতে দেয়। সেই অবজেক্টটি হাইড্রেশন প্রক্রিয়াটির মধ্য দিয়ে রাখা হয়, এটির জন্য awakeFromNibআহ্বান জানানো হয়, ভিউ হিসাবে যোগ করা হয় ইত্যাদি

আমরা এটিকে আমাদের দৃশ্যের একটি "কার্ডবোর্ড কাট-আউট" সাবক্লাসে ব্যবহার করতে পারি, যার একমাত্র উদ্দেশ্য NIB থেকে ভিউ লোড করা এবং স্টোরিবোর্ডে ব্যবহারের জন্য এটি ফিরিয়ে দেওয়া হবে। এম্বেডযোগ্য সাবক্লাসটি তারপরে মূল শ্রেণীর চেয়ে স্টোরিবোর্ড দর্শনের পরিচয় পরিদর্শকটিতে নির্দিষ্ট করা থাকে। এটি কাজ করার জন্য এটি আসলে একটি সাবক্লাস হতে হবে না, তবে এটি একটি সাবক্লাস তৈরি করে যা আইবি কোনও আইবিআইস্পেসটেবল / আইবিআউটলেট বৈশিষ্ট্য দেখতে দেয় see

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

দ্রষ্টব্য: NIB ফাইলে ভিউতে শ্রেণীর সেটটি একই রয়েছে। এম্বেডযোগ্য উপশ্রেণী হয় শুধুমাত্র স্টোরিবোর্ড ব্যবহার করা হয়। সাবক্লাসটি কোডে দর্শনটি ইনস্ট্যান্ট করতে ব্যবহার করা যাবে না, সুতরাং এটির কোনও অতিরিক্ত যুক্তি নিজেই থাকা উচিত নয়। এটিতে কেবলawakeAfter হুক থাকা উচিত ।

class MyCustomEmbeddableView: MyCustomView {
  override func awakeAfter(using aDecoder: NSCoder) -> Any? {
    return (UIView.instantiateViewFromNib("MyCustomView") as MyCustomView?)! as Any
  }
}

Here এখানে একটি উল্লেখযোগ্য ব্যর্থতা হ'ল আপনি যদি স্টোরিবোর্ডে প্রস্থ, উচ্চতা বা দিক অনুপাতের সীমাবদ্ধতাগুলি সংজ্ঞায়িত করেন যা অন্য দৃশ্যের সাথে সম্পর্কিত নয় তবে সেগুলি ম্যানুয়ালি অনুলিপি করতে হবে। দুটি মতামত সম্পর্কিত সীমাবদ্ধতাগুলি নিকটতম সাধারণ পূর্বপুরুষের উপর ইনস্টল করা হয় এবং স্টোরিবোর্ডটি অভ্যন্তরীণ আউট থেকে জাগ্রত হয়, সুতরাং ততক্ষণে তত্ত্বাবধানে এই সীমাবদ্ধতাগুলি হাইড্রেটেড হওয়ার সাথে সাথে অদলবদল ইতিমধ্যে ঘটেছে। যে প্রশ্নগুলিতে কেবলমাত্র প্রশ্নের মধ্যে জড়িত রয়েছে সেগুলি সরাসরি সেই দৃশ্যে ইনস্টল করা হয় এবং সুতরাং অনুলিপিটি অনুলিপি না করা হলে টাস্ক হয়ে যায়।

নোট করুন যে এখানে যা ঘটছে তা হ'ল স্টোরিবোর্ডে দৃশ্যে ইনস্টল হওয়া সীমাবদ্ধতাগুলি নতুন তাত্ক্ষণিক দৃশ্যে অনুলিপি করা হয়েছে , যার ইতিমধ্যে নিজস্ব সীমাবদ্ধতা থাকতে পারে, এটি তার নীব ফাইলটিতে সংজ্ঞায়িত করা হয়েছে। এগুলি ক্ষতিগ্রস্থ হয়।

class MyCustomEmbeddableView: MyCustomView {
  override func awakeAfter(using aDecoder: NSCoder) -> Any? {
    let newView = (UIView.instantiateViewFromNib("MyCustomView") as MyCustomView?)!

    for constraint in constraints {
      if constraint.secondItem != nil {
        newView.addConstraint(NSLayoutConstraint(item: newView, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: newView, attribute: constraint.secondAttribute, multiplier: constraint.multiplier, constant: constraint.constant))
      } else {
        newView.addConstraint(NSLayoutConstraint(item: newView, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: constraint.constant))
      }
    }

    return newView as Any
  }
}  

instantiateViewFromNibএটিতে টাইপ-সেফ এক্সটেনশন UIView। এটি সমস্ত কিছুই NIB এর অবজেক্টগুলির মধ্যে লুপ হয় যতক্ষণ না এটি ধরণের সাথে মিলে যায় finds নোট করুন যে জেনেরিক টাইপটি হ'ল রিটার্ন মান, সুতরাং টাইপটি কল সাইটে নির্দিষ্ট করতে হবে।

extension UIView {
  public class func instantiateViewFromNib<T>(_ nibName: String, inBundle bundle: Bundle = Bundle.main) -> T? {
    if let objects = bundle.loadNibNamed(nibName, owner: nil) {
      for object in objects {
        if let object = object as? T {
          return object
        }
      }
    }

    return nil
  }
}

এটাই মাইন্ডবোগলিং। যদিও আমি ভুল না হয়ে থাকলে এটি কেবল "স্টোরিবোর্ডে" কাজ করে - যদি আপনি রানটাইমে কোডে এমন শ্রেণি তৈরি করার চেষ্টা করেন তবে আমার মনে হয় না এটি কার্যকর হয়। আমি বিশ্বাস করি.
ফ্যাটি

সাবক্লাসটি কোডের পাশাপাশি সমস্ত মূল উদ্দেশ্য এবং উদ্দেশ্যগুলির জন্য মূল শ্রেণীর সাথে কাজ করা উচিত। আপনি যদি কোনও নিব থেকে কোডটি ভিউটি লোড করতে চান তবে আপনি কেবল একই কৌশলটি ব্যবহার করে সরাসরি এটি ইনস্ট্যান্ট করবেন। সমস্ত সাবক্লাসটি হ'ল কোনও নিব থেকে ভিউটি ইনস্ট্যান্ট করতে কোড নেওয়া এবং স্টোরিবোর্ডটি ব্যবহারের জন্য এটি একটি হুকের মধ্যে রেখে দেওয়া।
ক্রিস্টোফার স্বাসে

আসলে আমি ভুল এটা ছিল হবে ঠিক যেমন ভাল কাজ যদি আপনি এটি instantiate পারে, কিন্তু আপনি করতে পারবেন না কারণ নিব দেখুন যাতে তার ধরন হিসেবে সুপারক্লাস থাকবে instantiateViewFromNibকিছু ফেরত করা হবে না। আইএমও কোনওভাবেই বড় কথা নয়, সাবক্লাসটি স্টোরিবোর্ডে প্রবেশের পক্ষে কেবল একটি পক্ষপাতিত্ব, সমস্ত কোডটি মূল শ্রেণিতে হওয়া উচিত।
ক্রিস্টোফার স্বাসে

1
গ্রেট! একটা জিনিস আমাকে ছড়িয়ে দিয়েছে কারণ আমার xibs নিয়ে খুব সামান্য অভিজ্ঞতা আছে (আমি কেবল স্টোরিবোর্ড এবং প্রোগ্রাম্যাটিক পদ্ধতির সাথে কাজ করেছি), এটি কারওর ক্ষেত্রে সহায়তা করে যদি এটি এখানে রেখে যায়: .xib ফাইলে আপনাকে শীর্ষ স্তরের ভিউ নির্বাচন করতে হবে এবং সেট করতে হবে এর ক্লাস টাইপ MyCustomView। আমার এক্সিবায় বাম দিকের অভ্যন্তর-সাইডবারটি ডিফল্টরূপে অনুপস্থিত ছিল; এটি চালু করতে, নীচের / বাম পাশের কাছাকাছি "হিসাবে দেখুন: আইফোন 7" বৈশিষ্ট্যগুলি নিয়ন্ত্রণের পাশে একটি বোতাম রয়েছে।
xaphod

5
এটি যখন অন্য কোনও বস্তুর দ্বারা প্রতিস্থাপিত হয় তখন সীমাবদ্ধতাগুলি ব্রেক করে। :(
ইনভুডু

6

সেরা সমাধানটি এখন কেবলমাত্র একটি এক্সিবায় সংজ্ঞায়িত তার ভিউ সহ একটি কাস্টম ভিউ কন্ট্রোলার ব্যবহার করা এবং স্টোরিবোর্ডের সাথে ভিউ কন্ট্রোলার যুক্ত করার সময় এক্সকোডের দ্বারা তৈরি করা "ভিউ" বৈশিষ্ট্যটি কেবল মুছে ফেলা (নাম নির্ধারণ করতে ভুলবেন না যদিও কাস্টম ক্লাস)।

এটি রানটাইমটি স্বয়ংক্রিয়ভাবে xib সন্ধান করবে এবং এটি লোড করবে। আপনি এই কৌশলটি কোনও ধরণের ধারক দর্শন বা সামগ্রী দেখার জন্য ব্যবহার করতে পারেন।


5

আমি পৃথক স্টোরিবোর্ডেalternative ব্যবহার XIB viewsকরার বিষয়ে চিন্তা করি ।View Controller

তারপর কাস্টম দৃশ্য ব্যবহার স্থানে প্রধান স্টোরিবোর্ড মধ্যে container viewদিয়ে Embed Segueএবং StoryboardReferenceএই কাস্টম ভিউ নিয়ামক যা দৃশ্য প্রধান স্টোরিবোর্ড অন্যান্য দৃশ্য ভিতরে স্থাপন করা উচিত।

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

অতিরিক্ত সুবিধা হ'ল আপনি কাস্টমভিউ কনট্রোলার ক্লাসে আপনার যুক্তি প্রয়োগ করতে পারেন এবং সেখানে আলাদা আলাদা (প্রজেক্টে সন্ধান করা কঠিন) কন্ট্রোলার ক্লাস তৈরি না করে এবং কম্পোনেন্ট ব্যবহার করে মূল ইউআইভিউকন্ট্রোলারে বয়লারপ্লেট কোড না রেখে সমস্ত প্রতিনিধি এবং প্রস্তুতির ব্যবস্থা করতে পারেন। আমি মনে করি প্রাক্তন পুনরায় ব্যবহারযোগ্য উপাদানগুলির জন্য এটি ভাল। সঙ্গীত প্লেয়ার উপাদান (উইজেটের মতো) যা অন্যান্য দর্শনগুলিতে এম্বেডযোগ্য।


প্রকৃতপক্ষে দুঃখজনকভাবে কাস্টম ভিউ xib ব্যবহারের চেয়ে অনেক বেশি সহজ সমাধান :(
উইলসন

1
কাস্টম ইউআইভিউতে অ্যাপলের এক্সিব লাইফসাইकल ক্রিয়েশন চেইনের সাথে চেনাশোনাগুলিতে যাওয়ার পরে এইভাবেই আমি শেষ করে এসেছি।
লাইটনিংস্র্যাটিক

আপনি যদি কাস্টম ভিউটিকে গতিশীলভাবে যুক্ত করতে চান তবে আমাদের আলাদা আলাদা ভিউ কন্ট্রোলারের সাথে যেতে হবে (সর্বাধিক একাদশ)
সত্যম

5

যদিও শীর্ষ সর্বাধিক জনপ্রিয় উত্তরগুলি সূক্ষ্মভাবে কাজ করে, সেগুলি ধারণাগতভাবে ভুল। এগুলি সমস্ত File's ownerশ্রেণীর আউটলেট এবং ইউআই উপাদানগুলির মধ্যে সংযোগ হিসাবে ব্যবহার করে । File's ownerএটি কেবলমাত্র শীর্ষ-স্তরের অবজেক্টের জন্য ব্যবহৃত হবে বলে মনে করা হচ্ছে UIView। পরীক্ষা করে দেখুন অ্যাপল ডেভেলপার ডকুমেন্ট । ইউআইভিউউ File's ownerহওয়া এই অনাকাঙ্ক্ষিত পরিণতির দিকে নিয়ে যায়।

  1. আপনি contentViewযেখানে ব্যবহার করবেন বলে মনে করছেন সেখানে আপনাকে বাধ্য হতে হবে self। এটি কেবল কুৎসিতই নয়, কাঠামোগতভাবেও ভুল কারণ মধ্যবর্তী ভিউ ডেটা স্ট্রাকচারকে এটির UI কাঠামো জানাতে বাধা দেয়। এটি ঘোষণামূলক ইউআই এর বিপরীত মত।
  2. আপনার কাছে প্রতিটি জিবিতে কেবল একটি ইউআইভিউ থাকতে পারে। একটি এক্সিবের একাধিক ইউআইভিউ রয়েছে বলে ধারণা করা হচ্ছে।

এটি ব্যবহার না করে করার দুর্দান্ত উপায় আছে File's owner। এই ব্লগ পোস্ট চেক করুন । এটি সঠিক পদ্ধতিতে কীভাবে করা যায় তা ব্যাখ্যা করে।


এটি কেন খারাপ তা আপনি ব্যাখ্যা করেন নি মোটে কিছু যায় আসে না। আমি দেখতে পাচ্ছি না কেন। কোনও পার্শ্ব প্রতিক্রিয়া নেই।
জেবারোস 35

1

আপনি সমস্ত বরাবর চেয়েছিলেন উত্তর এখানে। আপনি কেবলমাত্র আপনার CustomViewক্লাস তৈরি করতে পারেন , সমস্ত সাবভিউ এবং আউটলেটগুলি সহ একটি এক্সবিতে এটির মাস্টার্স উদাহরণ থাকতে পারেন। তারপরে আপনি আপনার স্টোরিবোর্ডে বা অন্যান্য xibs এর যে কোনও দৃষ্টান্তে সেই শ্রেণিটি প্রয়োগ করতে পারেন।

ফাইলের মালিকের সাথে ঝাঁকুনির দরকার নেই, বা কোনও প্রক্সিতে আউটলেটগুলি সংযুক্ত করতে হবে বা জিজিবিটিকে একটি অদ্ভুত উপায়ে সংশোধন করতে হবে না বা নিজের কাস্টম ভিউয়ের একটি দৃষ্টান্ত নিজের মতো করে সংক্ষিপ্তসার হিসাবে যুক্ত করতে হবে।

শুধু এটি করুন:

  1. BFWControls কাঠামো আমদানি করুন
  2. থেকে আপনার সুপারক্লাস পরিবর্তন UIViewকরতে NibView(বা থেকে UITableViewCellথেকে NibTableViewCell)

এটাই!

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

আপনি এটি সম্পর্কে এখানে আরও পড়তে পারেন: https://medium.com/build-an-app- Like-lego / e એમ્બેડ-a-xib-in-a-storyboard-953edf274155

এবং আপনি ওপেন সোর্স BFWControls ফ্রেমওয়ার্কটি এখানে পেতে পারেন: https://github.com/BareFeetWare/BFWControls

এবং NibReplaceableকোডটি উত্সাহিত করার জন্য এখানে একটি সরল সূত্র রয়েছে , যদি আপনি কৌতূহলী হন তবে:
 https://gist.github.com/barefeettom/f48f6569100415e0ef1fd530ca39f5b4

টম


নিফটির সমাধান, ধন্যবাদ!
এজেভ

আমি যখন কোনও ফ্রেমওয়ার্ক স্থানীয়ভাবে সরবরাহ করা উচিত তখন ইনস্টল করতে চাই না।
জেবারোস 35

0

আপনার ক্লাসে একাদশের মতো একই নাম না থাকলেও এই সমাধানটি ব্যবহার করা যেতে পারে। উদাহরণস্বরূপ, যদি আপনার কাছে একটি বেস ভিউ কন্ট্রোলার শ্রেণি নিয়ামক রয়েছে যার একটি XIB নাম নিয়ামকএ.এসআইবি রয়েছে এবং আপনি এটি কন্ট্রোলার দিয়ে সাবক্লাস করেছেন এবং স্টোরিবোর্ডে কন্ট্রোলার একটি উদাহরণ তৈরি করতে চান তবে আপনি এটি করতে পারেন:

  • স্টোরিবোর্ডে ভিউ কন্ট্রোলার তৈরি করুন
  • কন্ট্রোলারকে ক্লাসটি নিয়ন্ত্রকবিতে সেট করুন
  • স্টোরিবোর্ডে নিয়ন্ত্রণকারী বি এর দৃশ্য মুছুন
  • কন্ট্রোলার এ লোড ভিউ ওভাররাইড করুন:

*

- (void) loadView    
{
        //according to the documentation, if a nibName was passed in initWithNibName or
        //this controller was created from a storyboard (and the controller has a view), then nibname will be set
        //else it will be nil
        if (self.nibName)
        {
            //a nib was specified, respect that
            [super loadView];
        }
        else
        {
            //if no nib name, first try a nib which would have the same name as the class
            //if that fails, force to load from the base class nib
            //this is convenient for including a subclass of this controller
            //in a storyboard
            NSString *className = NSStringFromClass([self class]);
            NSString *pathToNIB = [[NSBundle bundleForClass:[self class]] pathForResource: className ofType:@"nib"];
            UINib *nib ;
            if (pathToNIB)
            {
                nib = [UINib nibWithNibName: className bundle: [NSBundle bundleForClass:[self class]]];
            }
            else
            {
                //force to load from nib so that all subclass will have the correct xib
                //this is convenient for including a subclass
                //in a storyboard
                nib = [UINib nibWithNibName: @"baseControllerXIB" bundle:[NSBundle bundleForClass:[self class]]];
            }

            self.view = [[nib instantiateWithOwner:self options:nil] objectAtIndex:0];
       }
}

0

বেন প্যাচের প্রতিক্রিয়াতে বর্ণিত পদক্ষেপ অনুসারে উদ্দেশ্য-সি এর সমাধান ।

ইউআইভিউয়ের জন্য এক্সটেনশন ব্যবহার করুন:

@implementation UIView (NibLoadable)

- (UIView*)loadFromNib
{
    UIView *xibView = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil] firstObject];
    xibView.translatesAutoresizingMaskIntoConstraints = NO;
    [self addSubview:xibView];
    [xibView.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
    [xibView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
    [xibView.leftAnchor constraintEqualToAnchor:self.leftAnchor].active = YES;
    [xibView.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
    return xibView;
}

@end

ফাইল তৈরি করুন MyView.h, MyView.mএবং MyView.xib

প্রথমে আপনার প্রস্তুতি MyView.xibহিসাবে বেন প্যাচ প্রতিক্রিয়া তাই সেট বর্গ বলেছেন MyViewএই XIB ভিতরে প্রধান দৃশ্য পরিবর্তে ফাইলের মালিকের জন্য।

MyView.h:

#import <UIKit/UIKit.h>

IB_DESIGNABLE @interface MyView : UIView

@property (nonatomic, weak) IBOutlet UIView* someSubview;

@end

MyView.m:

#import "MyView.h"
#import "UIView+NibLoadable.h"

@implementation MyView

#pragma mark - Initializers

- (id)init
{
    self = [super init];
    if (self) {
        [self loadFromNib];
        [self internalInit];
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self loadFromNib];
        [self internalInit];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self loadFromNib];
    }
    return self;
}

- (void)awakeFromNib
{
    [super awakeFromNib];
    [self internalInit];
}

- (void)internalInit
{
    // Custom initialization.
}

@end

এবং পরে কেবল আপনার ভিউটি প্রোগ্রামাগুলি তৈরি করুন:

MyView* view = [[MyView alloc] init];

সতর্কবাণী! আপনি যদি Xcode> = 9.2: https://forums.developer.apple.com/thread/95616 এ এই বাগের কারণে ওয়াচকিট এক্সটেনশন ব্যবহার করেন তবে স্টিরিবোর্ডে এই দর্শনটির পূর্বরূপ দেখানো হবে না htt


সুইফট সংস্করণ সরবরাহ করা উচিত ছিল। খুব কম লোক এই সময়ে এখনও ওজেজেসি ব্যবহার করতে পারে
সত্যম
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.