SwiftのnibからのカスタムUITableViewCell


139

ペン先からカスタムテーブルビューセルを作成しようとしています。私はこの記事をここで参照しています。私は2つの問題に直面しています。

UITableViewCellオブジェクトをドラッグして.xibファイルを作成しました。のサブクラスを作成し、UITableViewCellそれをセルのクラスとして、Cellを再利用可能な識別子として設定しました。

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
    }

}

UITableViewControllerにこのコードがあります。

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
    }
}

このコードはエラーに準拠していませんが、シミュレーターで実行すると次のようになります。

ここに画像の説明を入力してください

ストーリーボードのUITableViewControllerでは、セルに対して何もしていません。空白の識別子で、サブクラスはありません。セル識別子をプロトタイプセルに追加してもう一度実行したところ、同じ結果が得られました。

私が直面したもう1つのエラーは、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]
}

記事で示したように、cellパラメーターの型フォームUITableViewCellCustomOneCellUITableViewCellのサブクラスに変更しました。しかし、私は次のエラーを受け取ります、

セレクター 'tableView:willDisplayCell:forRowAtIndexPath:'でメソッドをオーバーライドすると、互換性のないタイプ '(UITableView !, CustomOneCell !, NSIndexPath!)->()'が含まれます

誰でもこれらのエラーを解決する方法を知っていますか?これらはObjective-Cでは問題なく動作するようです。

ありがとうございました。

編集:シミュレータの向きを横に変更して縦に戻すと、セルが表示されることに気づきました!私はまだ何が起こっているのか理解できませんでした。ここに Xcodeプロジェクトをアップロードして、簡単に確認する時間がある場合の問題を示します。

回答:


213

Swift 5とiOS 12.2では、問題を解決するために次のコードを試す必要があります。

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
    }

}

以下の画像は、Xcodeからの制約のあいまいさのメッセージなしで、提供されたコードで機能する一連の制約を示しています。

ここに画像の説明を入力してください


1
ご返信ありがとうございます。しかし、それもうまくいきませんでした。テーブルビューコントローラーで何かを変更する必要がありますか?まだプロトタイプ細胞に設定されているため。
Isuru 2014

1
プロトタイプセルを使い続けます。ただし、適切な自動レイアウト制約が設定されていることを確認してください(自動レイアウトを使用する場合)。
Imanou Petit 2014

1
私が抱えている問題を示すテストプロジェクトをここにアップロードしました。時間があればぜひご覧ください。
Isuru 2014

1
テストプロジェクトはそれを確認します。.xibファイルのカスタムセルにいくつかの自動レイアウト制約を設定した後、アプリを正常に機能させることができました。自動レイアウトについて詳しく知る必要がある場合は、このビデオをご覧ください。
Imanou Petit 2014

2
@KirillKudaev Swift 4では名前が変更されませんでしたが、Swift 3では変更が修正されました。
2018年

30

これがSwift 2とXcode 7.3を使用した私のアプローチです。この例では、単一のViewControllerを使用して2つの.xibファイルをロードします。1つはUITableView用で、もう1つはUITableCellView用です。

ここに画像の説明を入力してください

この例では、UITableViewを空のTableNib .xibファイルに直接ドロップできます。内部では、ファイルの所有者をViewControllerクラスに設定し、アウトレットを使用してtableViewを参照します。

ここに画像の説明を入力してください

そして

ここに画像の説明を入力してください

これで、ビューコントローラで、通常のようにtableViewを委任できます。

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

        ...

カスタムセルを作成するには、テーブルビューセルオブジェクトを空のTableCellNib .xibファイルにドロップします。今回は、セル.xibファイルで「所有者」を指定する必要はありませんが、カスタムクラスと「TableCellId」のような識別子を指定する必要があります

ここに画像の説明を入力してください ここに画像の説明を入力してください

必要なアウトレットを使用してサブクラスを作成します。

class TableCell: UITableViewCell {

    @IBOutlet weak var nameLabel: UILabel!

}

