সুইফট সাবক্লাস ইউআইভিউ


95

আমি সাবক্লাস করতে UIViewএবং ভিউ মত একটি লগইন প্রদর্শন করতে চান । আমি এটি উদ্দেশ্য-সিতে তৈরি করেছি, তবে এখন আমি এটি সুইফটে পোর্ট করতে চাই। আমি স্টোরিবোর্ড ব্যবহার করি না, তাই আমি কোডে আমার সমস্ত ইউআই তৈরি করি।

তবে প্রথম সমস্যাটি হ'ল আমাকে অবশ্যই বাস্তবায়ন করতে হবে initWithCoder। আমি এটি একটি ডিফল্ট বাস্তবায়ন দিয়েছি কারণ এটি বলা হবে না। এখন আমি যখন প্রোগ্রামটি চালাচ্ছি এটি ক্র্যাশ হয়ে যায়, কারণ আমিও বাস্তবায়ন করেছি initWithFrame। এখন আমি এটি পেয়েছি:

override init() {
    super.init()
    println("Default init")
}

override init(frame: CGRect) {
    super.init(frame: frame)
    println("Frame init")
}

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

আমার প্রশ্ন হ'ল আমার পাঠ্যক্ষেত্র ইত্যাদি কোথায় তৈরি করা উচিত ... এবং যদি আমি কখনই ফ্রেম এবং কোডার প্রয়োগ করি না তবে কীভাবে আমি এটি "লুকিয়ে" রাখতে পারি?

উত্তর:


174

আমি সাধারণত এটির মতো কিছু করি, এটি কিছুটা ভার্বোজ।

class MyView: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        addBehavior()
    }

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

    required init(coder aDecoder: NSCoder) {
        fatalError("This class does not support NSCoding")
    }

    func addBehavior() {
        print("Add all the behavior here")
    }
}



let u = MyView(frame: CGRect.zero)
let v = MyView()

(সম্পাদনা করুন: আমি আমার উত্তরটি সম্পাদনা করেছি যাতে আরম্ভকারীদের মধ্যে সম্পর্ক আরও সুস্পষ্ট হয়)


4
তবে ইডবিহাইভারকে দ্বিগুণ বলা হয় যেহেতু ইনফ্রেমকে ডাকা হয় এবং আরআইডি করা হয়। আপনি যদি আমার কোডটি চালান প্রথম ফ্রেম
টিআইআই

6
ভাল জিনিস, ধন্যবাদ। ব্যবহারের পরিবর্তে CGRectZeroআমি বিশ্বাস করি এটি ব্যবহার করার পরামর্শ দেওয়া হচ্ছে CGRect.zeroRect
মিঃ রজার্স

57
এই ইনিশিয়াল স্টারটি জটিল ক্রেজি।
ইয়ান ওয়ারবার্টন

4
অটো লেআউটটির জন্য এটি করার কোনও উপায় আছে কি? ফ্রেম তাই পুরানো।
ডিভিস

8
এটি সম্পূর্ণ উত্তর নয়। ইউআইভিউ, থিওথকোডিং সমর্থন করে। কোনও নিব বা স্টোরিবোর্ড থেকে লোড হওয়া যে কোনও ভিউ initwithCoding পদ্ধতি, এবং ক্র্যাশকে কল করবে।
আইয়েন ডেলানী

17

এটি আরও সহজ।

override init (frame : CGRect) {
    super.init(frame : frame)
    // Do what you want.
}

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

10

কাস্টম ইউআইভিউ সাবক্লাস উদাহরণ

আমি সাধারণত স্টোরিবোর্ড বা নিব ব্যবহার না করে আইওএস অ্যাপস তৈরি করি। আমি আপনার প্রশ্নের উত্তর দিতে শিখেছি এমন কিছু কৌশলগুলি ভাগ করব।

 

অযাচিত initপদ্ধতি লুকানো হচ্ছে

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

class BaseView: UIView {

    // This initializer hides init(frame:) from subclasses
    init() {
        super.init(frame: CGRect.zero)
    }

    // This attribute hides `init(coder:)` from subclasses
    @available(*, unavailable)
    required init?(coder aDecoder: NSCoder) {
        fatalError("NSCoding not supported")
    }
}

আপনার কাস্টম ইউআইভিউ সাবক্লাসটি উত্তরাধিকার সূত্রে প্রাপ্ত হওয়া উচিত BaseView। এটি অবশ্যই তার ইনিশিয়ালাইজারে সুপার.init () কল করবে call এটি বাস্তবায়নের দরকার নেই init(coder:)। এটি নীচের উদাহরণে প্রদর্শিত হয়।

 

একটি ইউআইটিেক্সটফিল্ড যুক্ত করা হচ্ছে

