Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/94.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何制作具有圆角和单行边框的缩进UITableViewCell_Ios_Swift_Uitableview_Autolayout - Fatal编程技术网

Ios 如何制作具有圆角和单行边框的缩进UITableViewCell

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

我正在尝试使用具有圆角、边框和缩进的单元格构建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
方法单独添加边框时,会出现其他问题,如:

  • 右侧的边框不可见,因为没有考虑为缩进设置的新边框宽度
  • 这些角没有正确地倒圆
  • 仍然有一个双宽度分隔符
此外,问题的类型还取决于是直接加载视图(重新运行应用程序后)还是添加/删除单元格后

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
    }

}