【问题标题】:Corner radius image Swift角半径图像 Swift
【发布时间】:2018-12-28 21:58:00
【问题描述】:

我正在尝试制作这个圆角半径图像...它与图像的形状不完全相同...任何简单的答案而不是尝试随机数的宽度和高度? 非常感谢

 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

【问题讨论】:

  • 转到 wolframalpha.com 并输入center of circle through points (3, 0), (0, 3), and (0,-3),它会告诉您圆的半径和圆心。当然用你自己的观点代替。

标签: ios iphone swift uiimageview


【解决方案1】:

您可以使用 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添加一行
  • controlPointpt4 添加四边形曲线
  • 关闭路径
  • 使用该路径作为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
    }
    
}

【讨论】:

  • 请我将图像视图拖到情节提要并使其类为“RoundedBottomImageView”,但它根据代码中编写的红色背景在模拟器中为我提供了红色图像...你能解释一下代码吗请问?
  • 这是一个UIView 子类,而不是UIImageView
  • @DonMag 你能告诉我顶部的情况吗?
  • @MiteshDobareeya - 这对你来说真的是一个很好的学习练习,而不仅仅是要求改变。请参阅我的答案的编辑,这应该会让您更容易理解发生了什么。我鼓励您阅读说明并检查要点插图,并尝试自己进行更改...然后检查我更新的课程。
  • @DonMag 感谢您添加详细说明。我没有使用比例变换,而是通过改变 addLine 中的 Y 轴值来实现。
【解决方案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
    }
}

& 在viewWillAppear 中使用它,您可以获得 UIImageView 的实际框架。

用法:

 override func viewWillAppear(_ animated: Bool) {
    //use it in viewWillAppear like methods where you can get actual frame of UIImageView
      myImageView.setBottomCurve()
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-08
    • 2023-04-01
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    相关资源
    最近更新 更多