我正在尝试使用具有圆角,边框和缩进的单元格构建UITableView。结合使用这三种方法,我很难在每种情况下(1个单元格,2个单元格,> 2个单元格)在单元格的侧面和之间获得1.0pt的边框。
在最简单的版本中,唯一的问题是单元格之间的边界是双倍宽度。由于borderWidth
只能为整个框架设置,因此我尝试使用以下方法添加单个边框:
extension CALayer {
func addBorder(edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer()
switch edge {
case .top:
border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
case .bottom:
border.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness)
case .left:
border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.height)
case .right:
border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
default:
break
}
border.backgroundColor = color.cgColor;
addSublayer(border)
}
}
使用addBorder
方法分别添加边框时,会出现其他问题,例如:
此外,问题的类型还取决于是直接加载视图(重新运行应用程序之后)还是添加/删除单元格之后。
clipToBounds
在IB中设置为true,ContentView的ContentMode设置为center。
我将UITableViewCell
分为以下子类:
enum RoundedTableViewCellType {
case first
case last
case single
case middle
}
class RoundedTableViewCell: UITableViewCell {
override var frame: CGRect {
get {
return super.frame
}
set {
let inset: CGFloat = 20
var frame = newValue
frame.origin.x += inset
frame.size.width -= 2 * inset
super.frame = frame
}
}
var type: RoundedTableViewCellType = .middle {
didSet {
switch type {
case .first:
layer.cornerRadius = 6
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
case .last:
layer.cornerRadius = 6
layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
case .single:
layer.cornerRadius = 6
layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner, .layerMinXMinYCorner, .layerMaxXMinYCorner]
case .middle:
layer.cornerRadius = 0
layer.maskedCorners = []
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
layer.borderColor = UIColor.primaryTransparant.cgColor
layer.borderWidth = 1.0
}
}
要澄清:
所需结果
实际结果
非常感谢!
答案 0 :(得分:1)
使用典型的UITableView
,可以达到以下目的:
通过在viewDidLoad()
中添加以下行:
myTableView.layer.borderColor = myTableView.separatorColor?.cgColor
myTableView.layer.borderWidth = 1.0
myTableView.layer.cornerRadius = 6.0
编辑:另一种方法是适应使用frame
覆盖来赋予表“插入项”。
向该单元格添加CAShapeLayer
作为子层。将其路径设置为UIBezierPath
,以形成正确的边角。
顶部单元格只有左,上和右边缘(没有底部),顶部角是圆角的。
中间单元将具有左,上和右边缘(无底),且没有四角。
底部单元格将具有所有4条边,且底部角均被圆化。
单行表格中的一个单元格将具有所有4个边,所有4个角都被弄圆。
结果:
完整代码(无需IBOutlets):
enum RoundedTableViewCellType {
case first
case last
case single
case middle
}
class RoundedTableViewCell: UITableViewCell {
var theLabel: UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.font = UIFont.systemFont(ofSize: 16.0, weight: .bold)
v.textColor = UIColor(red: 62.0 / 255.0, green: 43.0 / 255.0, blue: 191.0 / 255.0, alpha: 1.0)
return v
}()
private var borderLayer = CAShapeLayer()
private var myType: RoundedTableViewCellType = .middle
override var frame: CGRect {
get {
return super.frame
}
set {
let inset: CGFloat = 20
var frame = newValue
frame.origin.x += inset
frame.size.width -= 2 * inset
super.frame = frame
}
}
var borderColor: UIColor = .clear {
didSet {
borderLayer.strokeColor = borderColor.cgColor
}
}
var borderWidth: CGFloat = 0.0 {
didSet {
borderLayer.lineWidth = borderWidth
}
}
// need to re-set layer cornerRadius if radius is set *after* type (in VC's cellForRowAt)
var radius: CGFloat = 6.0 {
didSet {
type = myType
}
}
var type: RoundedTableViewCellType = .middle {
didSet {
myType = type
switch type {
case .first:
layer.cornerRadius = radius
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
case .last:
layer.cornerRadius = radius
layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
case .single:
layer.cornerRadius = radius
layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner, .layerMinXMinYCorner, .layerMaxXMinYCorner]
case .middle:
layer.cornerRadius = 0
layer.maskedCorners = []
}
}
}
override func layoutSubviews() {
super.layoutSubviews()
let r = radius
var bPath = UIBezierPath()
let ptTopLeft = CGPoint(x: 0.0, y: 0.0)
let ptTopRight = CGPoint(x: bounds.width, y: 0.0)
let ptBotRight = CGPoint(x: bounds.width, y: bounds.height)
let ptBotLeft = CGPoint(x: 0.0, y: bounds.height)
switch type {
case .first:
// top cell, add left, top and right edges
// round top corners
bPath.move(to: ptBotLeft)
bPath.addLine(to: CGPoint(x: ptTopLeft.x, y: ptTopLeft.y + r))
bPath.addQuadCurve(to: CGPoint(x: ptTopLeft.x + r, y: ptTopLeft.y),
controlPoint: ptTopLeft)
bPath.addLine(to: CGPoint(x: ptTopRight.x - r, y: ptTopRight.y))
bPath.addQuadCurve(to: CGPoint(x: ptTopRight.x, y: ptTopRight.y + r),
controlPoint: ptTopRight)
bPath.addLine(to: CGPoint(x: ptBotRight.x, y: ptBotRight.y))
case .last:
// bottom cell, add all four edges
// round bottom corners
bPath = UIBezierPath(roundedRect: bounds,
byRoundingCorners: [.bottomLeft, .bottomRight],
cornerRadii: CGSize(width: r, height: r))
case .single:
// one-row table, add all four edges
// round all four corners
bPath = UIBezierPath(roundedRect: bounds, cornerRadius: r)
case .middle:
// middle cell, add left, top, right edges
// round NO corners
bPath.move(to: ptBotLeft)
bPath.addLine(to: ptTopLeft)
bPath.addLine(to: ptTopRight)
bPath.addLine(to: ptBotRight)
}
borderLayer.path = bPath.cgPath
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() -> Void {
contentView.addSubview(theLabel)
NSLayoutConstraint.activate([
theLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16.0),
theLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -16.0),
theLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16.0),
theLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16.0),
])
layer.addSublayer(borderLayer)
borderLayer.fillColor = UIColor.clear.cgColor
// default values
borderColor = UIColor(red: 220.0 / 255.0, green: 215.0 / 255.0, blue: 244.0 / 255.0, alpha: 1.0)
borderWidth = 1.0
}
}
class RoundedCornersInsetTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var myTableView: UITableView = {
let v = UITableView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
var theData = [1, 2, 3, 4]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red: 242.0 / 255.0, green: 240.0 / 255.0, blue: 250.0 / 255.0, alpha: 1.0)
myTableView.dataSource = self
myTableView.delegate = self
myTableView.register(RoundedTableViewCell.self, forCellReuseIdentifier: "RoundedTableViewCell")
myTableView.backgroundColor = .clear
myTableView.separatorStyle = .none
myTableView.tableFooterView = UIView(frame: CGRect.zero)
view.addSubview(myTableView)
NSLayoutConstraint.activate([
// constrain top + 40-pts
myTableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40.0),
// constrain leading / trailing to 0.0
myTableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0.0),
myTableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0.0),
// change this as appropriate
myTableView.heightAnchor.constraint(equalToConstant: 400.0)
])
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return theData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RoundedTableViewCell", for: indexPath) as! RoundedTableViewCell
cell.theLabel.text = "Cell \(theData[indexPath.row])"
cell.accessoryType = .disclosureIndicator
if theData.count == 1 {
cell.type = .single
} else {
if indexPath.row == 0 {
cell.type = .first
} else if indexPath.row == theData.count - 1 {
cell.type = .last
} else {
cell.type = .middle
}
}
// configurable cell border properties
//cell.borderColor = UIColor(red: 220.0 / 255.0, green: 215.0 / 255.0, blue: 244.0 / 255.0, alpha: 1.0)
//cell.borderWidth = 2.0
//cell.radius = 16.0
return cell
}
}
答案 1 :(得分:0)
当将border设置为1像素帧时,问题带有边框,第一个单元格从所有四个侧面获取1个像素,创建第二个单元格时,从所有四个侧面再次获取1个像素。单元格与第一个单元格的底部边框(实际上看起来像2像素厚度)相结合,您需要处理此问题。
extension UIView {
// Example use: myView.addBorder(toSide: .Left, withColor: UIColor.redColor().CGColor, andThickness: 1.0)
enum ViewSide {
case Left, Right, Top, Bottom
}
func addBorder(toSide side: ViewSide, withColor color: CGColor, andThickness thickness: CGFloat) {
let border = CALayer()
border.backgroundColor = color
switch side {
case .Left: border.frame = CGRect(x: frame.minX, y: frame.minY, width: thickness, height: frame.height); break
case .Right: border.frame = CGRect(x: frame.maxX, y: frame.minY, width: thickness, height: frame.height); break
case .Top: border.frame = CGRect(x: frame.minX, y: frame.minY, width: frame.width, height: thickness); break
case .Bottom: border.frame = CGRect(x: frame.minX, y: frame.maxY, width: frame.width, height: thickness); break
}
layer.addSublayer(border)
}
}
1-对于第一个单元格,向所有侧面添加边框
2-,其他则添加除“顶边框”以外的边框。