學習iOS第二週,學習到了比較重要的組件TableView,照着書上敲,沒有實現效果。在同事的幫助下,有了比較清晰的理解,記錄在此。
我使用的完全是xib的方式。我們先按照這種方式來梳理出Demo
先看下項目結構目錄
先從最簡單的model開始看起,可以理解爲javabean
//
// News.swift
// HelloIOS
//
// Created by zxg on 2018/9/27.
// Copyright © 2018年 zxg. All rights reserved.
//
import UIKit
class News: NSObject {
var title:String = "" //新聞標題
var desc:String = "" //新聞描述
init(title:String,desc:String){
self.title = title
self.desc = desc
}
}
接下來是cell
在NewsViewCell.xib中,引入兩個lib,並關聯到NewsViewCell.swift中,比較簡單,直接上截圖:
我們拖拽了兩個label,一個用於顯示title,一個用於顯示描述
接下來是重要的Controller,有兩種方案,第一種自己編寫的Controller繼承自UIViewController,自己去實現UITableView的兩個委託,並手動在xib文件中拖拽tableview並關聯。第二種是自己編寫的Controller直接繼承系統提供的UITableViewController,這種方案比較省事,一來,不用手動實現委託,二來xib中會自帶tableview,不需要再手動關聯。這裏我們先放下系統提供的UITableViewController
import Foundation
import UIKit
import _SwiftUIKitOverlayShims
//
// UITableViewController.h
// UIKit
//
// Copyright (c) 2008-2017 Apple Inc. All rights reserved.
//
// Creates a table view with the correct dimensions and autoresizing, setting the datasource and delegate to self.
// In -viewWillAppear:, it reloads the table's data if it's empty. Otherwise, it deselects all rows (with or without animation) if clearsSelectionOnViewWillAppear is YES.
// In -viewDidAppear:, it flashes the table's scroll indicators.
// Implements -setEditing:animated: to toggle the editing state of the table.
@available(iOS 2.0, *)
open class UITableViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
public init(style: UITableViewStyle)
public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)
public init?(coder aDecoder: NSCoder)
open var tableView: UITableView!
@available(iOS 3.2, *)
open var clearsSelectionOnViewWillAppear: Bool // defaults to YES. If YES, any selection is cleared in viewWillAppear:
@available(iOS 6.0, *)
open var refreshControl: UIRefreshControl?
}
可以看到繼承自UIViewController並實現委託,同時存在變量tableView。我們可以直接使用
接下來,放下我的Controller的代碼,很多關鍵點都在註釋中說明了
//
// NewsViewController.swift
// HelloIOS
//
// Created by zxg on 2018/9/26.
// Copyright © 2018年 zxg. All rights reserved.
//
import UIKit
class NewsViewController: UITableViewController {
//模擬數據源
let newsItem = [News(title: "吳秀波出軌", desc: "吳秀波圈養小妾"),News(title: "中美貿易升級", desc: "美提升2000億關稅"),News(title: "海底撈上市", desc: "創始人張勇暴富"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨")]
let cellIdentifier = "NewsCell"
override func viewDidLoad() {
super.viewDidLoad()
//將TableView背景橫線去掉
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.none
//兩種register方式:
//通過UINib註冊,適用於xib方式,本例中,cell採用的是xib方式而非純代碼。
let nib = UINib.init(nibName: "NewsViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: cellIdentifier)
/*通過class註冊,適用於純代碼方式,需要在cell文件中重寫init(style: UITableViewCellStyle, reuseIdentifier: String?)
在其中初始化view
*/
//tableView.register(NewsViewCell.self, forCellReuseIdentifier: cellIdentifier)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
//UITableViewDataSource委託協議:返回小節的數量
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
//UITableViewDataSource委託協議:返回每個小節的item數量,section爲小節Index
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return newsItem.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
/*使用dequeueReusableCell(withIdentifier: cellIdentifier)方法獲取cell不需要通過register註冊,但是要判斷cell是否爲空,爲空則new cell
var cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? NewsViewCell
if(cell == nil){
cell = NewsViewCell(style: UITableViewCellStyle.default, reuseIdentifier: cellIdentifier)
} */
/*使用dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)獲取cell,其實就使用了tableview的緩存機制,當取到cell爲空時
系統會幫忙創建register的cell,所以就不需要我們手動判空並實例化cell。所以必須register
*/
// Configure the cell...
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? NewsViewCell
let row = indexPath.row
let news:News = newsItem[row]
cell?.tvNewsTitle?.text = news.title
cell?.tvNewsDesc?.text = news.desc
return cell!
}
//返回每個cell的高度
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100.0
}
}
補一張NewsViewCell.swift的代碼,其中也包含了一些註釋:
//
// NewsViewCell.swift
// HelloIOS
//
// Created by zxg on 2018/9/26.
// Copyright © 2018年 zxg. All rights reserved.
//
import UIKit
class NewsViewCell: UITableViewCell {
@IBOutlet weak var tvNewsTitle: UILabel!
@IBOutlet weak var tvNewsDesc: UILabel!
//使用xib方式創建cell,在dequeueReusableCell()時會調用到該方法
//本例中使用的是xib方式
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
}
//使用純代碼方式創建cell,在dequeueReusableCell()時會調用到該方法
//需要在該方法中創建view
// override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
//例如創建如下view:
// super.init(style: style, reuseIdentifier: reuseIdentifier)
// self.iconImageView=UIImageView()
// self.contentView.addSubview(self.iconImageView!)
// self.TitleLabel=UILabel()
// self.contentView.addSubview(self.TitleLabel!)
// setUpviews()
// }
}
關於純代碼創建cell,這篇文章代碼可看:https://www.cnblogs.com/small-Sun/p/5667764.html
關於UITableView複用機制理解:https://blog.csdn.net/wuzesong/article/details/52225487
總結:
1、dequeueReuseableCellWithIdentifier:與dequeueReuseableCellWithIdentifier:forIndexPath:的區別:
前者不必向tableView註冊cell的Identifier,但需要判斷獲取的cell是否爲nil;
後者則必須向table註冊cell,可省略判斷獲取的cell是否爲空,因爲無可複用cell時runtime將使用註冊時提供的資源去新建一個cell並返回。
2、自定義cell時,記得將其他內容加到self.contentView 上,而不是直接添加到 cell 本身上
總結:
1.自定義cell時,
若使用nib,使用 registerNib: 註冊,dequeue時會調用 cell 的 -(void)awakeFromNib
不使用nib,使用 registerClass: 註冊, dequeue時會調用 cell 的 - (id)initWithStyle:withReuseableCellIdentifier:
2.需不需要註冊?
使用dequeueReuseableCellWithIdentifier:可不註冊,但是必須對獲取回來的cell進行判斷是否爲空,若空則手動創建新的cell;
使用dequeueReuseableCellWithIdentifier:forIndexPath:必須註冊,但返回的cell可省略空值判斷的步驟。
寫在最後:
本文介紹內容比較淺顯,沒有深究例如tableView緩存機制,xib講解等。是因爲我還沒深入學習到。會在後邊的文章接受