Home > Software engineering >  When use cornerRadius, iOS UIView background color is wrong color
When use cornerRadius, iOS UIView background color is wrong color

Time:02-20

I apply cornerRadius for UIView, and apply the border color. But, I can see the wrong color at the corner. This image below is an enlarged image for simulator.

simulator

And this image below is debug view hierarchy.

enter image description here

How is fix that?

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .black
        
        let test = UIView()
        test.backgroundColor = .white
        test.layer.cornerRadius = 7
        test.layer.borderColor = UIColor.black.cgColor
        test.layer.borderWidth = 2
        
        view.addSubview(test)
        
        test.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            test.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 15),
            test.topAnchor.constraint(equalTo: view.topAnchor, constant: 50),
            test.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -15),
            test.heightAnchor.constraint(equalToConstant: 40)
        ])
    }
}

CodePudding user response:

OK - what you're seeing is "artifacts" of anti-aliasing of the border... because the border is draw on the inside of the view.

It's been this way since (I believe) the first version of iOS.

The artifacts are even more noticeable when using a corner radius to make the view round:

enter image description here

and zoomed-in to 200%:

enter image description here

The way to avoid this is to use a CAShapeLayer with a rounded-corner UIBezierPath.

Here's a quick example view subclass, with public properties similar to what you're already using on the .layer:

class ExampleView: UIView {
    public var fillColor: CGColor = UIColor.clear.cgColor {
        didSet {
            shapeLayer.fillColor = fillColor
        }
    }
    public var strokeColor: CGColor = UIColor.clear.cgColor {
        didSet {
            shapeLayer.strokeColor = strokeColor
        }
    }
    public var lineWidth: CGFloat = 0 {
        didSet {
            shapeLayer.lineWidth = lineWidth
        }
    }
    public var cornerRadius: CGFloat = 0 {
        didSet {
            shapeLayer.cornerRadius = cornerRadius
        }
    }
    private var shapeLayer: CAShapeLayer!
    override class var layerClass: AnyClass {
        return CAShapeLayer.self
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() -> Void {
        shapeLayer = self.layer as? CAShapeLayer
        shapeLayer.fillColor = fillColor
        shapeLayer.strokeColor = strokeColor
        shapeLayer.lineWidth = lineWidth
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        let pth = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
        shapeLayer.path = pth.cgPath
    }

}

That gives us:

enter image description here

and, again zoomed-in to 200%:

enter image description here

Here's an example view controller showing the differences:

class ExampleViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .black
        
        let test = UIView()
        test.backgroundColor = .white
        test.layer.cornerRadius = 7
        test.layer.borderColor = UIColor.black.cgColor
        test.layer.borderWidth = 2
        
        
        let circleTest = UIView()
        circleTest.backgroundColor = .white
        circleTest.layer.cornerRadius = 20
        circleTest.layer.borderColor = UIColor.black.cgColor
        circleTest.layer.borderWidth = 2

        
        let myTest = ExampleView()
        myTest.backgroundColor = .white
        myTest.cornerRadius = 7
        myTest.strokeColor = UIColor.black.cgColor
        myTest.lineWidth = 2
        

        let myCircleTest = ExampleView()
        myCircleTest.backgroundColor = .white
        myCircleTest.cornerRadius = 20
        myCircleTest.strokeColor = UIColor.black.cgColor
        myCircleTest.lineWidth = 2
        

        view.addSubview(test)
        view.addSubview(circleTest)
        view.addSubview(myTest)
        view.addSubview(myCircleTest)

        test.translatesAutoresizingMaskIntoConstraints = false
        circleTest.translatesAutoresizingMaskIntoConstraints = false
        myTest.translatesAutoresizingMaskIntoConstraints = false
        myCircleTest.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            test.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 15),
            test.topAnchor.constraint(equalTo: view.topAnchor, constant: 50),
            test.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -170),
            test.heightAnchor.constraint(equalToConstant: 40),

            circleTest.topAnchor.constraint(equalTo: test.bottomAnchor, constant: 8),
            circleTest.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            circleTest.heightAnchor.constraint(equalToConstant: 40),
            circleTest.widthAnchor.constraint(equalTo: circleTest.heightAnchor),

            myTest.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 15),
            myTest.topAnchor.constraint(equalTo: circleTest.bottomAnchor, constant: 8),
            myTest.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -170),
            myTest.heightAnchor.constraint(equalToConstant: 40),

            myCircleTest.topAnchor.constraint(equalTo: myTest.bottomAnchor, constant: 8),
            myCircleTest.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            myCircleTest.heightAnchor.constraint(equalToConstant: 40),
            myCircleTest.widthAnchor.constraint(equalTo: myCircleTest.heightAnchor),
            
        ])
    }

}

CodePudding user response:

I hope I'm correct with your remark, that the border color is not right, because you still see the edges of the background color white on the outer edges of your view.

If that's the case, you can easily get rid of that with setting your view to clipsToBounds is true. your code then looks only slightly different.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .black
        
        let test = UIView()
        test.backgroundColor = .white
        test.clipsToBounds = true
        test.layer.cornerRadius = 7
        test.layer.borderColor = UIColor.black.cgColor
        test.layer.borderWidth = 2
        
        view.addSubview(test)
        
        test.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            test.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 15),
            test.topAnchor.constraint(equalTo: view.topAnchor, constant: 50),
            test.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -15),
            test.heightAnchor.constraint(equalToConstant: 40)
        ])
    }
}

This should solve your problem with the edges.

Kind regards, MacUserT

  • Related