如何制作带圆角和单线边框的缩进UITableViewCell

问题描述 投票:0回答:2

我正在尝试使用具有圆角,边框和缩进的单元格构建UITableView。有了这三个组合,我很难在两侧和每个病例的细胞之间获得1.0pt的边界(1个细胞,2个细胞,> 2个细胞)。

在最简单的版本中,唯一的问题是单元格之间的边界是双倍宽度。由于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方法单独添加边框时,会出现其他问题,例如:

  • 右侧的边框不可见,因为不考虑为缩进设置的新帧宽度
  • 角落没有正确倒圆
  • 还有一个双倍宽度的分隔符

此外,问题的类型还取决于视图是直接加载(在重新运行应用程序之后)还是在添加/删除单元格之后。

在IB中将clipToBounds设置为true,并将ContentView的ContentMode设置为居中。

我将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
    }
}

澄清:

期望的结果

enter image description here

实际结果

enter image description here

非常感谢!

ios swift uitableview autolayout
2个回答
1
投票

使用典型的UITableView,实现了:

enter image description here

通过在viewDidLoad()中添加这些行:

    myTableView.layer.borderColor = myTableView.separatorColor?.cgColor
    myTableView.layer.borderWidth = 1.0
    myTableView.layer.cornerRadius = 6.0

编辑:另一种方法,适应使用frame覆盖来给表“插入”。

CAShapeLayer作为子层添加到单元格中。将其路径设置为形成正确边缘和角落的UIBezierPath

顶部单元格只有左边,顶边和右边(没有底部),顶角是圆角。

中间单元格将具有左,上和右边缘(没有底部),没有角落圆角。

底部单元将具有所有4个边缘,底部圆角为圆形。

单行表格中的单元格将具有所有4个边缘,所有4个角都是圆角。

结果:

enter image description here

完整代码(不需要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
    }

}

0
投票

enter image description hereIssue带边框时设置边框为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-和其他人添加边框除了顶部边框。

© www.soinside.com 2019 - 2024. All rights reserved.