Solusi Asli
- Saya membuat XIB dan kelas bernama SomeView (menggunakan nama yang sama untuk kenyamanan dan keterbacaan). Saya mendasarkan keduanya pada UIView.
- Di XIB, saya mengubah kelas "File's Owner" ke SomeView (di inspektur identitas).
- Saya membuat outlet UIView di SomeView.swift, menautkannya ke tampilan tingkat atas dalam file XIB (menamakannya "tampilan" untuk kenyamanan). Saya kemudian menambahkan outlet lain ke kontrol lain di file XIB sesuai kebutuhan.
- di SomeView.swift, saya memuat XIB di dalam inisialisasi "init with code". Tidak perlu menetapkan apa pun untuk "diri". Segera setelah XIB dimuat, semua outlet terhubung, termasuk tampilan tingkat atas. Satu-satunya hal yang hilang, adalah menambahkan tampilan atas ke hierarki tampilan:
.
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
}
...
}
Perhatikan bahwa dengan cara ini saya mendapatkan kelas yang memuat dirinya sendiri dari nib. Saya kemudian dapat menggunakan SomeView sebagai kelas setiap kali UIView dapat digunakan dalam proyek (dalam pembangun antarmuka atau secara terprogram).
Perbarui - menggunakan sintaks Swift 3
Memuat xib dalam ekstensi berikut ini ditulis sebagai metode instance, yang kemudian dapat digunakan oleh penginisialisasi seperti yang di atas:
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
}
}
- Menggunakan nilai balik yang dapat dibuang karena tampilan yang dikembalikan sebagian besar tidak menarik bagi penelepon ketika semua outlet sudah terhubung.
- Ini adalah metode umum yang mengembalikan objek opsional tipe UIView. Jika gagal memuat tampilan, mengembalikan nihil.
- Mencoba memuat file XIB dengan nama yang sama dengan instance kelas saat ini. Jika gagal, nol dikembalikan.
- Menambahkan tampilan tingkat atas ke hierarki tampilan.
- Baris ini menganggap kami menggunakan batasan untuk menata tampilan.
- Metode ini menambahkan kendala atas, bawah, depan & belakang - melampirkan tampilan ke "diri" di semua sisi (Lihat: https://stackoverflow.com/a/46279424/2274829 untuk detail)
- Mengembalikan tampilan tingkat atas
Dan metode penelepon mungkin terlihat seperti ini:
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 ...
}
- SomeClass adalah subkelas UIView yang memuat kontennya dari file SomeClass.xib. Kata kunci "final" adalah opsional.
- Inisialisasi untuk ketika tampilan digunakan dalam storyboard (ingat untuk menggunakan SomeClass sebagai kelas kustom dari tampilan storyboard Anda).
- Penginisialisasi ketika tampilan dibuat secara terprogram (yaitu: "let myView = SomeView ()").
- Menggunakan bingkai all-nol sejak tampilan ini ditata menggunakan tata-letak otomatis. Perhatikan bahwa metode "init (frame: CGRect) {..}" tidak dibuat secara independen, karena tata letak otomatis digunakan secara eksklusif dalam proyek kami.
- & 6. Memuat file xib menggunakan ekstensi.
Kredit: Menggunakan ekstensi generik dalam solusi ini terinspirasi oleh jawaban Robert di bawah ini.
Edit
Mengubah "view" menjadi "contentView" untuk menghindari kebingungan. Juga mengubah subscript array menjadi ".first".
File's Owner
mencapai sasaran ... Terima kasih!fromNib()
dari dalaminit(coder aDecoder: NSCoder)
menciptakan loop tak terbatas saat memuat Nib di dalamfromNib()
metode membuat panggilan ke:init(coder aDecoder: NSCoder)
Kontribusi saya:
Kemudian panggil seperti ini:
..atau bahkan:
sumber
Sekarang dapat kembali
-> Self
dengan cepat membantu menyederhanakan ini sedikit. Terakhir dikonfirmasi pada Swift 5.Jika
.xib
file dan subclass Anda memiliki nama yang sama, Anda dapat menggunakan:Jika Anda memiliki nama khusus, gunakan:
CATATAN:
Jika Anda mendapatkan kesalahan "tampilan jenis YourType tidak ditemukan .." maka Anda belum menetapkan kelas tampilan di
.xib
filePilih tampilan Anda di
.xib
file, dan tekancmd + opt + 4
dan diclass
input, masukkan kelas Andasumber
let myCustomView = UIView.fromNib() as? CustomView
. Dalam hal ini,T.self
putuskan keUIView
alih-alihCustomView
dan gagal menemukan nib. Saya tidak yakin mengapa ini - mungkin tipe yang disimpulkan untuklet
fungsi yang disebut sebagaiUIView
?coba kode berikut.
Edit:
sumber
Ekstensi Protokol 4 Swift
Adopsi
Implementasi ini mengasumsikan bahwa Nib memiliki nama yang sama dengan kelas UIView. Ex. MyView.xib. Anda dapat memodifikasi perilaku ini dengan menerapkan nibName () di MyView untuk mengembalikan nama yang berbeda dari implementasi ekstensi protokol default.
Di xib pemilik file adalah MyView dan kelas tampilan root adalah MyView.
Pemakaian
sumber
Saya mencapai ini dengan Swift dengan kode berikut:
Jangan lupa menghubungkan outlet tampilan XIB Anda untuk melihatnya gerai didefinisikan dalam cepat. Anda juga dapat mengatur Responder Pertama ke nama kelas khusus Anda untuk mulai menghubungkan outlet tambahan apa pun.
Semoga ini membantu!
sumber
Diuji dalam Xcode 7 beta 4, Swift 2.0 dan iOS9 SDK. Kode berikut akan menetapkan xib ke uiview. Anda bisa dapat menggunakan tampilan xib khusus ini di storyboard dan mengakses objek IBOutlet juga.
Akses customview secara programatik
Kode sumber - https://github.com/karthikprabhuA/CustomXIBSwift
sumber
Jika Anda memiliki banyak tampilan khusus dalam proyek Anda, Anda dapat membuat kelas seperti
UIViewFromNib
Cepat 2.3
Cepat 3
Dan di setiap kelas yang diwarisi dari
UIViewFromNib
, Anda juga dapat menggantinibName
properti jika.xib
file memiliki nama yang berbeda:sumber
Membangun solusi di atas.
Ini akan bekerja di semua bundel proyek dan tidak perlu obat generik saat memanggil fromNib ().
Cepat 2
Cepat 3
Dapat digunakan seperti ini:
Atau seperti ini:
sumber
Cepat 4
Jangan lupa untuk menulis ".first as? CustomView".
Jika Anda ingin menggunakan di mana saja
Solusi Terbaik adalah jawaban Robert Gummesson .
Kemudian panggil seperti ini:
sumber
sumber
self
secara implisit dikembalikan dari semuainit
metode ...Cara yang baik untuk melakukan ini dengan Swift adalah dengan menggunakan enum.
Kemudian dalam kode Anda, Anda dapat menggunakan:
sumber
Saya lebih suka solusi ini (berdasarkan jawaban jika @ GK100):
Di SomeView.swift, saya memuat XIB di dalam
init
atauinit:frame: CGRect
inisialisasi. Tidak perlu menetapkan apa pun untuk "diri". Segera setelah XIB dimuat, semua outlet terhubung, termasuk tampilan tingkat atas. Satu-satunya hal yang hilang, adalah menambahkan tampilan atas ke hierarki tampilan:sumber
Jawaban Logan 3 versi cepat
sumber
Berikut ini adalah cara yang bersih dan deklaratif untuk memuat secara terprogram tampilan menggunakan protokol dan ekstensi protokol (Swift 4.2):
Dan Anda dapat menggunakan ini seperti ini:
Beberapa pertimbangan tambahan :
Custom Class
set tampilan (dan outlet / tindakan ditetapkan dari sana), bukan milik Pemilik File.sumber
Saya hanya melakukan ini:
Sampel ini menggunakan tampilan pertama di nib "MyView.xib" di bundel utama. Tetapi Anda dapat memvariasikan indeks, nama pena, atau bundel (utama secara default).
Saya dulu membangunkan pandangan ke metode view init atau membuat metode generik seperti pada solusi di atas (yang cerdas dengan cara), tapi saya tidak melakukannya lagi.
Dengan cara ini saya bisa menggunakan tata letak atau sifat yang berbeda sambil menjaga logika dan kode tampilan yang sama.
Saya menemukan lebih mudah untuk membiarkan objek pabrik (biasanya viewController yang akan menggunakan tampilan) membuatnya sesuai kebutuhan. Terkadang Anda membutuhkan pemilik (Biasanya ketika tampilan yang dibuat terhubung ke pembuat), terkadang tidak ..
Mungkin itulah sebabnya Apple tidak memasukkan
initFromNib
metode di kelas UIView-nya ...Untuk mengambil contoh tingkat dasar, Anda tidak tahu bagaimana Anda dilahirkan. Anda baru saja dilahirkan. Begitu juga pandangannya;)
sumber
Yang harus Anda lakukan adalah memanggil metode init di komputer Anda
UIView
kelas .Lakukan seperti itu:
Sekarang, jika Anda ingin menambahkan tampilan ini sebagai sub tampilan dalam view controller, lakukan seperti itu dalam file view controller.swift:
sumber
Mirip dengan beberapa jawaban di atas tetapi ekstensi Swift3 UIView yang lebih konsisten:
Yang memberikan kenyamanan untuk dapat memuat kelas dari nib bernama sendiri tetapi juga dari nibs / bundel lainnya.
sumber
Anda dapat melakukan ini melalui storyboard, cukup tambahkan batasan yang layak untuk dilihat. Anda dapat melakukan ini dengan mudah dengan mensubklasifikasikan setiap tampilan dari milik Anda sendiri katakanlah
BaseView
:Objektif-C
Cepat 4
Saya menyediakan 2 varian cara menambahkan kendala - yang umum dan dalam bahasa format visual - pilih yang Anda inginkan :)
Juga, secara default diasumsikan
xib
nama itu memiliki nama yang sama dengan nama kelas implementasi. Jika tidak - ubah sajaxibName
parameter.Jika Anda mensubklasifikasikan tampilan dari
BaseView
- Anda dapat dengan mudah menempatkan tampilan apa pun dan menentukan kelas dalam IB.sumber
sumber
Versi yang lebih kuat berdasarkan jawaban Logan
Dan Anda bisa menggunakan like
sumber
Implementasi yang paling nyaman. Di sini Anda memerlukan dua metode, untuk kembali langsung ke objek kelas Anda, bukan UIView.
Contoh:
sumber
Jika Anda ingin subkelas Swift UIView sepenuhnya mandiri, dan memiliki kemampuan untuk dipakai menggunakan init atau init (frame :) tanpa memaparkan detail implementasi menggunakan Nib, maka Anda dapat menggunakan ekstensi protokol untuk mencapai ini. Solusi ini menghindari hierarki UIView yang bersarang seperti yang disarankan oleh banyak solusi lainnya.
sumber
sumber
Saya lebih suka ekstensi di bawah ini
Perbedaan antara ini dan ekstensi jawab teratas adalah Anda tidak perlu menyimpannya sebagai konstanta atau variabel.
sumber
sumber