#ios #swift #uitableview
#iOS #swift #uitableview
Вопрос:
Я пытаюсь реализовать UITableView программно без использования xib или раскадровок. Это мой код:
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let table: UITableViewController = MyTableViewController()
let tableView: UITableView = UITableView()
tableView.frame = CGRect(x: 10, y: 10, width: 100, height: 500)
tableView.dataSource = table
tableView.delegate = table
self.view.addSubview(tableView)
}
}
MyTableViewController.swift
import UIKit
class MyTableViewController: UITableViewController {
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
NSLog("sections")
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
NSLog("rows")
return 3
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
NSLog("get cell")
let cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")
cell.textLabel!.text = "foo"
return cell
}
}
Но когда я запускаю приложение, все, что я получаю, это пустую таблицу. В журнале я вижу несколько строк sections
и rows
, но нет get cell
. Как я могу исправить этот код, чтобы получить таблицу с 6 строками foo
текста?
Комментарии:
1. Почему у вас есть как a
ViewController
с собственным табличным представлением, так и aMyTableViewController
, которые также имеют свое собственное табличное представление?2.
MyTableViewController
выходит послеviewDidLoad
. Поэтому попробуйте сохранить ссылку.3. Если вы новичок в iOS и Swift, я настоятельно рекомендую вам следовать руководству в Интернете или iTunesU. В Стэнфордском курсе iTunesU, который называется
Developing iOS 9 Apps with Swift
, рассказывается об объектных графах и о том, как использовать фреймворки iOS.4. Спасибо за ответы, ответ New16 мне помог.
Ответ №1:
Примечание: Как вы упомянули, вы только начали программировать в Swift
. Я создал TableView программно. Copy
и paste
приведенный ниже код вставьте в свой viewController
и запустите проект…
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let myArray: NSArray = ["First","Second","Third"]
private var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
myTableView = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
myTableView.dataSource = self
myTableView.delegate = self
self.view.addSubview(myTableView)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Num: (indexPath.row)")
print("Value: (myArray[indexPath.row])")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath as IndexPath)
cell.textLabel!.text = "(myArray[indexPath.row])"
return cell
}
}
Вывод:
Комментарии:
1. я получаю сообщение об ошибке при попытке зарегистрировать ячейку-прототип. любое решение или обходной путь. я использую swift 4
2. @ZahurafzalMirza Приведенный выше код должен нормально работать в Swift 4. Что говорится в вашем журнале ошибок?
3. Метод @Joe didSelectRowAt не вызывается,
4. как настроить элемент TableCell, например, добавить изображение? и количество ячеек в каждой строке?
5. @Criss Вам нужно создать пользовательскую ячейку просмотра, чтобы добавить изображение и т.д. Следуйте этому руководству, может помочь ralfebert.de/ios-examples/uikit/uitableviewcontroller /…
Ответ №2:
Обновлено для Swift 3
Вариант 1:
import UIKit
//
// MARK :- TableViewController
//
class TableViewController: UITableViewController {
private let headerId = "headerId"
private let footerId = "footerId"
private let cellId = "cellId"
//
// MARK :- HEADER
//
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerId) as! CustomTableViewHeader
return header
}
//
// MARK :- FOOTER
//
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 150
}
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: footerId) as! CustomTableViewFooter
return footer
}
//
// MARK :- CELL
//
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! CustomTableCell
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
title = "TableView Demo"
view.backgroundColor = .white
setupTableView()
}
func setupTableView() {
tableView.backgroundColor = .lightGray
tableView.register(CustomTableViewHeader.self, forHeaderFooterViewReuseIdentifier: headerId)
tableView.register(CustomTableViewFooter.self, forHeaderFooterViewReuseIdentifier: footerId)
tableView.register(CustomTableCell.self, forCellReuseIdentifier: cellId)
}
}
//
// MARK :- HEADER
//
class CustomTableViewHeader: UITableViewHeaderFooterView {
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .orange
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//
// MARK :- FOOTER
//
class CustomTableViewFooter: UITableViewHeaderFooterView {
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .green
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//
// MARK :- CELL
//
class CustomTableCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .white
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Вариант 2: замените приведенный выше вариант 1 TableViewController этим классом
import UIKit
//
// MARK :- ViewController
//
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let headerId = "headerId"
private let footerId = "footerId"
private let cellId = "cellId"
lazy var tableView: UITableView = {
let tv = UITableView(frame: .zero, style: .plain)
tv.translatesAutoresizingMaskIntoConstraints = false
tv.backgroundColor = .lightGray
tv.delegate = self
tv.dataSource = self
tv.register(CustomTableViewHeader.self, forHeaderFooterViewReuseIdentifier: self.headerId)
tv.register(CustomTableViewFooter.self, forHeaderFooterViewReuseIdentifier: self.footerId)
tv.register(CustomTableCell.self, forCellReuseIdentifier: self.cellId)
return tv
}()
//
// MARK :- HEADER
//
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerId) as! CustomTableViewHeader
return header
}
//
// MARK :- FOOTER
//
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: footerId) as! CustomTableViewFooter
return footer
}
//
// MARK :- CELL
//
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! CustomTableCell
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
title = "TableView Demo"
view.backgroundColor = .white
view.addSubview(tableView)
setupAutoLayout()
}
func setupAutoLayout() {
tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
}
Комментарии:
1. если вам не нужны верхний или нижний колонтитулы, просто удалите соответствующие коды меток и прокомментируйте строку TableView.register..
2. Для варианта 2 в swift 4 добавление делегата и источника данных внутри объявления TableView (например, tv.DataSource = self) приводит к ошибке. Вместо этого мне пришлось определить источник данных и делегат в методе viewDidLoad.
3. @GeorgeBikas, пожалуйста, сделайте это с помощью lazy var TableView вместо let TableView, тогда это сработает…
Ответ №3:
Совместимость с Swift 4
Вместо того, чтобы UITableView
добавлять в свой UIViewController
, вам следует подумать о создании UITableViewController
и избегать настройки делегатов:
class YourTVC: TableViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setup custom cells if you use them
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "yourCell")
}
// MARK: tableView
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3 // set to value needed
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "yourCell", for: indexPath) as! CustomTableViewCell
cell.textLabel?.text = "Cell at row (indexPath.row)"
return cell
}
}
Ответ №4:
Не имеет смысла, что вы используете UITableViewController
в качестве источника данных и делегата для табличного представления вашего контроллера представления. Источником данных и делегатом табличного представления должен быть ваш собственный контроллер представления.
Поскольку вам, похоже, нужен контроллер представления с табличным представлением, которое не занимает весь вид, переместите все элементы в свой контроллер представления следующим образом:
ViewController.swift:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let tableView: UITableView = UITableView()
tableView.frame = CGRect(x: 10, y: 10, width: 100, height: 500)
tableView.dataSource = self
tableView.delegate = self
self.view.addSubview(tableView)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
NSLog("sections")
return 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
NSLog("rows")
return 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
NSLog("get cell")
let cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")
cell.textLabel!.text = "foo"
return cell
}
}
Комментарии:
1. Я думаю, что OP хотел создать структуру (или модель данных) вдали от VC ?
Ответ №5:
Вам не нужно создавать отдельный класс для UITableView. Просто в вашем классе ViewController реализуйте протоколы UITableViewDelegate и UITableViewDataSource, а затем реализуйте методы делегирования. Я думаю, что ваш код должен быть похож
class ViewController: UIViewController , UITableViewDelegate , UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
let table: UITableViewController = MyTableViewController()
let tableView: UITableView = UITableView()
tableView.frame = CGRect(x: 10, y: 10, width: 100, height: 500)
tableView.dataSource = table
tableView.delegate = table
self.view.addSubview(tableView)
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
NSLog("sections")
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
NSLog("rows")
return 3
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
NSLog("get cell")
let cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")
cell.textLabel!.text = "foo"
return cell
}
}
Сообщите нам больше информации или покажите журналы, если вы все еще сталкиваетесь с проблемой.
Ответ №6:
У меня была похожая проблема в том, что данные не заполнялись для моего программного UITableView. Это произошло потому, что я использовал делегат / источник данных без строгой ссылки. Как только я сохранил ссылку на него (у меня был один класс, реализующий как UITableViewDataSource, так и UITableViewDelegate), данные были заполнены.
Ответ №7:
import UIKit
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TableCell.self, forCellReuseIdentifier: "cell")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableCell
cell.nameLabel.text = "TableViewCell programtically"
cell.nameLabel.textAlignment = .center
cell.nameLabel.textColor = .white
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
Ответ №8:
Простое решение
import UIKit
class CustomTableViewController: UICollectionViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
cell.textLabel!.text = "(indexPath.row)"
return cell
}
}