UITableViewCell kustom dari nib di Swift

143

Saya mencoba membuat sel tampilan tabel kustom dari ujung pena. Saya mengacu pada artikel ini di sini . Saya menghadapi dua masalah.

Saya membuat file .xib dengan objek UITableViewCell yang diseret ke sana. Saya membuat subkelas UITableViewCelldan menetapkannya sebagai kelas sel dan Sel sebagai pengenal yang dapat digunakan kembali.

import UIKit

class CustomOneCell: UITableViewCell {

    @IBOutlet weak var middleLabel: UILabel!
    @IBOutlet weak var leftLabel: UILabel!
    @IBOutlet weak var rightLabel: UILabel!

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

    override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

Di UITableViewController saya memiliki kode ini,

import UIKit

class ViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {

    var items = ["Item 1", "Item2", "Item3", "Item4"]

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // MARK: - UITableViewDataSource
    override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
        let identifier = "Cell"
        var cell: CustomOneCell! = tableView.dequeueReusableCellWithIdentifier(identifier) as? CustomOneCell
        if cell == nil {
            tableView.registerNib(UINib(nibName: "CustomCellOne", bundle: nil), forCellReuseIdentifier: identifier)
            cell = tableView.dequeueReusableCellWithIdentifier(identifier) as? CustomOneCell
        }

        return cell
    }
}

Kode ini sesuai dengan tanpa kesalahan tetapi ketika saya menjalankannya di simulator, terlihat seperti ini.

masukkan deskripsi gambar di sini

Di UITableViewController di storyboard, saya belum melakukan apa pun pada sel. Pengenal kosong dan tidak ada subclass. Saya mencoba menambahkan pengenal Sel ke sel prototipe dan menjalankannya lagi tetapi saya mendapatkan hasil yang sama.

Kesalahan lain yang saya hadapi adalah, ketika saya mencoba menerapkan metode berikut di UITableViewController.

override func tableView(tableView: UITableView!, willDisplayCell cell: CustomOneCell!, forRowAtIndexPath indexPath: NSIndexPath!) {

    cell.middleLabel.text = items[indexPath.row]
    cell.leftLabel.text = items[indexPath.row]
    cell.rightLabel.text = items[indexPath.row]
}

Seperti ditunjukkan dalam artikel saya sebutkan saya mengubah cellbentuk jenis parameter ini UITableViewCelluntuk CustomOneCellyang subclass saya UITableViewCell. Tapi saya mendapatkan kesalahan berikut,

Mengganti metode dengan selector 'tableView: willDisplayCell: forRowAtIndexPath:' memiliki tipe yang tidak kompatibel '(UITableView !, CustomOneCell !, NSIndexPath!) -> ()'

Adakah yang tahu cara mengatasi kesalahan ini? Ini sepertinya berfungsi dengan baik di Objective-C.

Terima kasih.

EDIT: Saya baru menyadari jika saya mengubah orientasi simulator ke lanskap dan mengubahnya kembali ke potret, sel-selnya akan muncul! Saya masih tidak tahu apa yang sedang terjadi. Saya mengunggah proyek Xcode di sini yang mendemonstrasikan masalahnya jika Anda punya waktu untuk melihat sekilas.

Isuru
sumber

Jawaban:

217

Dengan Swift 5 dan iOS 12.2, Anda harus mencoba kode berikut untuk menyelesaikan masalah Anda:

CustomCell.swift

import UIKit

class CustomCell: UITableViewCell {

    // Link those IBOutlets with the UILabels in your .XIB file
    @IBOutlet weak var middleLabel: UILabel!
    @IBOutlet weak var leftLabel: UILabel!
    @IBOutlet weak var rightLabel: UILabel!

}

TableViewController.swift

import UIKit

class TableViewController: UITableViewController {

    let items = ["Item 1", "Item2", "Item3", "Item4"]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
    }

    // MARK: - UITableViewDataSource

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell

        cell.middleLabel.text = items[indexPath.row]
        cell.leftLabel.text = items[indexPath.row]
        cell.rightLabel.text = items[indexPath.row]

        return cell
    }

}

Gambar di bawah ini menunjukkan sekumpulan batasan yang bekerja dengan kode yang diberikan tanpa batasan pesan ambiguitas dari Xcode:

