Ios 如何制作具有圆角和单行边框的缩进UITableViewCell
我正在尝试使用具有圆角、边框和缩进的单元格构建UITableView。将这三种情况结合起来,我很难在每种情况下(1个单元格,2个单元格,>2个单元格)的单元格两侧和之间获得1.0pt的边框 在最简单的版本中,唯一的问题是单元格之间的边界是双倍宽度。由于只能为整个帧设置Ios 如何制作具有圆角和单行边框的缩进UITableViewCell,ios,swift,uitableview,autolayout,Ios,Swift,Uitableview,Autolayout,我正在尝试使用具有圆角、边框和缩进的单元格构建UITableView。将这三种情况结合起来,我很难在每种情况下(1个单元格,2个单元格,>2个单元格)的单元格两侧和之间获得1.0pt的边框 在最简单的版本中,唯一的问题是单元格之间的边界是双倍宽度。由于只能为整个帧设置borderWidth,因此我尝试使用以下方法添加单个边框: extension CALayer { func addBorder(edge: UIRectEdge, color: UIColor, thickness: C
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
方法单独添加边框时,会出现其他问题,如:
- 右侧的边框不可见,因为没有考虑为缩进设置的新边框宽度
- 这些角没有正确地倒圆
- 仍然有一个双宽度分隔符
cliptobunds
在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
}
}
澄清:
期望的结果
实际结果
非常感谢 当将边框设置为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-对于其他,添加除顶部边框以外的边框 使用典型的
UITableView
,实现了以下目标:
通过在viewDidLoad()
中添加这些行:
编辑:另一种方法,允许使用
frame
override为表格提供“insets”
将CAShapeLayer
作为子层添加到单元格中。将其路径设置为形成正确边和角的UIBezierPath
顶部单元格将只有左、上、右边缘(无底部),顶部角为圆角
中间单元格将具有左、上、右边缘(无底部),没有圆角
底部单元格将具有全部4条边,底角为圆角
单行表格中的单元格将具有所有4条边,所有4个角均为圆角
结果:
完整代码(无需IBO):
只有在我看到的这个问题上仍然有一个双宽度分隔符,其余两点看起来很好。对,其他问题只有在使用
addBorder
为每边添加边框时才会出现,我在示例中没有这样做,因为我不确定这是否是解决问题的正确方向。您是否尝试过在表视图的层而不是单元格上设置.borderColor
.borderWidth和.cornerRadius
?是的,但这不起作用,因为表视图的宽度与屏幕相同,插入是通过覆盖RoundedTableViewCell
@bas-d中的frame
属性来完成的-我真的认为更改表视图的大小是最简单的方法,但是如果您必须采取覆盖frame
的方法来进行插入,请参阅我编辑过的答案以获得另一种方法。我知道原因,但就是不知道如何正确地修复它。
myTableView.layer.borderColor = myTableView.separatorColor?.cgColor
myTableView.layer.borderWidth = 1.0
myTableView.layer.cornerRadius = 6.0
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
}
}