Ios 如何使用遮罩为圆形图像添加边框

Ios 如何使用遮罩为圆形图像添加边框,ios,swift,mask,cashapelayer,Ios,Swift,Mask,Cashapelayer,这是我的尝试: func round() { let width = bounds.width < bounds.height ? bounds.width : bounds.height let mask = CAShapeLayer() mask.path = UIBezierPath(ovalInRect: CGRectMake(bounds.midX - width / 2, bounds.midY - width / 2, width, width)).C

这是我的尝试:

func round() {
    let width = bounds.width < bounds.height ? bounds.width : bounds.height
    let mask = CAShapeLayer()
    mask.path = UIBezierPath(ovalInRect: CGRectMake(bounds.midX - width / 2, bounds.midY - width / 2, width, width)).CGPath

    self.layer.mask = mask

    // add border
    let frameLayer = CAShapeLayer()
    frameLayer.path = mask.path
    frameLayer.lineWidth = 4.0
    frameLayer.strokeColor = UIColor.whiteColor().CGColor
    frameLayer.fillColor = nil

    self.layer.addSublayer(frameLayer)
}
func round(){
设width=bounds.width
它在iphone 6模拟器上工作(故事板大小为4.7),但在5s和6+上看起来很奇怪:

这是自动布局问题吗?如果没有边框,自动布局工作正常。这是我第一次使用口罩,所以我不确定我所做的是否正确

round
函数在
viewdilayoutsubviews
中调用


有什么想法吗?

最简单的方法是操纵图像视图本身的

imageView.layer.cornerRadius = imageView.bounds.size.width / 2.0
imageView.layer.borderWidth = 2.0
imageView.layer.borderColor = UIColor.whiteColor.CGColor
imageView.layer.masksToBounds = true
您可以在
viewDidLayoutSubviews
layoutSubviews
中包含此项,以确保大小始终正确


注:也许这项技术会让你的圆圈面具过时;-)。根据经验,始终选择最简单的解决方案。

例如,如果您有子类
UIImageView
,您可以覆盖
layoutSubviews
,以便它(a)更新掩码;(b) 删除任何旧边界;和(c)添加新边界。在Swift 3中:

import UIKit

@IBDesignable
class RoundedImageView: UIImageView {

    /// saved rendition of border layer

    private weak var borderLayer: CAShapeLayer?

    override func layoutSubviews() {
        super.layoutSubviews()

        // create path

        let width = min(bounds.width, bounds.height)
        let path = UIBezierPath(arcCenter: CGPoint(x: bounds.midX, y: bounds.midY), radius: width / 2, startAngle: 0, endAngle: .pi * 2, clockwise: true)

        // update mask and save for future reference

        let mask = CAShapeLayer()
        mask.path = path.cgPath
        layer.mask = mask

        // create border layer

        let frameLayer = CAShapeLayer()
        frameLayer.path = path.cgPath
        frameLayer.lineWidth = 32.0
        frameLayer.strokeColor = UIColor.white.cgColor
        frameLayer.fillColor = nil

        // if we had previous border remove it, add new one, and save reference to new one

        borderLayer?.removeFromSuperlayer()
        layer.addSublayer(frameLayer)
        borderLayer = frameLayer
    }
}
这样,它可以响应布局的变化,但可以确保清除任何旧的边界

顺便说一下,如果您不是子类化
UIImageView
,而是将此逻辑放在视图控制器中,那么您将覆盖
UIView的
viewWillLayoutSubviews
,而不是
UIView的
layoutSubviews
。但基本想法是一样的

--

顺便说一下,我将遮罩与此形状层结合使用,因为如果仅应用
UIView
的圆角,可能会产生奇怪的瑕疵(请看圆形边框下部非常细的灰线):

如果使用贝塞尔路径方法,则不会产生此类瑕疵:


对于Swift 2.3示例,请参见。

阅读
viewDidLayoutSubviews
的描述,它告诉您何时调用该方法,并且它看起来并不适合您想要实现的目标。我的替代方法是什么?创建视图类的子类,存储对添加的路径和层的引用,当检测到尺寸变化时修改它们(使用
layoutSubviews
),以后再使用它。你能给我举个例子吗?我是新手。我用过这个,但是自动布局有很多问题,所以你应该用这个来解决你的自动布局问题。我要添加
imageView.layer.masksToBounds=true
。我用这个解决方案来处理cornerRadius,还设置了masktoBounds=true,但是我的图像在不同的屏幕上运行时需要调整大小,并且有很多问题,我无法解决它们,所以我说我应该尝试掩蔽。
cornerRadius
方法是臭名昭著的,因为当你仔细观察角落时,会引入不需要的瑕疵。我建议修复
UIBezierPath
方法(如上面评论中的A-Live建议的那样)。这是一个多么好的答案。这解决了我所有的问题。非常感谢。工作顺利,但我们不能用画法吗?哇。回答得很好。SA上有太多类似的问题没有解决这个问题。@NikhilManapure-是的,你可以在方法中手动屏蔽和渲染,但我们通常避免这样做,因为理论上我们会丢失苹果实现的任何优化/功能。此外,这是一种通用机制,您可以使用它,而不必考虑视图的类型或它可能具有的任何子视图。