আমি initপদ্ধতির বাইরে রেফারেন্স করা সাবভিউগুলির জন্য সঞ্চিত বৈশিষ্ট্য তৈরি করি । আমি সাধারণত একটি ইউআইটিেক্সটফিল্ডের জন্য এটি করব। আমি ভালো subview সম্পত্তি ঘোষণা মধ্যে instantiate subviews পছন্দ: let textField = UITextField()

আপনি কল করে কাস্টম ভিউ'র সাবভিউ তালিকায় যুক্ত না করলেই ইউআইটিেক্সটফিল্ডটি দৃশ্যমান হবে না addSubview(_:)। এটি নীচের উদাহরণে প্রদর্শিত হয়।

 

অটো লেআউট ছাড়াই প্রোগ্রাম্যাটিক লেআউট

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

রেফারেন্সের জন্য কাস্টমভিউয়ের মাত্রাগুলি পেতে আপনি frame.heightএবং এর frame.widthমধ্যে উল্লেখ করতে পারেন layoutSubviews()। এটি নীচের উদাহরণে প্রদর্শিত হয়।

 

উদাহরণস্বরূপ ইউআইভিউ সাবক্লাস

একটি কাস্টম ইউআইভিউ সাবক্লাসে একটি ইউআইটিেক্সটফিল্ড রয়েছে যা বাস্তবায়নের প্রয়োজন হয় না init?(coder:)

class CustomView: BaseView {

    let textField = UITextField()

    override init() {
        super.init()

        // configure and add textField as subview
        textField.placeholder = "placeholder text"
        textField.font = UIFont.systemFont(ofSize: 12)
        addSubview(textField)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        // Set textField size and position
        textField.frame.size = CGSize(width: frame.width - 20, height: 30)
        textField.frame.origin = CGPoint(x: 10, y: 10)
    }
}

 

অটো লেআউট সহ প্রোগ্রামেটিক লেআউট

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

 

প্রোগ্রামেটিক লেআউট ফ্রেমওয়ার্ক

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

 

কেন করা fatalErrorমধ্যেinit(coder:)

ইউআইভিউউ সাবক্ল্যাসগুলি তৈরি করার সময় যা স্টোরিবোর্ড বা নিব কখনই ব্যবহৃত হবে না, আপনি হয়ত বিভিন্ন পরামিতি এবং প্রারম্ভিককরণের প্রয়োজনীয়তাগুলির সাথে প্রবর্তনকারীদের পরিচয় করিয়ে দিতে পারেন যা init(coder:)পদ্ধতি দ্বারা কল করা যায় না । আপনি যদি থ্রিজি (কোডার :) এর সাথে ব্যর্থ না হন fatalError, দুর্ঘটনাক্রমে স্টোরিবোর্ড / নিব ব্যবহার করা গেলে এটি লাইনে খুব বিভ্রান্তিকর সমস্যা দেখা দিতে পারে। মারাত্মক ইরর এই উদ্দেশ্যগুলি জোর করে।

required init?(coder aDecoder: NSCoder) {
    fatalError("NSCoding not supported")
}

সাবক্লাসটি কোড বা স্টোরিবোর্ড / নিব তৈরি না করেই যদি আপনি কিছু কোড চালনা করতে চান তবে নীচের মতো আপনি কিছু করতে পারেন ( জেফ গু কাংয়ের উত্তরের ভিত্তিতে )

class CustomView: UIView {
    override init (frame: CGRect) {
        super.init(frame: frame)
        initCommon()
    }

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

    func initCommon() {
        // Your custom initialization code
    }
}

এবং? যোগ করে fatalErrorআপনি xib ফাইলগুলির সাথে এই দৃশ্য init করতে আল্লাহ তোমাদেরকে নিষেধ
Vyachaslav Gerchicov

@ ভাইচাস্লাভ জের্চিকভ, আমার উত্তরটি ধরে নেওয়া হয়েছে যে আপনি এক্সিবস বা স্টোরিবোর্ডকে গ্রহণযোগ্য উত্তর এবং প্রশ্নের মতো ব্যবহার করছেন না। প্রশ্নটি নোট করে "আমি স্টোরিবোর্ড ব্যবহার করি না, তাই কোডে আমার সমস্ত ইউআই তৈরি করি"।
মোবাইল ড্যান

