简体   繁体   English

遮罩UIImageView中的甜甜圈形状

[英]Masking a donut shape in a UIImageView

I am trying to cut a donut shape into a UIImageView. 我正在尝试将甜甜圈形状切成UIImageView。 I can currently only achieve a circle cutout like so: 我目前只能像这样实现圆形切口:

import UIKit
import CoreGraphics

class AvatarImageView: UIImageView {

    enum AvatarImageViewOnlineStatus {
        case online
        case offline
        case hidden
    }

    var rounded: Bool = false
    var onlineStatus: AvatarImageViewOnlineStatus = .hidden

    override func layoutSubviews() {
        super.layoutSubviews()
        guard !rounded else { return }
        if let image = image, !rounded {
            self.image = image.af_imageRoundedIntoCircle()
            rounded = true
        }

        let rect: CGRect = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
        let maskLayer: CAShapeLayer = CAShapeLayer()
        maskLayer.frame = rect

        let mainPath: UIBezierPath = UIBezierPath(rect: rect)
        let circlePath: UIBezierPath = UIBezierPath(ovalIn: CGRect(x: 20, y: 20, width: 30, height: 30))
        mainPath.append(circlePath)

        maskLayer.fillRule = kCAFillRuleEvenOdd
        maskLayer.path = mainPath.cgPath
        maskLayer.strokeColor = UIColor.clear.cgColor
        maskLayer.lineWidth = 10.0
        layer.mask = maskLayer
    }

}

在此处输入图片说明

Is it possible to create a donut shaped cutout using masks? 是否可以使用面罩创建甜甜圈形的切口?

This took a little more effort then I was expecting and the solution wasn't obvious ... until I found it, then it was like, oh, yeah, sure :/ 这比我期望的多了一些努力,并且解决方案并不明显...直到找到它,然后,就像,哦,是的,肯定://

The "basic" idea is, you want to "cut out" a section of the an existing path, the solution wasn't obvious, because UIBezierPath doesn't provide a "subtract" or "remove" method. “基本”的想法是,您想要“切出”现有路径的一部分,解决方案并不明显,因为UIBezierPath不提供“减”或“删除”方法。 Instead, you need to "reverse" the path, for example... 相反,您需要“反转”路径,例如...

let path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 200, height: 200))
path.append(UIBezierPath(ovalIn: CGRect(x: 50, y: 50, width: 100, height: 100)).reversing())
path.append(UIBezierPath(ovalIn: CGRect(x: 75, y: 75, width: 50, height: 50)))

And, because "out-of-context" snippets are rarely helpful, this is the playground I used to test it (supply own image)... 而且,由于“上下文外”片段很少有帮助,因此这是我用来测试它的操场(提供自己的图像)...

import UIKit
import Foundation
import CoreGraphics

let image = UIImage(named: "Profile")
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
let backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
backgroundView.backgroundColor = UIColor.green
backgroundView.addSubview(imageView)

imageView.contentMode = .scaleAspectFit
imageView.image = image
imageView.layer.cornerRadius = 100

let shapeLayer = CAShapeLayer()

let path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 200, height: 200))
path.append(UIBezierPath(ovalIn: CGRect(x: 50, y: 50, width: 100, height: 100)).reversing())
path.append(UIBezierPath(ovalIn: CGRect(x: 75, y: 75, width: 50, height: 50)))

shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor.red.cgColor
shapeLayer.frame = imageView.bounds

imageView.layer.mask = shapeLayer
backgroundView

And my results... 我的结果

这些是您要寻找的机器人

The green color is from the backgroundView on which the UIImageView resides 绿色来自UIImageView所在的backgroundView

Now, if you would prefer something more like... 现在,如果您更喜欢...

我看不到这头盔的任何东西

Then just get rid of the second append statement, path.append(UIBezierPath(ovalIn: CGRect(x: 75, y: 75, width: 50, height: 50))) 然后只需摆脱第二条append语句path.append(UIBezierPath(ovalIn: CGRect(x: 75, y: 75, width: 50, height: 50)))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM