早年我曾想实现一个相似 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啦!