[英]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.