Спеціальний UITableViewCell від кнопки в Swift


139

Я намагаюся створити користувальницьку клітинку для перегляду таблиці за допомогою кнопки. Я маю на увазі цю статтю тут . Я стикаюся з двома питаннями.

Я створив .xib файл із об’єктом UITableViewCell, затягнутим на нього. Я створив підклас 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 на аркуші розробки я нічого не зробив із коміркою. Порожній ідентифікатор і без підкласу. Я спробував додати ідентифікатор Cell до комірки-прототипу і запустив його знову, але я отримав той самий результат.

Ще одна помилка, з якою я зіткнувся - це коли я намагався реалізувати наступний метод у 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який є мій підклас UITableViewCell. Але я отримую таку помилку,

Метод переопределення із селектором 'tableView: willDisplayCell: forRowAtIndexPath:' має несумісний тип '(UITableView !, CustomOneCell !, NSIndexPath!) -> ()'

Хтось має ідею, як вирішити ці помилки? Вони, здавалося, добре спрацювали в Objective-C.

Дякую.

EDIT: Я щойно помітив, якщо я зміню орієнтацію симулятора на пейзаж і поверну його до портретного, клітини з’являються! Я все ще не міг зрозуміти, що відбувається. Я завантажив сюди проект 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
Дякуємо за відповідь. Але і це не спрацювало. Чи потрібно щось змінювати в контролері подання таблиці? Тому що його все ще встановлено на прототипи комірок.
Ісуру

1
Продовжуйте використовувати прототипові комірки. Але переконайтеся, що ви встановили хороші обмеження щодо автоматичного макета (якщо ви використовуєте автоматичний макет).
Imanou Petit

1
Я завантажив сюди тестовий проект, демонструючи проблему, яка у мене є. Чи можете ви, будь ласка, поглянути на це, якщо у вас є час?
Ісуру

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

        ...

Щоб створити власну клітинку, знову опустіть об'єкт Cell Cell Cell у порожній файл TableCellNib .xib. Цього разу у файлі .xib у комірці не потрібно вказувати "власника", але потрібно вказати спеціальний клас та ідентифікатор типу "TableCellId"

введіть тут опис зображення введіть тут опис зображення

Створіть свій підклас із будь-якими торговими точками, які вам потрібні

class TableCell: UITableViewCell {

    @IBOutlet weak var nameLabel: UILabel!

}

Нарешті ... ще назад у своєму контролері перегляду ви можете завантажити та відобразити всю річ так

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

1
У програмі створення інтерфейсу під час створення tableCell у розділі "Інспектор атрибутів" ви визначаєте ідентифікатор. Той самий ідентифікатор - це те, що ви використовуєте в контролері для посилання на об'єкт. let tableCellId = "myAwesomeCell". Я додав ще одне зображення, щоб допомогти вам.
internet-nico

16

Швидкий 4

Зареєструйте Nib

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

У DataView 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. Додайте UITableViewCellкорінь файлу xib та будь-які інші візуальні компоненти.

введіть тут опис зображення

  1. Створіть файл сенсорного класу какао з назвою класу MyCustomCellяк підкласом 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. так ... сталася помилка часу запуску.
лабіринт

До речі .. чому ми оголосили те саме ім'я для ідентифікатора в .swiftі в tableView?.register(blahblah, forCellReuseIdentifier: "myCell")? Я думав, що одна з них не потрібна, але .. Я виявив, що обоє є важливими.
лабіринт

гм .. Це може бути тому, що .. .xibдля користувацької комірки може містити кілька, UITableViewCellтому .. .xibнедостатньо, щоб .. знайти правильну комірку.
лабіринт

5

Ви не зареєстрували свою нитку, як показано нижче:

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

4

Ще один метод, який може працювати для вас (так я це роблю) - це реєстрація класу.

Припустимо, ви створили власну таблицюView у такий спосіб:

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 . Встановіть інтерфейс користувача відповідно до повторного впорядкування та призначте 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 дорівнює нулю
Вігнеш
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.