代码之家  ›  专栏  ›  技术社区  ›  Moondra

在填充的白色圆(UIButton)内创建黑色细圆(未填充)

  •  0
  • Moondra  · 技术社区  · 6 年前

    我正在尝试复制iOS设备上的默认相机按钮:

    https://www.iphonefaq.org/images/archives/photo-tip-shutter1.jpg

    我可以创建一个白色的圆形按钮,里面有黑色的按钮。但是,黑色按钮也会被填充,而不仅仅是一个薄圆圈。

    这就是我所拥有的(其中大部分都是从不同的来源复制并组合在一起的,所以代码效率不高)

    对象表示按钮,

    func applyRoundCorner(_ object: AnyObject) {
        //object.layer.shadowColor = UIColor.black.cgColor
        //object.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
        object.layer.cornerRadius = (object.frame.size.width)/2
        object.layer.borderColor = UIColor.black.cgColor
        object.layer.borderWidth = 5
        object.layer.masksToBounds = true
        //object.layer.shadowRadius = 1.0
        //object.layer.shadowOpacity = 0.5
    
        var CircleLayer   = CAShapeLayer()
        let center = CGPoint (x: object.frame.size.width / 2, y: object.frame.size.height / 2)
        let circleRadius = object.frame.size.width / 6
        let circlePath = UIBezierPath(arcCenter: center, radius: circleRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI * 2), clockwise: true)
        CircleLayer.path = circlePath.cgPath
        CircleLayer.strokeColor = UIColor.black.cgColor
        //CircleLayer.fillColor = UIColor.blue.cgColor
        CircleLayer.lineWidth = 1
        CircleLayer.strokeStart = 0
        CircleLayer.strokeEnd  = 1
        object.layer.addSublayer(CircleLayer)
    }
    
    3 回复  |  直到 6 年前
        1
  •  2
  •   Ahmad F    6 年前

    基本方法

    你可以这样做(为了演示,我将使用一个操场以编程方式完成按钮):

    let buttonWidth = 100.0
    
    let button = UIButton(frame: CGRect(x: 0, y: 0, width: buttonWidth, height: buttonWidth))
    button.backgroundColor = .white
    button.layer.cornerRadius = button.frame.width / 2
    

    绘图部分:

    因此,添加按钮并进行所需设置(使其成为圆形)后,以下是如何在其中绘制圆形的部分内容:

    let circlePath = UIBezierPath(arcCenter: CGPoint(x: buttonWidth / 2,y: buttonWidth / 2), radius: 40.0, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
    
    let circleLayer = CAShapeLayer()
    circleLayer.path = circlePath.cgPath
    circleLayer.fillColor = UIColor.clear.cgColor
    circleLayer.strokeColor = UIColor.black.cgColor
    circleLayer.lineWidth = 2.5
    
    // adding the layer into the button:
    button.layer.addSublayer(circleLayer)
    

    可能, circleLayer.fillColor = UIColor.clear.cgColor 是你错过的部分。

    因此:

    enter image description here


    回到你的案子:

    边栏提示:

    为了实现 applyRoundCorner ,我建议让它 只有 取整视图的作业,然后创建另一个函数在视图中添加圆。这是为了避免命名冲突,也就是说当我读“applyRoundCorner”的时候 假设它也会给我的视图添加圆!所以:

    func applyRoundedCorners(for view: UIView) {
        view.layer.cornerRadius = view.frame.size.width / 2
        view.layer.borderColor = UIColor.white.cgColor
        view.layer.borderWidth = 5.0
        view.layer.masksToBounds = true
    }
    
    func drawCircle(in view: UIView) {
        let circlePath = UIBezierPath(arcCenter: CGPoint(x: view.frame.size.width / 2,y: view.frame.size.width / 2),
                                                 radius: view.frame.size.width / 2.5,
                                                 startAngle: 0,
                                                 endAngle: CGFloat.pi * 2,
                                                 clockwise: true)
    
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = circlePath.cgPath
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeColor = UIColor.black.cgColor
        shapeLayer.lineWidth = 2.5
    
        button.layer.addSublayer(shapeLayer)
    }
    

    现在:

    applyRoundedCorners(for: button)
    drawCircle(in: button)
    

    看起来好多了。从另一个方面考虑,您希望使视图成为圆形 没有 在其中添加一个圆,使用分隔的方法 applyRoundedCorners(for: myView) 没有必要在里面加一个圆。


    此外:

    如你所见,我改变了 AnyObject UIView ,这似乎更符合你的情况。所以我们可以做一件很酷的事:

    extension UIView {
        func applyRoundedCorners(for view: UIView) {
            view.layer.cornerRadius = view.frame.size.width / 2
            view.layer.borderColor = UIColor.white.cgColor
            view.layer.borderWidth = 5.0
            view.layer.masksToBounds = true
        }
    
        func drawCircle(in view: UIView) {
            let circlePath = UIBezierPath(arcCenter: CGPoint(x: view.frame.size.width / 2,y: view.frame.size.width / 2),
                                          radius: view.frame.size.width / 2.5,
                                          startAngle: 0,
                                          endAngle: CGFloat.pi * 2,
                                          clockwise: true)
    
            let shapeLayer = CAShapeLayer()
            shapeLayer.path = circlePath.cgPath
            shapeLayer.fillColor = UIColor.clear.cgColor
            shapeLayer.strokeColor = UIColor.black.cgColor
            shapeLayer.lineWidth = 2.5
    
            button.layer.addSublayer(shapeLayer)
        }
    }
    

    现在两者 applyRoundedCorners drawCircle 隐式包含在 UIView公司 (这意味着 UIButton ),而不是通过 button 对于这些功能,您将能够:

    button.applyRoundedCorners()
    button.drawCircle()
    
        2
  •  1
  •   Prashant Tukadiya    6 年前

    只需添加宽度和高度较小的圆形图层

    尝试此代码

    func applyRoundCorner(_ object: UIButton) {
        object.layer.cornerRadius = (object.frame.size.width)/2
        object.layer.borderColor = UIColor.black.cgColor
        object.layer.borderWidth = 5
        object.layer.masksToBounds = true
    
        let anotherFrame = CGRect(x: 12, y: 12, width: object.bounds.width - 24, height: object.bounds.height - 24)
        let circle = CAShapeLayer()
        let path = UIBezierPath(arcCenter: object.center, radius: anotherFrame.width / 2, startAngle: 0, endAngle: .pi * 2, clockwise: true)
        circle.path = path.cgPath
        circle.strokeColor = UIColor.black.cgColor
        circle.lineWidth = 1.0
        circle.fillColor = UIColor.clear.cgColor
        object.layer.addSublayer(circle)
    }
    

    注意:根据您的要求和最佳用户体验更改帧值

    输出

    enter image description here

        3
  •  1
  •   MadProgrammer    6 年前

    我毫不怀疑有无数种不同的方法来解决这个问题,这只是一个。。。

    我从一个 UIButton 为了简单快捷,我可以考虑从 UIImage 只需设置按钮的图像属性,但这在很大程度上取决于我要实现的目标

    internal extension FloatingPoint {
        var degreesToRadians: Self { return self * .pi / 180 }
        var radiansToDegrees: Self { return self * 180 / .pi }
    }
    
    class RoundButton: UIButton {
        override func draw(_ rect: CGRect) {
            makeButtonImage()?.draw(at: CGPoint(x: 0, y: 0))
        }
    
        func makeButtonImage() -> UIImage? {
            let size = bounds.size
    
            UIGraphicsBeginImageContext(CGSize(width: size.width, height: size.height))
            defer {
                UIGraphicsEndImageContext()
            }
            guard let ctx = UIGraphicsGetCurrentContext() else {
                return nil
            }
    
            let center = CGPoint(x: size.width / 2.0, y: size.height / 2.0)
            // Want to "over fill" the image area, so the mask can be applied
            // to the entire image
            let radius = min(size.width / 2.0, size.height / 2.0)
    
            let innerRadius = radius * 0.75
            let innerCircle = UIBezierPath(arcCenter: center,
                                                                         radius: innerRadius,
                                                                         startAngle: CGFloat(0.0).degreesToRadians,
                                                                         endAngle: CGFloat(360.0).degreesToRadians,
                                                                         clockwise: true)
            // The color doesn't matter, only it's alpha level
            UIColor.red.setStroke()
            innerCircle.lineWidth = 4.0
            innerCircle.stroke(with: .normal, alpha: 1.0)
    
            let circle = UIBezierPath(arcCenter: center,
                                                                radius: radius,
                                                                startAngle: CGFloat(0.0).degreesToRadians,
                                                                endAngle: CGFloat(360.0).degreesToRadians,
                                                                clockwise: true)
            UIColor.clear.setFill()
            ctx.fill(bounds)
    
            UIColor.white.setFill()
            circle.fill(with: .sourceOut, alpha: 1.0)
    
            return UIGraphicsGetImageFromCurrentImageContext()
        }
    }
    

    注:这是 未经选择 ! 我会考虑缓存 makeButtonImage 当按钮的状态/大小改变时使其失效,但要小心

    为什么这种方法比其他方法“更好”?我只想说,这不是,但它所创造的,是一个核心圈的“剪影”

    Playground Result

    这是我的一个挑剔,但我认为它看起来更好,是一个更灵活的解决方案,因为你不需要一个内圈冲程颜色,废话,废话,废话。

    解决方案利用 CoreGraphics CGBlendMode s

    我当然可以把整件事都做进去 PaintCodeApp 就这样结束吧