masukkan deskripsi gambar di sini

Imanou Petit
sumber
2
Terima kasih atas tanggapannya. Tapi itu juga tidak berhasil. Apakah saya perlu mengubah sesuatu di pengontrol tampilan tabel? Karena ini masih disetel ke sel prototipe.
Isuru
1
Tetap gunakan sel prototipe. Namun pastikan Anda telah menyetel batasan tata letak Otomatis yang baik (jika Anda menggunakan tata letak Otomatis).
Imanou Petit
1
Saya mengunggah proyek uji di sini yang menunjukkan masalah yang saya alami. Bisakah Anda melihatnya jika Anda punya waktu?
Isuru
1
Proyek pengujian Anda mengonfirmasinya: Saya dapat membuat aplikasi Anda berfungsi dengan baik setelah saya menyetel beberapa batasan tata letak otomatis ke sel khusus Anda di file .xib. Lihat video ini jika Anda ingin tahu lebih banyak tentang tata letak Otomatis.
Imanou Petit
2
@KirKudaev tidak diganti namanya di Swift 4 tetapi di Swift 3: Saya telah memperbaiki hasil edit Anda.
Cœur
30

Inilah pendekatan saya menggunakan Swift 2 dan Xcode 7.3. Contoh ini akan menggunakan satu ViewController untuk memuat dua file .xib - satu untuk UITableView dan satu lagi untuk UITableCellView.

masukkan deskripsi gambar di sini

Untuk contoh ini, Anda dapat meletakkan UITableView langsung ke dalam file TableNib .xib kosong . Di dalam, setel pemilik file ke kelas ViewController Anda dan gunakan outlet untuk mereferensikan tableView.

masukkan deskripsi gambar di sini

dan

masukkan deskripsi gambar di sini

Sekarang, di pengontrol tampilan, Anda bisa mendelegasikan tableView seperti biasa, seperti biasa

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!

    ...

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // Table view delegate
        self.tableView.delegate = self
        self.tableView.dataSource = self

        ...

Untuk membuat sel Kustom Anda, sekali lagi, jatuhkan objek Sel Tampilan Tabel ke dalam file TableCellNib .xib kosong . Kali ini, dalam file .xib sel Anda tidak perlu menentukan "pemilik" tetapi Anda perlu menentukan Kelas Kustom dan pengenal seperti "TableCellId"

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Buat subclass Anda dengan outlet apa pun yang Anda butuhkan

class TableCell: UITableViewCell {

    @IBOutlet weak var nameLabel: UILabel!

}

Akhirnya ... kembali ke View Controller Anda, Anda dapat memuat dan menampilkan semuanya seperti itu

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    // First load table nib
    let bundle = NSBundle(forClass: self.dynamicType)
    let tableNib = UINib(nibName: "TableNib", bundle: bundle)
    let tableNibView = tableNib.instantiateWithOwner(self, options: nil)[0] as! UIView

    // Then delegate the TableView
    self.tableView.delegate = self
    self.tableView.dataSource = self

    // Set resizable table bounds
    self.tableView.frame = self.view.bounds
    self.tableView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]

    // Register table cell class from nib
    let cellNib = UINib(nibName: "TableCellNib", bundle: bundle)
    self.tableView.registerNib(cellNib, forCellReuseIdentifier: self.tableCellId)

    // Display table with custom cells
    self.view.addSubview(tableNibView)

}

Kode tersebut menunjukkan bagaimana Anda dapat dengan mudah memuat dan menampilkan file ujung pena (tabel), dan cara kedua mendaftarkan ujung pena untuk penggunaan sel.

Semoga ini membantu!!!

internet-nico
sumber
2
dapatkah Anda menjelaskan apa itu "tableCellId" di baris ini .... self.tableView.registerNib (cellNib, forCellReuseIdentifier: self.tableCellId) .... karena Anda belum mendefinisikan apa itu. dan Anda tidak dapat secara manual menentukan pengenal di xib .. tidak ada pilihan untuk menentukannya
PRADIP KUMAR
1
Dalam pembuat antarmuka, saat Anda membuat tableCell, Dalam "inspektur atribut" Anda menentukan pengenal. Pengenal yang sama adalah apa yang Anda gunakan di pengontrol Anda untuk mereferensikan objek. let tableCellId = "myAwesomeCell". Saya menambahkan gambar lain untuk membantu Anda.
internet-nico
16

