早年我曾想實現一個相似 iPad 設置頁面右方的 tableView 的風格。它的特色主要是在整個分組設置圓角,以下圖所示 swift
因爲 Section
並非一個真實存在的 View,而是 tableView 便於管理設計的一個邏輯容器。那麼如何對整個 Section 設置圓角呢?ide
還有,若是要利用 tableViewCell 的自帶元素,那麼 Cell 與父視圖應該有必定的 padding,且高亮不能是完整的一行,這個也是我當初沒考慮到的。佈局
當時在網上找了兩種方案,一種是計算好 Section 的位置,在底下添加白底。ui
一種是在把每一個 Section 當作一個 Row 處理,這樣的壞處是要本身處理點擊高亮,並且沒有很好複用 Cell。spa
如今看來,這兩種方案都不太優雅。設計
我想到了第三種方案,大概是這樣的: Section 第一個 Cell 設置左上、右上圓角,最後一個 Cell 設置左下,右下邊角,若是隻有一個 Cell,設置所有圓角。code
首先,Row 的寬度不須要佔滿整個行,因此我須要對 Cell 的位置進行調整,調整完畢以後,設置圓角,圓角能夠分3種情形來設置,還有一種不設置的狀況。cdn
一開始,我設置了 tableView 的 contentInsets 屬性,結果卻讓 tableView 能夠左右滑動了,由於 tableView 繼承於 scrollView,只不過他的 contentSize 的寬度與 frame 的寬度一致纔沒有左右滑動,設置了 contentInsets 的左右邊距以後,tableView 再也不跟預想同樣了。blog
想一想個人目標:調整 tableViewCell 的寬度,使之的 x 座標不爲 0。繼承
那麼這個任務就好辦了,我能夠在 layoutSubviews 裏面去操做,反正任何佈局代碼都會到這裏來,包括經過 AutoLayout 設置的佈局。
而後我自定義了一個 TableViewCell,從而可以自定義 layoutSubviews 操做:
class TableViewCell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
adjustMyFrame()
}
func adjustMyFrame() {
frame = CGRect(x: 16, y: frame.minY, width: superview!.frame.width - 32, height: frame.height)
}
}
複製代碼
經過 Google,很容易找到了設置部分圓角的辦法,而後我在此基礎上添加了一個不設置圓角的方法以免複用問題
extension UIView {
func roundCorners(corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
func noCornerMask() {
layer.mask = nil
}
}
複製代碼
通過剛纔的分析,把這4種狀態做爲一個枚舉:
class TableViewCell: UITableViewCell {
enum Position {
case solo
case first
case middle
case last
}
var position: Position = .middle
}
複製代碼
而後在 layoutSubviews 裏面設置就好了。因爲這種圓角是經過 mask 設置的,不會形成離屏渲染問題,能夠放心使用。
override func layoutSubviews() {
super.layoutSubviews()
adjustMyFrame()
setCorners()
}
func setCorners() {
let cornerRadius: CGFloat = 4.0
switch position {
case .solo: roundCorners(corners: .allCorners, radius: cornerRadius)
case .first: roundCorners(corners: [.topLeft, .topRight], radius: cornerRadius)
case .last: roundCorners(corners: [.bottomLeft, .bottomRight], radius: cornerRadius)
default: noCornerMask()
}
}
複製代碼
同時,須要在 tableViewCell 的數據源指定這個位置:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.textLabel?.text = listData[indexPath.section][indexPath.row]
cell.accessoryType = .disclosureIndicator
if listData[indexPath.section].count == 1 {
cell.position = .solo
} else if indexPath.row == 0 {
cell.position = .first
} else if (indexPath.row == listData[indexPath.section].count - 1) {
cell.position = .last
} else {
cell.position = .middle
}
return cell
}
複製代碼
而後,再自定義分割線,細調一下,就OK啦!