পরের বার আপনি fatalErrorডেলোক পদ্ধতিতে লিখবেন এবং আমাদের জানান যে এটি কার্যকর হয় না কারণ সেই শ্রেণিটি একটি সিঙ্গলটন হওয়া উচিত। আপনি যদি কোডটিতে ইউআই উপাদান তৈরি করতে পছন্দ করেন তবে আপনার অন্য সমস্ত উপায়ে ম্যানুয়ালি নিষেধ করা উচিত নয়। অবশেষে প্রশ্নটি হল কীভাবে "স্টোরিবোর্ডগুলি ছাড়াই প্রোগ্রামিয়ালি তৈরি করা যায়" তবে xibs / nibs উল্লেখ করা হয়নি। আমার ক্ষেত্রে আমাকে প্রোগ্রামেমেটিকালি + xib দিয়ে কোষগুলির একটি অ্যারে তৈরি করতে হবে DropDownMenuKitএবং সেগুলিতে প্রবেশ করতে হবে এবং এইভাবে কাজ করবে না কারণ এই লাইব্রেরির লেখক xibsও নিষিদ্ধ করে।
ব্যয়াচস্লাভ গেরিকোভ

@ ভাইচাস্লাভ জের্চিকোভ মনে হচ্ছে জেফ গু কাংয়ের উত্তর যা আপনি খুঁজছেন যেহেতু এটি স্টোরিবোর্ডগুলি / জিবগুলি উপযুক্ত করে
মোবাইল ড্যান

4
@ ভাইচাস্লাভ জের্চিকভ প্রশ্নটিতে আরও বলা হয়েছে "এবং আমি যদি ফ্রেম এবং কোডার কখনই প্রয়োগ করি না তবে কীভাবে আমি এটি" লুকিয়ে "রাখতে পারি?" ইউআইভিউ সাবক্ল্যাস তৈরি করার সময় যা কখনই কোনও সিবিবি / স্টোরিবোর্ডে ব্যবহার করা হবে না, আপনি বিভিন্ন পরামিতিগুলির সাথে ইনিশিয়ালাইজারগুলি পরিচয় করিয়ে দিতে পারেন যা init (কোডার :) পদ্ধতি দ্বারা কল করা যায় না। যদি আপনি মারাত্মক ইরর দিয়ে ইনড (কোডার :) ব্যর্থ না হন তবে কোনও এক্স / স্টোরিবোর্ডে যদি দুর্ঘটনাক্রমে ব্যবহার করা হয় তবে এটি লাইনে খুব বিভ্রান্তিকর সমস্যা দেখা দিতে পারে। মারাত্মক ইরর এই উদ্দেশ্যগুলি জানিয়েছে। এটি একটি উদ্দেশ্যমূলক এবং সাধারণ অনুশীলন হিসাবে গ্রহণযোগ্য উত্তরে দেখা গেছে।
মোবাইল ড্যান

4

আপনার ইউআইভিউ ইন্টারফেস বিল্ডার / স্টোরিবোর্ড বা কোড থেকে তৈরি করা যেতে পারে তা গুরুত্বপূর্ণ। যে setupকোনও সেটআপ কোডটির সদৃশতা হ্রাস করতে কোনও পদ্ধতি থাকা আমার পক্ষে দরকারী । যেমন

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

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

    func setup () {
        backgroundColor = .red
    }
}

4

সুইফট ৪.০, আপনি যদি xib ফাইল থেকে ভিউটি ব্যবহার করতে চান তবে এটি আপনার জন্য। আমি ইউআইভিউর কাস্টমক্যালআউটভিউ ক্লাসের সাব ক্লাস তৈরি করেছি। আমি একটি xib ফাইল তৈরি করেছি এবং আইবিতে কেবল ফাইলের মালিক নির্বাচন করুন তারপরে কাস্টমক্যালআউটভিউতে অ্যাট্রিবিউট ইন্সপেক্টর সেট শ্রেণীর নাম নির্বাচন করুন, তারপরে আপনার শ্রেণিতে আউটলেট তৈরি করুন।

    import UIKit
    class CustomCalloutView: UIView {

        @IBOutlet var viewCallout: UIView! // This is main view

        @IBOutlet weak var btnCall: UIButton! // subview of viewCallout
        @IBOutlet weak var btnDirection: UIButton! // subview of viewCallout
        @IBOutlet weak var btnFavourite: UIButton! // subview of viewCallout 

       // let nibName = "CustomCalloutView" this is name of xib file

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

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

        func nibSetup() {
            Bundle.main.loadNibNamed(String(describing: CustomCalloutView.self), owner: self, options: nil)
            guard let contentView = viewCallout else { return } // adding main view 
            contentView.frame = self.bounds //Comment this line it take default frame of nib view
           // custom your view properties here
            self.addSubview(contentView)
        }
    }

// এখন এটি যুক্ত করুন

    let viewCustom = CustomCalloutView.init(frame: CGRect.init(x: 120, y: 120, 50, height: 50))
    self.view.addSubview(viewCustom)

-1

