Пользовательский UITableViewCell от nib в Swift
Я пытаюсь создать пользовательскую ячейку представления таблицы из наконечника. Я имею в виду эту статью здесь. Я столкнулся с двумя проблемами.
Я создал файл .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
}
}
Этот код не содержит ошибок, но когда я запускаю его в симуляторе, он выглядит следующим образом.
![enter image description here]()
В 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
, который является моим подклассом UITableViewCell. Но я получаю следующую ошибку:
Переопределяющий метод с селектором 'tableView: willDisplayCell: forRowAtIndexPath:' имеет несовместимый тип '(UITableView!, CustomOneCell!, NSIndexPath!) → ()'
Кто-нибудь знает, как разрешить эти ошибки? Они, похоже, отлично работали в Objective-C.
Спасибо.
EDIT: Я только заметил, изменил ли я ориентацию симулятора на пейзаж и вернул его к портрету, ящики появятся! Я все еще не мог понять, что происходит. Я загрузил проект Xcode здесь, демонстрируя проблему, если у вас есть время для быстрого просмотра.
Ответы
Ответ 1
В 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:
![enter image description here]()
Ответ 2
Здесь мой подход с использованием 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 View Table в пустой файл 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 (таблица), а второй - зарегистрировать наконечник для использования ячейки.
Надеюсь, это поможет!!!
Ответ 3
Swift 4
Зарегистрироваться Nib
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
}
Ответ 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
}
Ответ 5
Вы не зарегистрировали свое перо, как показано ниже:
tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
Ответ 6
Подробное решение со скриншотами
- Создайте пустой файл интерфейса пользователя и назовите его
MyCustomCell.xib
.
![enter image description here]()
- Добавьте
UITableViewCell
в качестве корня вашего xib файла и любых других визуальных компонентов, которые вы хотите.
![enter image description here]()
-
Создайте файл класса касания cocoa с именем класса
MyCustomCell
в качестве подкласса UITableViewCell
.
![enter image description here]()
- Установите пользовательский класс и повторно используйте идентификатор для пользовательской ячейки табличного представления.
![enter image description here]()
- Откройте редактор помощника и
ctrl+drag
, чтобы создать розетки для ваших визуальных компонентов.
![enter image description here]()
- Сконфигурируйте
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
}
...
}
}
Ответ 7
Для исправления ошибки "Метод переопределения... имеет несовместимый тип..." Я изменил объявление функции на
override func tableView(tableView: (UITableView!),
cellForRowAtIndexPath indexPath: (NSIndexPath!))
-> UITableViewCell {...}
(был -> UITableViewCell!
- с восклицательным знаком в конце)
Ответ 8
Свифт 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
}
}
Ответ 9
Просто возьмите 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
}
![enter image description here]()
100% работает без проблем (проверено)