iOS 视图边框透出底色问题解决

260 阅读1分钟

image.png

小红点UI要求如图例,红色视图添加白色外边框

image.png

方案 1

使用 AB 两个视图进行搭建,A 视图底色为白色,B 视图底色为红色,A add B,并将 B 的约束/frame 布局进行内边距处理,随后进行对 A 视图进行边框处理。

方案 2(本文讨论的方案)

使用 A 一个视图进行搭建,A 视图底色为红色,并对其进行添加边框处理,边框宽度为 1

    import UIKit

    class ViewController: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            view.backgroundColor = .blue
            
            let view = UIView()
            view.backgroundColor = .red
            view.frame = CGRect(x: 100, y: 100, width: 8, height: 8)
            view.layer.cornerRadius = 4
            view.layer.borderColor = UIColor.white.cgColor
            view.layer.borderWidth = 1
            view.clipsToBounds = true
            self.view.addSubview(view)
        }
    }

问题

image.png

但是经过效果呈现的截图放大,发现边框透出底色的红色

解决方案

使用贝塞尔曲线,设置完边框,再设置一下 layer 的 mask 即可

            let path = UIBezierPath(roundedRect: view.bounds,
                                    cornerRadius: view.layer.cornerRadius)
            let mask = CAShapeLayer()
            mask.path = path.cgPath
            view.layer.mask = mask

image.png

完整代码

    class ViewController: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            view.backgroundColor = .blue
            
            let view = UIView()
            view.backgroundColor = .red
            view.frame = CGRect(x: 100, y: 100, width: 8, height: 8)
            view.layer.cornerRadius = 4
            view.layer.borderColor = UIColor.white.cgColor
            view.layer.borderWidth = 1
            view.clipsToBounds = true
            self.view.addSubview(view)
            
            let path = UIBezierPath(roundedRect: view.bounds,
                                    cornerRadius: view.layer.cornerRadius)
            let mask = CAShapeLayer()
            mask.path = path.cgPath
            view.layer.mask = mask
        }
    }

PS

如果使用约束布局的话,需要强制刷新一下视图,拿到视图的 size

A 方案
            self.setNeedsLayout()
            self.layoutIfNeeded()
B方案
            DispatchQueue.main.asyncAfter(deadline: .now()) {
                // code
            }