আমি সাধারণত আমার সাবক্ল্যাসগুলি কীভাবে তৈরি করি তার একটি উদাহরণ এখানে রয়েছে (ইউআইভিউ)। আমার কাছে ভেরিয়েবল হিসাবে সামগ্রী রয়েছে যাতে সেগুলি অ্যাক্সেস করতে পারে এবং পরে সম্ভবত অন্য কোনও শ্রেণিতে টুইট করা যায়। আমি কীভাবে স্বয়ংক্রিয় বিন্যাস এবং সামগ্রী যুক্ত করব তাও দেখিয়েছি।

উদাহরণস্বরূপ, একটি ভিউকন্ট্রোলারের ক্ষেত্রে আমার এই ভিউটি ভিডিডলিডে শুরু করা হয় () যেহেতু দৃশ্যটি দৃশ্যমান হয় কেবল তখনই এটি ডাকা হয়। তারপরে আমি এখানে তৈরি করা এই ফাংশনগুলি ব্যবহার করি addContentToView()এবং তারপরে activateConstraints()সামগ্রী এবং সীমাবদ্ধতাগুলি তৈরি করতে। আমি যদি পরে কোনও ভিউকন্ট্রোলারটিতে একটি বাটনটি লাল হতে বলার রঙ চাই তবে আমি কেবল সেই ভিউকন্ট্রোলারের সেই নির্দিষ্ট ফাংশনে এটি করি। কিছুটা এইরকম:func tweaksome(){ self.customView.someButton.color = UIColor.red}

class SomeView: UIView {


var leading: NSLayoutConstraint!
var trailing: NSLayoutConstraint!
var bottom: NSLayoutConstraint!
var height: NSLayoutConstraint!


var someButton: UIButton = {
    var btn: UIButton = UIButton(type: UIButtonType.system)
    btn.setImage(UIImage(named: "someImage"), for: .normal)
    btn.translatesAutoresizingMaskIntoConstraints = false
    return btn
}()

var btnLeading: NSLayoutConstraint!
var btnBottom: NSLayoutConstraint!
var btnTop: NSLayoutConstraint!
var btnWidth: NSLayoutConstraint!

var textfield: UITextField = {
    var tf: UITextField = UITextField()
    tf.adjustsFontSizeToFitWidth = true
    tf.placeholder = "Cool placeholder"
    tf.translatesAutoresizingMaskIntoConstraints = false
    tf.backgroundColor = UIColor.white
    tf.textColor = UIColor.black
    return tf
}()
var txtfieldLeading: NSLayoutConstraint!
var txtfieldTrailing: NSLayoutConstraint!
var txtfieldCenterY: NSLayoutConstraint!

override init(frame: CGRect){
    super.init(frame: frame)
    self.translatesAutoresizingMaskIntoConstraints = false
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    //fatalError("init(coder:) has not been implemented")
}



/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
    // Drawing code

}
*/
func activateConstraints(){
    NSLayoutConstraint.activate([self.btnLeading, self.btnBottom, self.btnTop, self.btnWidth])
    NSLayoutConstraint.activate([self.txtfieldCenterY, self.txtfieldLeading, self.txtfieldTrailing])
}

func addContentToView(){
    //setting the sizes
    self.addSubview(self.userLocationBtn)

    self.btnLeading = NSLayoutConstraint(
        item: someButton,
        attribute: .leading,
        relatedBy: .equal,
        toItem: self,
        attribute: .leading,
        multiplier: 1.0,
        constant: 5.0)
    self.btnBottom = NSLayoutConstraint(
        item: someButton,
        attribute: .bottom,
        relatedBy: .equal,
        toItem: self,
        attribute: .bottom,
        multiplier: 1.0,
        constant: 0.0)
    self.btnTop = NSLayoutConstraint(
        item: someButton,
        attribute: .top,
        relatedBy: .equal,
        toItem: self,
        attribute: .top,
        multiplier: 1.0,
        constant: 0.0)
    self.btnWidth = NSLayoutConstraint(
        item: someButton,
        attribute: .width,
        relatedBy: .equal,
        toItem: self,
        attribute: .height,
        multiplier: 1.0,
        constant: 0.0)        


    self.addSubview(self.textfield)
    self.txtfieldLeading = NSLayoutConstraint(
        item: self.textfield,
        attribute: .leading,
        relatedBy: .equal,
        toItem: someButton,
        attribute: .trailing,
        multiplier: 1.0,
        constant: 5)
    self.txtfieldTrailing = NSLayoutConstraint(
        item: self.textfield,
        attribute: .trailing,
        relatedBy: .equal,
        toItem: self.doneButton,
        attribute: .leading,
        multiplier: 1.0,
        constant: -5)
    self.txtfieldCenterY = NSLayoutConstraint(
        item: self.textfield,
        attribute: .centerY,
        relatedBy: .equal,
        toItem: self,
        attribute: .centerY,
        multiplier: 1.0,
        constant: 0.0)
}
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.