最後に... View Controllerに戻って、全体をロードして表示することができます

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)

}

このコードは、nibファイル(テーブル)を単にロードして表示する方法と、セルで使用するためにnibを登録する方法を示しています。

お役に立てれば!!!


2
この行の「tableCellId」が何であるかを説明できますか... self.tableView.registerNib(cellNib、forCellReuseIdentifier:self.tableCellId)....何を定義していないのですか?また、識別子をxibで手動で定義することはできません。.定義するオプションはありません
PRADIP KUMAR '27

1
インターフェイスビルダーでtableCellを作成するときに、「属性インスペクター」で識別子を定義します。同じ識別子は、オブジェクトを参照するためにコントローラーで使用するものです。let tableCellId = "myAwesomeCell"。私はあなたを助けるために別の画像を追加しました。
internet-nico

16

スウィフト4

ニブを登録

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

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
    }

9

スクリーンショットによる詳細なソリューション

  1. 空のユーザーインターフェイスファイルを作成し、名前を付けMyCustomCell.xibます。

ここに画像の説明を入力してください

  1. UITableViewCellxibファイルのルートとして、および必要なその他のビジュアルコンポーネントを追加します。

ここに画像の説明を入力してください

  1. クラス名MyCustomCellがのサブクラスであるcocoa touchクラスファイルを作成しますUITableViewCell

ここに画像の説明を入力してください ここに画像の説明を入力してください

  1. カスタムクラスを設定し、カスタムテーブルビューセルの識別子を再利用します。

ここに画像の説明を入力してください ここに画像の説明を入力してください

  1. アシスタントエディターを開き、ctrl+dragビジュアルコンポーネントのアウトレットを作成します。

ここに画像の説明を入力してください

  1. UIViewControllerカスタムセルを使用するようにを設定します。
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
        }
        ...
    }
}

あなたは私の日を救った。MyHeaderView.swiftカスタムセル用にコピーしました。.swiftヘッダのビューがありませんidentifierTable View CellしてAttribute Inspector。だから...ランタイムエラーが発生しました。
mazend

ところで、なぜin .swiftとinの識別子に同じ名前を宣言しているのtableView?.register(blahblah, forCellReuseIdentifier: "myCell")ですか?どちらか一方は必要ないと思いましたが、どちらも必須だと思いました。
mazend

ええと...それは多分..ため.xibのカスタムセルのために複数含めることができますUITableViewCell..だから.xib正しいセルを見つける。..に十分ではありません。
mazend

5

以下のようにnibを登録しませんでした:

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

4

あなたのために働くかもしれない別の方法(それは私がそれをする方法です)はクラスを登録することです。

次のようなカスタムtableViewを作成するとします。

class UICustomTableViewCell: UITableViewCell {...}

次に、「registerClass」を使用して、表示するUITableViewControllerにこのセルを登録できます。

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

そして、行メソッドのセルで期待するようにそれを呼び出すことができます:

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

3

「メソッドをオーバーライドしています...互換性のないタイプです...」エラーを修正するために、関数宣言を

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

-> UITableViewCell!以前は-末尾に感嘆符付き)


2

迅速な4.1.2

xib。

ImageCell2.swiftを作成する

ステップ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)
    }

}

ステップ2 。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
    } 

}

2

アウトレットを作成するときに、オブジェクトの所有者ではなく、セルにフックしていることを指定する必要があります。名前を付けるメニューが表示されたら、「オブジェクト」ドロップダウンメニューでメニューを選択する必要があります。もちろん、「TableViewCellClass」だけでなく、セルもクラスとして宣言する必要があります。そうしないと、クラスがキーに準拠しなくなります。


1

単純に、クラスUITableViewCellで xibを取得します。必要に応じてUIを設定し、IBOutletを割り当てます。次のように、テーブルビューのcellForRowAt()で使用します。

//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
}

ここに画像の説明を入力してください

100%問題なく動作(テスト済み)


それはコントロールセルを言う?.labelNameはnil
Vignesh
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.