在我的应用程序中,我有一个方形UIView,我想从顶部切出一个洞/缺口。在线的所有教程都是一样的,看起来很简单,但是每一个教程总是与我想要的完全相反。
例如,这是自定义UIView的代码:
class BottomOverlayView: UIView {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
drawCircle()
}
fileprivate func drawCircle(){
let circleRadius: CGFloat = 80
let topMidRectangle = CGRect(x: 0, y: 0, width: circleRadius*2, height: circleRadius*2)
let circle: CAShapeLayer = CAShapeLayer()
circle.position = CGPoint(x: (frame.width/2)-circleRadius, y: 0-circleRadius)
circle.fillColor = UIColor.black.cgColor
circle.path = UIBezierPath(ovalIn: topMidRectangle).cgPath
circle.fillRule = kCAFillRuleEvenOdd
self.layer.mask = circle
self.clipsToBounds = true
}
}
这是我希望实现的目标(浅蓝色是UIView,深蓝色是背景):
但这是我得到的。 (无论我尝试什么,每一次)
我不确定如何实现这一点,除了制作一个已经是我需要的确切形状的面具。但如果我能够做到这一点,那么我首先就不会遇到这个问题。有没有人知道如何实现这个目标?
编辑:这个问题应该是我已经尝试过并且无法正常工作的问题。也许我做错了或在错误的环境中使用它。我不熟悉任何给定的方法,并且使用指针使它看起来有点过时。接受的答案可以更好地解释如何使用更广泛使用的UIBezierPaths以及在自定义UIView的上下文中实现这一点。
答案 0 :(得分:6)
我建议为你的面具画一条路径,例如:在Swift 3中
// BottomOverlayView.swift
import UIKit
@IBDesignable
class BottomOverlayView: UIView {
@IBInspectable
var radius: CGFloat = 100 { didSet { updateMask() } }
override func layoutSubviews() {
super.layoutSubviews()
updateMask()
}
private func updateMask() {
let path = UIBezierPath()
path.move(to: bounds.origin)
let center = CGPoint(x: bounds.midX, y: bounds.minY)
path.addArc(withCenter: center, radius: radius, startAngle: .pi, endAngle: 0, clockwise: false)
path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
path.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))
path.close()
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
注意,我调整了这个以在两个地方设置掩码:
来自layoutSubviews
:这样,如果框架发生变化,例如自动布局(或通过手动更改frame
或其他),它会相应更新;以及
如果您更新radius
:这样,如果您在故事板中使用此功能,或者以编程方式更改半径,则会反映出此更改。
所以,你可以在深蓝色BottomOverlayView
上覆盖半高,浅蓝色UIView
,如下所示:
产量:
如果你想使用"切一个洞"在重复答案中建议的技术,updateMask
方法将是:
private func updateMask() {
let center = CGPoint(x: bounds.midX, y: bounds.minY)
let path = UIBezierPath(rect: bounds)
path.addArc(withCenter: center, radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
let mask = CAShapeLayer()
mask.fillRule = .evenOdd
mask.path = path.cgPath
layer.mask = mask
}
我个人发现路径中的奇偶规则路径有点违反直觉。在我可以的地方(比如这种情况),我只想画出面具的路径。但是如果你需要一个带有切口的面具,这种偶数填充规则方法会很有用。