Swift - 如何创建其中裁剪形状的视图

Swift - How to create a view with a shape cropped in it

我正在尝试使用 swift 1.2 和 xcode 6 获得图中显示的结果。

基本上我想创建一个带有形状切割的视图,以便能够看到下面的视图来为我的应用程序制作教程。 我知道如何创建圆形,但我不知道如何在视图中将其剪掉。 我需要一个完整的示例来说明如何操作。 提前致谢

执行此操作的最简单方法是创建一个 png 图像,其外部为部分透明的白色,中间为透明圆圈。然后将 2 个图像视图堆叠在一起,遮罩图像在顶部,并将其“不透明”标志设置为 false。

您也可以通过创建一个 CAShapeLayer 并将其设置为使用半透明的白色来实现此目的,然后安装一个形状,该形状是从其形状中切出孔的正方形。您将该形状层安装在图像视图层的顶部。

最通用的方法是创建 UIImageView 的自定义子类,并让子类的 init 方法创建和安装形状层。我昨天刚刚创建了一个要点,说明了创建 UIImageView 的自定义子类。这是 link:ImageViewWithGradient gist

该要点创建了一个渐变图层。让它适应创建一个形状层将是一件简单的事情,如果你修改了 layoutSubviews 方法,你可以让它在图像视图调整大小时适应视图和路径。

编辑:

好的,我采取了额外的步骤来创建一个创建裁剪图像视图的游乐场。您可以在 ImageViewWithMask on github

找到它

我的游乐场生成的图像如下所示:

以下是如何为 UIView 制作圆形遮罩的示例代码:

let sampleView = UIView(frame: UIScreen.mainScreen().bounds)
let maskLayer = CALayer()
maskLayer.frame = sampleView.bounds
let circleLayer = CAShapeLayer()
//assume the circle's radius is 100
circleLayer.frame = CGRectMake(sampleView.center.x - 100, sampleView.center.y - 100, 200, 200)
let circlePath = UIBezierPath(ovalInRect: CGRectMake(0, 0, 200, 200))
circleLayer.path = circlePath.CGPath
circleLayer.fillColor = UIColor.blackColor().CGColor
maskLayer.addSublayer(circleLayer)

sampleView.layer.mask = maskLayer

这是我在操场上做的:

虽然有答案,但我想分享我的方法:

// Let's say that you have an outlet to the image view called imageView
// Create the white view 
let whiteView = UIView(frame: imageView.bounds) 
let maskLayer = CAShapeLayer() //create the mask layer

// Set the radius to 1/3 of the screen width
let radius : CGFloat = imageView.bounds.width/3 

// Create a path with the rectangle in it.
let path = UIBezierPath(rect: imageView.bounds)
// Put a circle path in the middle
path.addArcWithCenter(imageView.center, radius: radius, startAngle: 0.0, endAngle: CGFloat(2*M_PI), clockwise: true)

// Give the mask layer the path you just draw
maskLayer.path = path.CGPath
// Fill rule set to exclude intersected paths
maskLayer.fillRule = kCAFillRuleEvenOdd

// By now the mask is a rectangle with a circle cut out of it. Set the mask to the view and clip.
whiteView.layer.mask = maskLayer
whiteView.clipsToBounds = true

whiteView.alpha = 0.8
whiteView.backgroundColor = UIColor.whiteColor()

//If you are in a VC add to the VC's view (over the image)
view.addSubview(whiteView)    
// Annnnnd you're done.
class MakeTransparentHoleOnOverlayView: UIView {

    @IBOutlet weak var transparentHoleView: UIView!

    // MARK: - Drawing

    override func draw(_ rect: CGRect) {
        super.draw(rect)

        if self.transparentHoleView != nil {
            // Ensures to use the current background color to set the filling color
            self.backgroundColor?.setFill()
            UIRectFill(rect)

            let layer = CAShapeLayer()
            let path = CGMutablePath()

            // Make hole in view's overlay
            // NOTE: Here, instead of using the transparentHoleView UIView we could use a specific CFRect location instead...
            path.addRect(transparentHoleView.frame)
            path.addRect(bounds)

            layer.path = path
            layer.fillRule = kCAFillRuleEvenOdd
            self.layer.mask = layer
        }
    }

    override func layoutSubviews () {
        super.layoutSubviews()
    }

    // MARK: - Initialization

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }
}
    //assume you create a UIImageView and content image before execute this code
  let sampleMask = UIView()
    sampleMask.frame = self.view.frame
    sampleMask.backgroundColor =  UIColor.black.withAlphaComponent(0.6)
    //assume you work in UIViewcontroller
    self.view.addSubview(sampleMask)
    let maskLayer = CALayer()
    maskLayer.frame = sampleMask.bounds
    let circleLayer = CAShapeLayer()
    //assume the circle's radius is 150
    circleLayer.frame = CGRect(x:0 , y:0,width: sampleMask.frame.size.width,height: sampleMask.frame.size.height)
    let finalPath = UIBezierPath(roundedRect: CGRect(x:0 , y:0,width: sampleMask.frame.size.width,height: sampleMask.frame.size.height), cornerRadius: 0)
    let circlePath = UIBezierPath(ovalIn: CGRect(x:sampleMask.center.x - 150, y:sampleMask.center.y - 150, width: 300, height: 300))
    finalPath.append(circlePath.reversing())
    circleLayer.path = finalPath.cgPath
    circleLayer.borderColor = UIColor.white.withAlphaComponent(1).cgColor
     circleLayer.borderWidth = 1
    maskLayer.addSublayer(circleLayer)

    sampleMask.layer.mask = maskLayer