您可以使用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
的结果:
![enter image description here](https://istack.dev59.com/0aSmQ.webp)
编辑 - (3.5 年后)...
回答 @MiteshDobareeya 的评论,我们可以通过变换贝塞尔路径将圆角从底部变为顶部:
let c = CGAffineTransform(scaleX: 1, y: -1).concatenating(CGAffineTransform(translationX: 0, y: bounds.size.height))
myBezier.apply(c)
这个答案最初发布已经有一段时间了,所以有一些更改:
- 直接继承
UIImageView
- 不需要用嵌入的UIImageView
来制作一个UIView
- 添加一个布尔变量
roundTop
- 如果设置为False(默认值),我们将圆角应用在底部
- 如果设置为True,则我们将圆角应用在顶部
- 重新排序和“命名”路径点以增加清晰度
所以,基本原理是:
![enter image description here](https://istack.dev59.com/utzEF.webp)
我们创建一个UIBezierPath
并:
- 移动到
pt1
- 添加一条线到
pt2
- 添加一条线到
pt3
- 使用
controlPoint
添加一个二次曲线到pt4
- 关闭路径
- 使用该路径进行
CAShapeLayer
遮罩
结果如下:
![enter image description here](https://istack.dev59.com/QhGvR.webp)
如果我们想要圆角应用在顶部,在关闭路径后,我们可以应用一个scale
变换,使用-1
作为y
值进行垂直镜像。因为该变换在“y-zero”处镜像它,所以我们还要应用一个translate
变换将其移回到原位。
这给了我们:
![enter image description here](https://istack.dev59.com/nTOeZ.webp)
以下是更新后的类:
@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 {
let c = CGAffineTransform(scaleX: 1, y: -1)
myBezier.apply(c)
}
let maskForPath = CAShapeLayer()
maskForPath.path = myBezier.cgPath
layer.mask = maskForPath
}
}