为UIView添加边框和宽度,将显示一小部分背景。

4
我想给一个绿色背景的UIView添加圆形边框,我创建了一个简单的UIView子类,具有borderWidth,cornerRadius和borderColor属性,并且我从storyboard中设置它。
@IBDesignable
class RoundedView: UIView {

    @IBInspectable var cornerRadius: CGFloat {
        get {
            return layer.cornerRadius
        }
        set {
            layer.cornerRadius = newValue
            layer.masksToBounds = newValue > 0
        }
    }

    @IBInspectable var borderWidth: CGFloat {
        get {
            return layer.borderWidth
        }
        set {
            layer.borderWidth = newValue
        }
    }

    @IBInspectable var borderColor: UIColor {
        get {
            if let color = layer.borderColor {
                return UIColor(cgColor: color)
            } else {
                return UIColor.clear
            }
        }
        set {
            layer.borderColor = newValue.cgColor
        }
    } 

}

但是,当我编译和运行一个应用程序或在InterfaceBuilder中显示它时,我可以看到一个在边框外仍然存在的线条(在白色背景上非常明显)。

enter image description here

这个带有绿色背景、10x10框架和5的圆角半径的RoundedView被放置在普通UIImageView的角落(表示某人是否在线)。您可以在UIImageView和白色背景上看到绿色边框。

enter image description here

你能告诉我出了什么问题吗?


(1) 你没有包含任何代码或说明UIImageView是如何在UIView中定位的,也没有包含任何约束条件。 (2) 你提到了IB和编译,但当你实际运行应用程序时呢?我能看到视图本身的所有正确信息(包括代码和你的IB截图)...如果UIImageView没有边框(并且背景是透明的),那就没问题了。 - user7014451
(1) 我更新了我的回答,这个绿点是带边框的“RoundedView”,它有一个奇怪的边框问题 - 它只是放在“UIImageView”上面。(2) 当然,编译和运行 - 这个边框在模拟器和真实设备上都可以看到,围绕着绿点。 - Roval
4个回答

4
你正在依赖图层来绘制边框和圆角,所以你不掌控结果。你给它一个绿色的背景,现在你看到背景在边框的边缘处“突出”。而且,圆角是一种非常不可靠的方法来制作圆形视图。要制作圆形视图,请制作一个圆形掩模。
因此,制作徽章的方法是完全掌控所绘制的内容:你在白色背景中央绘制一个绿色的圆形,并用更大的圆形掩蔽它们以制作边框。
这里有一个徽章视图,可以精确地做到你想要的,没有任何外部影响。
class Badge : UIView {
    class Mask : UIView {
        override init(frame:CGRect) {
            super.init(frame:frame)
            self.isOpaque = false
            self.backgroundColor = .clear
        }
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        override func draw(_ rect: CGRect) {
            let con = UIGraphicsGetCurrentContext()!
            con.fillEllipse(in: CGRect(origin:.zero, size:rect.size))
        }
    }
    let innerColor : UIColor
    let outerColor : UIColor
    let innerRadius : CGFloat
    var madeMask = false
    init(frame:CGRect, innerColor:UIColor, outerColor:UIColor, innerRadius:CGFloat) {
        self.innerColor = innerColor
        self.outerColor = outerColor
        self.innerRadius = innerRadius
        super.init(frame:frame)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func draw(_ rect: CGRect) {
        let con = UIGraphicsGetCurrentContext()!
        con.setFillColor(outerColor.cgColor)
        con.fill(rect)
        con.setFillColor(innerColor.cgColor)
        con.fillEllipse(in: CGRect(
            x: rect.midX-innerRadius, y: rect.midY-innerRadius,
            width: 2*innerRadius, height: 2*innerRadius))
        if !self.madeMask {
            self.madeMask = true // do only once
            self.mask = Mask(frame:CGRect(origin:.zero, size:rect.size))
        }
    }
}

我尝试使用以下示例设置进行操作:

let v = Badge(frame: CGRect(x:100, y:100, width:16, height:16), 
              innerColor: .green, outerColor: .white, innerRadius: 5)
self.view.addSubview(v)

看起来很好。根据需要调整参数。


1
非常感谢。你能解释一下为什么这是“肮脏和不可靠的方式”吗?另外,你知道为什么会出现这个绿色边框吗? - Roval
1
我也想知道为什么会发生这种情况。原因是我希望我的带边框的圆形视图能够在内部和外部的颜色值之间进行动画处理。如果没有高度复杂的颜色计算方案(由苹果的层动画为我完成),我不确定如何使用您的解决方案来实现这一点。不知道它是如何工作的,达到我想要的最终目标就更加困难了。或者换句话说:您如何将颜色更改动画添加到此解决方案中? - mbm29414
6
我不是原帖作者,我主要是在评论你对好奇心的原帖作者的批评。你似乎把他的评论当作是在和你争辩。无论他是否这样做(我并没有那样读懂他的评论),我认为原问题的“为什么”也很有趣。如果答案是“这是一个私有实现,我们不知道它的具体工作方式”,那很好。但原帖作者最初的评论是在询问我认为是很好的后续问题,而没有以任何方式挑战你的回答。(而且我正在实施你的答案,所以谢谢。) - mbm29414
@mbm29414 尽管如此,如果您有关于颜色动画的实际问题,请将其作为单独的问题进行提问。当您这样做时,请随时通知我。 - matt
谢谢。目前,我正处于截止日期之下,转换的即时性已经足够好了。希望我能在某个时候有时间回过头来处理这个问题... - mbm29414
显示剩余3条评论

1
我通过使用UIBezierPath并添加到视图的层中解决了这个问题:
        let strokePath = UIBezierPath(roundedRect: view.bounds, cornerRadius: view.frame.width / 2)
        let stroke = CAShapeLayer()
        stroke.frame = bounds
        stroke.path = strokePath.cgPath
        stroke.fillColor = .green.cgColor
        stroke.lineWidth = 1.0
        stroke.strokeColor = .white.cgColor
        view.layer.insertSublayer(stroke, at: 2)

1

一种更简单的解决方法可能是像这样屏蔽它:

let mask = UIView()
mask.backgroundColor = .black
mask.frame = yourCircleView.bounds.inset(by: UIEdgeInsets(top: 0.1, left: 0.1, bottom: 0.1, right: 0.1))
mask.layer.cornerRadius = mask.height * 0.5
yourCircleView.mask = mask

0
我用渐变解决了这个问题。只需将您的圆形的backgroundColor设置为渐变即可。
let gradientLayer = CAGradientLayer()
    //define colors
    gradientLayer.colors = [<<your_bgc_color>>>>,  <<border__bgc__color>>]
    //define locations of colors as NSNumbers in range from 0.0 to 1.0
    gradientLayer.locations = [0.0, 0.7]
    //define frame
    gradientLayer.frame = self.classView.bounds

    self.classView.layer.insertSublayer(gradientLayer, at: 0)

我的图片


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接