您可以使用 QuadCurve 获得您想要的设计。
这是一个 Swift @IBDesignable 类,可让您在 Storyboard / Interface Builder 中指定图像和舍入的“高度”:
@IBDesignable
class RoundedBottomImageView: UIView {
var imageView: UIImageView!
@IBInspectable var image: UIImage? {
didSet { self.imageView.image = image }
}
@IBInspectable var roundingValue: CGFloat = 0.0 {
didSet {
self.setNeedsLayout()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
doMyInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
doMyInit()
}
func doMyInit() {
imageView = UIImageView()
imageView.backgroundColor = UIColor.red
imageView.contentMode = UIViewContentMode.scaleAspectFill
addSubview(imageView)
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = self.bounds
let rect = self.bounds
let y:CGFloat = rect.size.height - roundingValue
let curveTo:CGFloat = rect.size.height + roundingValue
let myBezier = UIBezierPath()
myBezier.move(to: CGPoint(x: 0, y: y))
myBezier.addQuadCurve(to: CGPoint(x: rect.width, y: y), controlPoint: CGPoint(x: rect.width / 2, y: curveTo))
myBezier.addLine(to: CGPoint(x: rect.width, y: 0))
myBezier.addLine(to: CGPoint(x: 0, y: 0))
myBezier.close()
let maskForPath = CAShapeLayer()
maskForPath.path = myBezier.cgPath
layer.mask = maskForPath
}
}
300 x 200 图像视图的结果,四舍五入设置为 40:
编辑 - (3.5 年后)...
要回答@MiteshDobareeya 的评论,我们可以通过变换贝塞尔路径将圆边从底部切换到顶部:
let c = CGAffineTransform(scaleX: 1, y: -1).concatenating(CGAffineTransform(translationX: 0, y: bounds.size.height))
myBezier.apply(c)
自从最初发布此答案以来已经有一段时间了,因此进行了一些更改:
- 直接子类
UIImageView - 无需将其设为UIView 并嵌入UIImageView
- 添加一个布尔值
roundTop var
- 如果设置为 False(默认),我们将底部舍入
- 如果设置为 True,我们会舍入顶部
- 为了清楚起见,重新排序并“命名”我们的路径点
那么,基本原理:
我们创建一个UIBezierPath 并且:
- 移至
pt1
- 添加一行到
pt2
- 在
pt3添加一行
- 用
controlPoint 向pt4 添加四边形曲线
- 关闭路径
- 使用该路径作为
CAShapeLayer 掩码
结果:
如果我们想要圆顶,在关闭路径后,我们可以应用scale 转换,使用-1 作为y 值来垂直镜像它。因为该变换将其镜像到“y 零”,所以我们还应用 translate 变换将其向下移动到原位。
这给了我们:
这是更新后的课程:
@IBDesignable
class RoundedTopBottomImageView: UIImageView {
@IBInspectable var roundingValue: CGFloat = 0.0 {
didSet {
self.setNeedsLayout()
}
}
@IBInspectable var roundTop: Bool = false {
didSet {
self.setNeedsLayout()
}
}
override func layoutSubviews() {
super.layoutSubviews()
let r = bounds
let myBezier = UIBezierPath()
let pt1: CGPoint = CGPoint(x: r.minX, y: r.minY)
let pt2: CGPoint = CGPoint(x: r.maxX, y: r.minY)
let pt3: CGPoint = CGPoint(x: r.maxX, y: r.maxY - roundingValue)
let pt4: CGPoint = CGPoint(x: r.minX, y: r.maxY - roundingValue)
let controlPoint: CGPoint = CGPoint(x: r.midX, y: r.maxY + roundingValue)
myBezier.move(to: pt1)
myBezier.addLine(to: pt2)
myBezier.addLine(to: pt3)
myBezier.addQuadCurve(to: pt4, controlPoint: controlPoint)
myBezier.close()
if roundTop {
// if we want to round the Top instead of the bottom,
// flip the path vertically
let c = CGAffineTransform(scaleX: 1, y: -1) //.concatenating(CGAffineTransform(translationX: 0, y: bounds.size.height))
myBezier.apply(c)
}
let maskForPath = CAShapeLayer()
maskForPath.path = myBezier.cgPath
layer.mask = maskForPath
}
}