Cepat 4

Daftarkan Nib

override func viewDidLoad() {
    super.viewDidLoad()
    tblMissions.register(UINib(nibName: "MissionCell", bundle: nil), forCellReuseIdentifier: "MissionCell")
}

Di TableView DataSource

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          guard let cell = tableView.dequeueReusableCell(withIdentifier: "MissionCell", for: indexPath) as? MissionCell else { return UITableViewCell() }
          return cell
    }
Gurjinder Singh
sumber
11

Solusi Terperinci dengan Screenshot

  1. Buat file antarmuka pengguna kosong dan beri nama MyCustomCell.xib.

masukkan deskripsi gambar di sini

  1. Tambahkan a UITableViewCellsebagai root file xib Anda dan komponen visual lainnya yang Anda inginkan.

masukkan deskripsi gambar di sini

  1. Buat file kelas cocoa touch dengan nama kelas MyCustomCellsebagai subkelas UITableViewCell.

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

  1. Setel kelas kustom dan gunakan kembali pengenal untuk sel tampilan tabel kustom Anda.

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

  1. Buka asisten editor dan ctrl+dragmembuat saluran untuk komponen visual Anda.

masukkan deskripsi gambar di sini

  1. Konfigurasi a UIViewControlleruntuk menggunakan sel khusus Anda.
class MyViewController: UIViewController {

    @IBOutlet weak var myTable: UITableView!

    override func viewDidLoad {
        super.viewDidLoad()

        let nib = UINib(nibName: "MyCustomCell", bundle: nil)
        myTable.register(nib, forCellReuseIdentifier: "MyCustomCell")
        myTable.dataSource = self
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: "MyCustomCell") as? MyCustomCell {
            cell.myLabel.text = "Hello world."
            return cell
        }
        ...
    }
}

Derek Soike
sumber
Anda menyelamatkan hari saya. Saya telah .. menyalin MyHeaderView.swiftuntuk sel khusus. Tampilan .swiftuntuk tajuk tidak ada identifierdi Table View Celldalam Attribute Inspector. jadi ... terjadi kesalahan waktu proses.
mazend
Ngomong-ngomong .. kenapa kita harus mendeklarasikan nama yang sama untuk identifier in .swiftdan in tableView?.register(blahblah, forCellReuseIdentifier: "myCell")? Saya pikir salah satunya tidak perlu, tetapi .. Saya menemukan bahwa keduanya penting.
mazend
um .. Mungkin karena .. .xibuntuk sel khusus bisa berisi banyak UITableViewCelljadi .. .xibtidak cukup untuk .. menemukan sel yang benar.
mazend
5

Anda tidak mendaftarkan ujung pena Anda seperti di bawah ini:

tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
Sujan
sumber
4

Metode lain yang mungkin berhasil untuk Anda (begitulah cara saya melakukannya) adalah mendaftarkan kelas.

Asumsikan Anda membuat tableView kustom seperti berikut:

class UICustomTableViewCell: UITableViewCell {...}

Anda kemudian dapat mendaftarkan sel ini di UITableViewController apa pun yang akan Anda tampilkan dengan "registerClass":

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.registerClass(UICustomTableViewCell.self, forCellReuseIdentifier: "UICustomTableViewCellIdentifier")
}

Dan Anda dapat memanggilnya seperti yang Anda harapkan di sel untuk metode baris:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("UICustomTableViewCellIdentifier", forIndexPath: indexPath) as! UICustomTableViewCell
    return cell
}
Ethan Kay
sumber
3

Untuk memperbaiki kesalahan "Overriding method ... has incompatible type ..." Saya telah mengubah deklarasi fungsi menjadi

override func tableView(tableView: (UITableView!), 
                        cellForRowAtIndexPath indexPath: (NSIndexPath!)) 
    -> UITableViewCell {...}

(tadinya -> UITableViewCell!- dengan tanda seru di akhir)

tse
sumber
3

cepat 4.1.2

xib.

Buat ImageCell2.swift

Langkah 1

import UIKit

