提问人:ema so 提问时间:7/20/2018 最后编辑:Ashley Millsema so 更新时间:1/3/2022 访问量:596
圆角半径图像 Swift
Corner radius image Swift
问:
我正在尝试制作这个圆角半径图像......它与图像的形状不完全相同。有什么简单的答案而不是尝试宽度和高度的随机数字吗? 多谢
let rectShape = CAShapeLayer()
rectShape.bounds = self.mainImg.frame
rectShape.position = self.mainImg.center
rectShape.path = UIBezierPath(roundedRect: self.mainImg.bounds, byRoundingCorners: [.bottomLeft , .bottomRight ], cornerRadii: CGSize(width: 50, height: 4)).cgPath
答:
4赞
DonMag
7/20/2018
#1
您可以使用 QuadCurve 来获得所需的设计。
下面是一个 Swift 类,它允许您在 Storyboard / Interface Builder 中指定图像和舍入的“高度”:@IBDesignable
@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
- 添加 Bool 变量
roundTop
- 如果设置为 False(默认值),则将 Bottom 四舍五入
- 如果设置为 True,则将顶部四舍五入
- 重新排序和“命名”我们的路径点,以便清晰
所以,基本原理:
我们创建一个和:UIBezierPath
- 移至
pt1
- 添加一行
pt2
- 添加一行
pt3
- 将四曲线添加到
pt4
controlPoint
- 关闭路径
- 将该路径用于蒙版
CAShapeLayer
结果:
如果我们想对顶部进行圆角,在关闭路径后,我们可以应用应用变换,将其用作垂直镜像的值。由于该变换将其镜像为“y-zero”,因此我们还应用了变换将其移回原位。scale
-1
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
}
}
评论
0赞
ema so
7/21/2018
请我把一个图像视图拖到故事板上,并制作了它的类'RoundedBottomImageView',但它根据代码中写的红色背景在模拟器中给了我一个红色图像......你能解释一下代码吗?
0赞
DonMag
7/21/2018
它是一个子类,而不是.UIView
UIImageView
0赞
Mitesh Dobareeya
1/3/2022
@DonMag 你能告诉我顶部的相同情况吗?
0赞
DonMag
1/3/2022
@MiteshDobareeya - 这对你来说真的是一个很好的学习练习,而不仅仅是要求改变。请参阅编辑我的答案,这应该使您更容易理解正在发生的事情。我鼓励您阅读说明并检查点插图,并尝试自己进行更改......然后检查我更新的类。
0赞
Mitesh Dobareeya
1/3/2022
@DonMag 感谢您添加详细说明。我没有使用比例转换,而是通过更改 addLine 中的 Y 轴值来实现。
0赞
Jack
7/22/2018
#2
您可以尝试使用扩展。如UIView
extension UIView {
func setBottomCurve(){
let offset = CGFloat(self.frame.size.height + self.frame.size.height/1.8)
let bounds = self.bounds
let rectBounds = CGRect(x: bounds.origin.x,
y: bounds.origin.y ,
width: bounds.size.width,
height: bounds.size.height / 2)
let rectPath = UIBezierPath(rect: rectBounds)
let ovalBounds = CGRect(x: bounds.origin.x - offset / 2,
y: bounds.origin.y ,
width: bounds.size.width + offset,
height: bounds.size.height)
let ovalPath = UIBezierPath(ovalIn: ovalBounds)
rectPath.append(ovalPath)
let maskLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = rectPath.cgPath
self.layer.mask = maskLayer
}
}
& 在类似的方法中使用它,您可以在其中获取 UIImageView 的实际帧。viewWillAppear
用法:
override func viewWillAppear(_ animated: Bool) {
//use it in viewWillAppear like methods where you can get actual frame of UIImageView
myImageView.setBottomCurve()
}
评论
center of circle through points (3, 0), (0, 3), and (0,-3)