Создайте UITableView программно в Swift

#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 с собственным табличным представлением, так и a MyTableViewController , которые также имеют свое собственное табличное представление?

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