在 UIImageView 中屏蔽甜甜圈形状
Masking a donut shape in a UIImageView
我正在尝试将甜甜圈形状切割成 UIImageView。我目前只能实现这样的圆形切割:
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
}
}
是否可以使用蒙版创建圆环形状的切口?
这比我预期的要花更多的努力,解决方案并不明显......直到我找到它,然后它就像,哦,是的,当然 :/
"basic" 的想法是,您想 "cut out" 现有路径的一部分,解决方案并不明显,因为 UIBezierPath
没有提供 "subtract" 或 "remove" 方法。相反,您需要 "reverse" 路径,例如...
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)))
而且,因为 "out-of-context" 片段很少有用,这是我用来测试它的 playground(提供自己的图像)...
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
我的结果...
绿色来自 UIImageView
所在的 backgroundView
现在,如果您更喜欢...
然后去掉第二个append
语句,path.append(UIBezierPath(ovalIn: CGRect(x: 75, y: 75, width: 50, height: 50)))
我正在尝试将甜甜圈形状切割成 UIImageView。我目前只能实现这样的圆形切割:
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
}
}
是否可以使用蒙版创建圆环形状的切口?
这比我预期的要花更多的努力,解决方案并不明显......直到我找到它,然后它就像,哦,是的,当然 :/
"basic" 的想法是,您想 "cut out" 现有路径的一部分,解决方案并不明显,因为 UIBezierPath
没有提供 "subtract" 或 "remove" 方法。相反,您需要 "reverse" 路径,例如...
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)))
而且,因为 "out-of-context" 片段很少有用,这是我用来测试它的 playground(提供自己的图像)...
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
我的结果...
绿色来自 UIImageView
所在的 backgroundView
现在,如果您更喜欢...
然后去掉第二个append
语句,path.append(UIBezierPath(ovalIn: CGRect(x: 75, y: 75, width: 50, height: 50)))