class ImageCell2: UITableViewCell {

    @IBOutlet weak var imgBookLogo: UIImageView!
    @IBOutlet weak var lblTitle: UILabel!
    @IBOutlet weak var lblPublisher: UILabel!
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

}

Langkah 2 . Menurut kelas Viewcontroller

  import UIKit

    class ImageListVC: UIViewController,UITableViewDataSource,UITableViewDelegate {
    @IBOutlet weak var tblMainVC: UITableView!

    var arrBook : [BookItem] = [BookItem]()

    override func viewDidLoad() {
        super.viewDidLoad()
         //Regester Cell
        self.tblMainVC.register(UINib.init(nibName: "ImageCell2", bundle: nil), forCellReuseIdentifier: "ImageCell2")
        // Response Call adn Disply Record
        APIManagerData._APIManagerInstance.getAPIBook { (itemInstance) in
            self.arrBook = itemInstance.arrItem!
            self.tblMainVC.reloadData()
        }
    }
    //MARK: DataSource & delegate
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.arrBook.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//    [enter image description here][2]
        let cell  = tableView.dequeueReusableCell(withIdentifier: "ImageCell2") as! ImageCell2
        cell.lblTitle.text = self.arrBook[indexPath.row].title
        cell.lblPublisher.text = self.arrBook[indexPath.row].publisher
        if let authors = self.arrBook[indexPath.row].author {
            for item in authors{
                print(" item \(item)")
            }
        }
        let  url  = self.arrBook[indexPath.row].imageURL
        if url == nil {
            cell.imgBookLogo.kf.setImage(with: URL.init(string: ""), placeholder: UIImage.init(named: "download.jpeg"))
        }
        else{
            cell.imgBookLogo.kf.setImage(with: URL(string: url!)!, placeholder: UIImage.init(named: "download.jpeg"))
        }
        return cell
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 90
    } 

}
pengguna3263340
sumber
2

Saya harus memastikan bahwa saat membuat outlet untuk menentukan bahwa saya mengaitkan ke sel, bukan pemilik objek. Ketika menu muncul untuk menamainya, Anda harus memilihnya di menu dropdown 'objek'. Tentu saja Anda harus mendeklarasikan sel sebagai kelas Anda juga, bukan hanya 'TableViewCellClass'. Jika tidak, saya akan terus mendapatkan kelas yang tidak sesuai dengan kunci.

buckleyJohnson
sumber
1

Ambil xib sederhana dengan kelas UITableViewCell . Atur UI sesuai kebutuhan dan tetapkan IBOutlet. Gunakan dalam cellForRowAt () tampilan tabel seperti ini:

//MARK: - table method

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.arrayFruit.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell:simpleTableViewCell? = tableView.dequeueReusableCell(withIdentifier:"simpleTableViewCell") as? simpleTableViewCell
    if cell == nil{
        tableView.register(UINib.init(nibName: "simpleTableViewCell", bundle: nil), forCellReuseIdentifier: "simpleTableViewCell")
        let arrNib:Array = Bundle.main.loadNibNamed("simpleTableViewCell",owner: self, options: nil)!
        cell = arrNib.first as? simpleTableViewCell
    }

    cell?.labelName.text = self.arrayFruit[indexPath.row]
    cell?.imageViewFruit.image = UIImage (named: "fruit_img")

    return cell!

}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
 return 100.0
}

masukkan deskripsi gambar di sini

100% bekerja tanpa masalah apa pun (Teruji)

Tuan Javed Multani
sumber
dikatakan sel kontrol?. LabelName adalah nihil
Vignesh
0

Baris ini menambahkan TableViewsel:

static var nib  : UINib{

           return UINib(nibName: identifier, bundle: nil)

       }

       static var identifier : String{

           return String(describing: self)

       }

    

And register in viewcontroller like



//This line use in viewdid load

tableview.register(TopDealLikedTableViewCell.nib, forCellReuseIdentifier: TopDealLikedTableViewCell.identifier)

// cell for row at indexpath

if let cell = tableView.dequeueReusableCell(withIdentifier:

    TopDealLikedTableViewCell.identifier) as? TopDealLikedTableViewCell{

           return cell

  }

return UITableViewCell()
jenish.x
sumber