Custom UITableViewCell จากปลายปากกาใน Swift


139

ฉันกำลังพยายามสร้างเซลล์มุมมองตารางที่กำหนดเองจากปลายปากกา ผมหมายถึงในบทความนี้ที่นี่ ฉันกำลังเผชิญกับสองประเด็น

ฉันสร้างไฟล์. xib โดยมีวัตถุ UITableViewCell ลากไปไว้ ฉันสร้างคลาสย่อยของUITableViewCellและตั้งเป็นคลาสของเซลล์และเซลล์เป็นตัวระบุที่ใช้ซ้ำได้

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 ในกระดานเรื่องราวฉันไม่ได้ทำอะไรกับเซลล์ ตัวระบุว่างเปล่าและไม่มีคลาสย่อย ฉันพยายามเพิ่มตัวระบุเซลล์ลงในเซลล์ต้นแบบและเรียกใช้อีกครั้ง แต่ฉันได้รับผลลัพธ์เดียวกัน

ข้อผิดพลาดอื่นที่ฉันเผชิญคือเมื่อฉันพยายามใช้วิธีการต่อไปนี้ใน 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รูปแบบประเภทของพารามิเตอร์UITableViewCellการCustomOneCellซึ่งเป็น subclass ของฉัน UITableViewCell แต่ฉันได้รับข้อผิดพลาดดังต่อไปนี้

วิธีการแทนที่ด้วยตัวเลือก '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

1
ใช้เซลล์ต้นแบบต่อไป แต่ให้แน่ใจว่าคุณได้ตั้งค่าข้อ จำกัด เลย์เอาต์อัตโนมัติที่ดี (ถ้าคุณใช้เลย์เอาต์อัตโนมัติ)
Imanou Petit

1
ฉันอัปโหลดโครงการทดสอบที่นี่เพื่อแสดงปัญหาที่ฉันมี คุณช่วยดูหน่อยได้ไหมถ้าคุณมีเวลา
Isuru

1
โครงการทดสอบของคุณยืนยัน: ฉันสามารถทำให้แอปของคุณทำงานได้ดีหลังจากที่ฉันตั้งข้อ จำกัด เลย์เอาต์อัตโนมัติให้กับเซลล์ที่กำหนดเองของคุณในไฟล์. xib ของคุณ ดูวิดีโอนี้หากคุณจำเป็นต้องรู้เพิ่มเติมเกี่ยวกับเลย์เอาต์อัตโนมัติ
Imanou Petit

2
@KirillKudaev ไม่ได้เปลี่ยนชื่อเป็น Swift 4 แต่เป็น Swift 3: ฉันแก้ไขการแก้ไขของคุณแล้ว
Cœur

30

นี่คือวิธีการของฉันโดยใช้ Swift 2 และ Xcode 7.3 ตัวอย่างนี้จะใช้ ViewController ไฟล์เดียวเพื่อโหลดไฟล์. xib สองไฟล์ - หนึ่งไฟล์สำหรับ UITableView และอีกไฟล์หนึ่งสำหรับ 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)

}

รหัสแสดงวิธีที่คุณสามารถโหลดและแสดงไฟล์ปลายปากกา (ตาราง) และวิธีที่สองในการลงทะเบียนปลายปากกาสำหรับการใช้เซลล์

หวังว่านี่จะช่วย !!!


2
คุณสามารถอธิบายว่า "tableCellId" ในบรรทัดนี้คืออะไร .... self.tableView.registerNib (cellNib, forCellReuseIdentifier: self.tableCellId) .... เพราะคุณยังไม่ได้กำหนดอะไร และคุณไม่สามารถกำหนดตัวระบุด้วยตนเองได้ใน xib .. ไม่มีตัวเลือกใดให้กำหนด
PRADIP KUMAR

1
ในตัวสร้างอินเตอร์เฟสเมื่อคุณสร้าง tableCell ใน "attribute inspector" คุณกำหนดตัวระบุ ตัวระบุเดียวกันคือสิ่งที่คุณใช้ในตัวควบคุมของคุณเพื่ออ้างอิงวัตถุ let tableCellId = "myAwesomeCell". ฉันเพิ่มรูปภาพอื่นเพื่อช่วยคุณ
internet-nico

16

สวิฟต์ 4

ลงทะเบียน Nib

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. เพิ่ม a UITableViewCellroot ของไฟล์ xib และส่วนประกอบภาพอื่น ๆ ที่คุณต้องการ

ป้อนคำอธิบายรูปภาพที่นี่

  1. สร้างแฟ้มระดับโกโก้ติดต่อกับชื่อชั้นMyCustomCellเป็น subclass UITableViewCellของ

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

  1. ตั้งค่าคลาสที่กำหนดเองและใช้ตัวระบุซ้ำสำหรับเซลล์มุมมองตารางที่กำหนดเองของคุณ

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

  1. เปิดตัวแก้ไขผู้ช่วยและctrl+dragสร้างช่องสำหรับส่วนประกอบภาพของคุณ

ป้อนคำอธิบายรูปภาพที่นี่

  1. กำหนดค่า a 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สำหรับมุมมองส่วนหัวไม่ได้มีidentifierในในTable View Cell Attribute Inspectorดังนั้น ... เกิดข้อผิดพลาดในการรัน
mazend

ทำไมเราถึงประกาศชื่อเดียวกันสำหรับตัวระบุใน.swiftและในtableView?.register(blahblah, forCellReuseIdentifier: "myCell")? ฉันคิดว่าหนึ่งในนั้นไม่จำเป็น แต่ .. ฉันพบว่าทั้งคู่มีความสำคัญ
mazend

อืม .. อาจเป็นเพราะ .. .xibสำหรับเซลล์ที่กำหนดเองสามารถมีได้หลายรายการUITableViewCellดังนั้น .. .xibไม่เพียงพอที่จะหาเซลล์ที่ถูกต้อง
mazend

5

คุณไม่ได้ลงทะเบียนปลายปากกาดังนี้:

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

4

วิธีการอื่นที่อาจใช้ได้ผลกับคุณ (เป็นวิธีที่ฉันทำได้) คือการลงทะเบียนชั้นเรียน

สมมติว่าคุณสร้าง tableView แบบกำหนดเองดังต่อไปนี้:

class UICustomTableViewCell: UITableViewCell {...}

จากนั้นคุณสามารถลงทะเบียนเซลล์นี้ในสิ่งที่ UITableViewController คุณจะแสดงในด้วย "registerClass":

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

ง่ายใช้ Xib กับระดับUITableViewCell ตั้งค่า 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 เป็นศูนย์
Vignesh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.