2016-10-24 14 views
14

Jestem nowy Swift i iOS rozwoju i staram się realizować UITableView programowo bez użycia XIb lub storyboardy. To jest mój kod:Tworzenie UITableView programowo w Swift

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

Ale kiedy uruchomić aplikację, wszystko mam jest pusta tabela. W logu widzę kilka wierszy sections i rows, ale nie ma ich get cell. Jak mogę naprawić ten kod, aby uzyskać tabelę z 6 wierszami tekstu foo?

+3

Dlaczego masz zarówno "ViewController" z własnym widokiem tabeli i 'MyTableViewController', które również mają swój własny widok tabeli? – rmaddy

+2

'MyTableViewController' jest wydawane po' viewDidLoad'. Więc spróbuj zachować referencję. –

+0

Jeśli dopiero zaczynasz korzystać z iOS i Swift, zdecydowanie zalecamy skorzystanie z samouczka w Internecie lub iTunesU. Kurs Stanford na iTunesU o nazwie 'Developing iOS 9 Apps with Swift' wyjaśni, jak wyglądają wykresy obiektów i jak korzystać ze struktur iOS. –

Odpowiedz

29

Uwaga: Jak już wspomniano, programowanie rozpoczęto od Swift 3. Stworzyłem programowo tableView. Copy i paste poniżej kodu w swoim viewController i uruchomić projektu ...

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

wyjściowa:

enter image description here

3

To nie ma sensu, że jesteś przy użyciu UITableViewController jako źródło danych i delegata do widoku tabeli Państwa zdanie kontrolera. Twój kontroler widoku powinien być źródłem danych widoku tabeli i delegować.

Ponieważ wydaje się chcieć kontroler widoku z widoku tabeli, która nie zajmuje całego widoku, przesunąć każdą rzecz do kontrolera widoku w następujący sposób:

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

Myślę, że OP chciał stworzyć strukturę (lub model danych) z dala od VC? – aremvee

1

Nie trzeba tworzyć oddzielnej klasy dla UITableView. Tylko w swojej klasie ViewController wdrożyć protokoły UITableViewDelegate i UITableViewDataSource a następnie wdrożyć metody delegata. Myślę, że Twój kod powinien być jak

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

Opowiedz nam więcej info lub pokazać logi jeśli wciąż napotykają problem.

10

Aktualizacja dla Swift 3

Wariant 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") 
    } 
} 

Opcja 2: zastąpić powyżej Wariant 1 TableViewController z tej klasy

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

enter image description here

+0

jeśli nie chcesz nagłówka lub stopki, wystarczy usunąć odpowiednie kody znaczników i skomentować linię tableView.register .. – iajmeri43

+0

Dla opcji 2, w swift 4, dodanie delegata i źródła danych w deklaracji tableView (np. Tv.dataSource = self) zgłasza błąd. Zamiast tego musiałem zdefiniować źródło danych i delegata w metodzie viewDidLoad. –

+1

@GeorgeBikas uprzejmie z leniwym var tableView zamiast niech tableView to działa ... – iajmeri43

0

Swift 4 kompatybilny

Zamiast dodawania UITableView do swojej UIViewController, należy rozważyć tworzenie UITableViewController i unikanie konfigurowania delegatów:

class YourTVC: TableViewController { 

    override func viewDidLoad() { 
    super.viewDidLoad() 

    // setup stuff 
    tableView.register(UITableViewCell.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) 
    cell.textLabel?.text = "Cell at row \(indexPath.row)" 
    return cell 
    } 

}