如何创建一个内部带有透明圆圈的UIView(在swift中)?

时间:2015-02-11 07:24:46

标签: ios swift uiview uikit

我想创建一个如下所示的视图:Goal View

我认为我需要的是带有某种面具的uiview,我可以使用UIBezier路径制作一个圆形的面具,但是我无法反转这样做,以便它除了圆圈之外的所有内容。我需要这个是视图的掩码,而不是填充层,因为我打算掩盖的视图上有一个UIBlurEffect。最终目标是动画这个UIView超越我现有的视图来提供指导。

请注意我使用的是swift。有没有办法做到这一点?如果是这样,怎么样?

4 个答案:

答案 0 :(得分:40)

您可以使用此功能创建所需内容。

func createOverlay(frame : CGRect)
{
    let overlayView = UIView(frame: frame)
    overlayView.alpha = 0.6
    overlayView.backgroundColor = UIColor.blackColor()
    self.view.addSubview(overlayView)

    let maskLayer = CAShapeLayer()

    // Create a path with the rectangle in it.
    var path = CGPathCreateMutable()

    let radius : CGFloat = 50.0
    let xOffset : CGFloat = 10
    let yOffset : CGFloat = 10

    CGPathAddArc(path, nil, overlayView.frame.width - radius/2 - xOffset, yOffset, radius, 0.0, 2 * 3.14, false)
    CGPathAddRect(path, nil, CGRectMake(0, 0, overlayView.frame.width, overlayView.frame.height))


    maskLayer.backgroundColor = UIColor.blackColor().CGColor

    maskLayer.path = path;
    maskLayer.fillRule = kCAFillRuleEvenOdd

    // Release the path since it's not covered by ARC.
    overlayView.layer.mask = maskLayer
    overlayView.clipsToBounds = true
}

调整radiusxOffset以及yOffset以更改圆的半径和位置。

答案 1 :(得分:27)

再次更新Swift 4&删除了一些项目以使代码更紧密。

请注意 maskLayer.fillRule 在Swift 4和Swift 4.2之间设置不同。

func createOverlay(frame: CGRect,
                   xOffset: CGFloat,
                   yOffset: CGFloat,
                   radius: CGFloat) -> UIView {
    // Step 1
    let overlayView = UIView(frame: frame)
    overlayView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
    // Step 2
    let path = CGMutablePath()
    path.addArc(center: CGPoint(x: xOffset, y: yOffset),
                radius: radius,
                startAngle: 0.0,
                endAngle: 2.0 * .pi,
                clockwise: false)
    path.addRect(CGRect(origin: .zero, size: overlayView.frame.size))
    // Step 3
    let maskLayer = CAShapeLayer()
    maskLayer.backgroundColor = UIColor.black.cgColor
    maskLayer.path = path
    // For Swift 4.0
    maskLayer.fillRule = kCAFillRuleEvenOdd
    // For Swift 4.2
    maskLayer.fillRule = .evenOdd
    // Step 4
    overlayView.layer.mask = maskLayer
    overlayView.clipsToBounds = true

    return overlayView
}

对正在发生的事情进行粗略分析:

  1. 创建一个大小适合指定框架的视图,黑色背景设置为60%不透明度
  2. 使用提供的起点和半径
  3. 创建绘制圆的路径
  4. 为要删除的区域创建掩码
  5. 涂抹面膜&剪辑到界限
  6. 以下代码段会调用此代码,并在半径为50的屏幕中间放置一个圆圈:

    let overlay = createOverlay(frame: view.frame,
                                xOffset: view.frame.midX,
                                yOffset: view.frame.midY,
                                radius: 50.0)
    view.addSubview(overlay)
    

    看起来像这样: enter image description here

答案 2 :(得分:17)

对于Swift 3,这里是rakeshbs的答案格式化,所以它返回所需的UIView:

func createOverlay(frame : CGRect, xOffset: CGFloat, yOffset: CGFloat, radius: CGFloat) -> UIView
{
    let overlayView = UIView(frame: frame)
    overlayView.alpha = 0.6
    overlayView.backgroundColor = UIColor.black

    // Create a path with the rectangle in it.
    let path = CGMutablePath()
    path.addArc(center: CGPoint(x: xOffset, y: yOffset), radius: radius, startAngle: 0.0, endAngle: 2 * 3.14, clockwise: false)
    path.addRect(CGRect(x: 0, y: 0, width: overlayView.frame.width, height: overlayView.frame.height))

    let maskLayer = CAShapeLayer()
    maskLayer.backgroundColor = UIColor.black.cgColor
    maskLayer.path = path;
    maskLayer.fillRule = kCAFillRuleEvenOdd

    // Release the path since it's not covered by ARC.
    overlayView.layer.mask = maskLayer
    overlayView.clipsToBounds = true

    return overlayView
}

答案 3 :(得分:0)

上述解决方案效果很好。

如果要查找具有矩形区域的蒙版,这是下面的代码段

let fWidth = self.frame.size.width
let fHeight = self.frame.size.height
let squareWidth = fWidth/2
let topLeft = CGPoint(x: fWidth/2-squareWidth/2, y: fHeight/2-squareWidth/2)
let topRight = CGPoint(x: fWidth/2+squareWidth/2, y: fHeight/2-squareWidth/2)
let bottomLeft = CGPoint(x: fWidth/2-squareWidth/2, y: fHeight/2+squareWidth/2)
let bottomRight = CGPoint(x: fWidth/2+squareWidth/2, y: fHeight/2+squareWidth/2)
let cornerWidth = squareWidth/4


// Step 2
let path = CGMutablePath()
path.addRoundedRect(in: CGRect(x: topLeft.x, y: topLeft.y,
  width: topRight.x - topLeft.x, height: bottomLeft.y - topLeft.y),
 cornerWidth: 20, cornerHeight: 20)


path.addRect(CGRect(origin: .zero, size: self.frame.size))
// Step 3
let maskLayer = CAShapeLayer()
maskLayer.backgroundColor = UIColor.clear.cgColor
maskLayer.path = path
// For Swift 4.0
maskLayer.fillRule = kCAFillRuleEvenOdd
// For Swift 4.2
//maskLayer.fillRule = .evenOdd
// Step 4
self.layer.mask = maskLayer
self.clipsToBounds = true

rectangle mask looks like this