Ios 使用Beizepath在UIView上绘制形状?

Ios 使用Beizepath在UIView上绘制形状?,ios,swift,uiview,Ios,Swift,Uiview,如何绘制背景路径,如下图所示 我在试着自己,但没有安全地来 下面是我的代码: public class ShapeView : UIView{ public override func draw(_ rect: CGRect) { let context = UIGraphicsGetCurrentContext()! let corneRadius : CGFloat = 40.0 //// Color Declar

如何绘制背景路径,如下图所示

我在试着自己,但没有安全地来

下面是我的代码:

public class ShapeView : UIView{
    public override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()!
        
        let corneRadius : CGFloat = 40.0

        //// Color Declarations
        let fillColor = UIColor(red: 0.125, green: 0.259, blue: 0.443, alpha: 1.000)
        let fillColor2 = UIColor(red: 0.153, green: 0.314, blue: 0.525, alpha: 1.000)

        //// g10
        //// g12
        //// path14 Drawing
        context.saveGState()
        context.translateBy(x: rect.origin.x, y: rect.origin.y)
//        context.rotate(by: 0.8 * CGFloat.pi/180)

        let path14Path = UIBezierPath(roundedRect: CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.size.width, height: rect.size.height), cornerRadius: CGFloat(corneRadius))
        fillColor.setFill()
        path14Path.fill()

        context.restoreGState()


        //// g16
        //// g18
        //// g24
        //// path30 Drawing


        //// path32 Drawing
//        let path32Path = UIBezierPath()
//        path32Path.move(to: CGPoint(x: 0, y:0))
////        path32Path.addLine(to: CGPoint(x: 5.15, y: corneRadius))
////        path32Path.addCurve(to: CGPoint(x: corneRadius + 5 , y: 0), controlPoint1: CGPoint(x: corneRadius + 5 , y: corneRadius ), controlPoint2: CGPoint.zero)
////        path32Path.addCurve(to: CGPoint(x: 50.59, y: 5.01), controlPoint1: CGPoint(x: 50.53, y: 5.01), controlPoint2: CGPoint(x: 50.56, y: 5.01))
//        path32Path.addLine(to: CGPoint(x: rect.width * 0.3, y: 0))  // top left x and y position of first shape
//        path32Path.addLine(to: CGPoint(x: 0, y: rect.height * 0.5))
//        path32Path.close()
//        fillColor2.setFill()
//        path32Path.fill()
        
        
//        let path14Path = UIBezierPath(roundedRect: CGRect(x: -321.25, y: -190.1, width: 642.5, height: 380.2), cornerRadius: 44.6)

        
//        let path30Path = UIBezierPath()
//        path30Path.move(to: CGPoint(x: 182.31, y: 385.45))
//        path30Path.addLine(to: CGPoint(x: 45.15, y: 385.16))
//        path30Path.addCurve(to: CGPoint(x: 17.03, y: 374.93), controlPoint1: CGPoint(x: 34.43, y: 385.13), controlPoint2: CGPoint(x: 24.65, y: 381.31))
//        path30Path.addLine(to: CGPoint(x: 329.68, y: 5.61))
//        path30Path.addLine(to: CGPoint(x: 503.55, y: 5.99))
//        path30Path.addLine(to: CGPoint(x: 182.31, y: 385.45))
//        path30Path.close()
//        fillColor2.setFill()
//        path30Path.fill()
        
        
        
        
        let path30Path = UIBezierPath()
        path30Path.move(to: CGPoint(x: rect.width * 0.5, y: rect.height - 10))
        path30Path.addLine(to: CGPoint(x: 10, y: rect.height  -  10 ))
//        path30Path.addCurve(to: CGPoint(x: corneRadius , y: 374.93), controlPoint1: CGPoint(x: rect.width * 0.5 * 2, y: 385.13), controlPoint2: CGPoint(x: rect.width * 0.5, y: 381.31))
        
        path30Path.addLine(to: CGPoint(x: rect.width * 0.8, y: 0))
        path30Path.addLine(to: CGPoint(x: rect.width * 0.35, y: rect.height))
        path30Path.addLine(to: CGPoint(x: rect.width * 0.5, y: rect.height ))

        path30Path.close()
        fillColor2.setFill()
        path30Path.fill()

        


        //// path34 Drawing
//        let path34Path = UIBezierPath()
//        path34Path.move(to: CGPoint(x: 283.03, y: 385.67))
//        path34Path.addLine(to: CGPoint(x: 208.2, y: 385.51))
//        path34Path.addLine(to: CGPoint(x: 529.44, y: 6.04))
//        path34Path.addLine(to: CGPoint(x: 603.49, y: 6.2))
//        path34Path.addCurve(to: CGPoint(x: 604.26, y: 6.21), controlPoint1: CGPoint(x: 603.75, y: 6.2), controlPoint2: CGPoint(x: 604.01, y: 6.21))
//        path34Path.addLine(to: CGPoint(x: 283.03, y: 385.67))
//        path34Path.close()
//        fillColor2.setFill()
//        path34Path.fill()
//
//
//        //// path36 Drawing
//        let path36Path = UIBezierPath()
//        path36Path.move(to: CGPoint(x: 522.68, y: 386.19))
//        path36Path.addLine(to: CGPoint(x: 447.85, y: 386.03))
//        path36Path.addLine(to: CGPoint(x: 646.21, y: 151.71))
//        path36Path.addLine(to: CGPoint(x: 644.92, y: 241.79))
//        path36Path.addLine(to: CGPoint(x: 522.68, y: 386.19))
//        path36Path.close()
//        fillColor2.setFill()
//        path36Path.fill()
    }
}
我想画那些背景光的颜色,形状

输出:


就你的情况而言,你的形状是规则的

要处理坐标数学,最好使用基于rect高度的相关列表坐标

public class ShapeView : UIView{
    public override func draw(_ rect: CGRect) {
        let list: [CGFloat] = [0, 0.5, 1, 1.6, 1.7, 2, 2.5, 2.7, 3]
        let coordinates = list.map { (i) -> CGFloat in
            rect.height * i
        }
        var i = 1
        let shallow = UIColor(red: 0.125, green: 0.259, blue: 0.443, alpha: 1.000)
        let deep = UIColor(red: 0.153, green: 0.314, blue: 0.525, alpha: 1.000)
        while i < list.count {
            let b = UIBezierPath()
            b.move(to: CGPoint(x: 0, y: coordinates[i - 1]))
            b.addLine(to: CGPoint(x: 0, y: coordinates[i]))
            b.addLine(to: CGPoint(x: coordinates[i], y: 0))
            b.addLine(to: CGPoint(x: coordinates[i - 1], y: 0))
            b.close()
            if i % 2 == 1{
                shallow.setFill()
            }
            else{
                deep.setFill()
            }
            b.fill()
            i += 1
        }
    }
}

改进@dengApro的好答案

可以用另一种方法来处理拐角

仅绘制角点,而不是使用
layer.cornerRadius

public class ShapeView : UIView{
    public override func draw(_ rect: CGRect) {

        let list: [CGFloat] = [0, 0.5, 1, 1.6, 1.7, 2, 2.5, 2.7, 3]
        let coordinates = list.map { (i) -> CGFloat in
            rect.height * i
        }
        var i = 1
        while i < list.count {
            let b = UIBezierPath()
            b.move(to: CGPoint(x: 0, y: coordinates[i - 1]))
            b.addLine(to: CGPoint(x: 0, y: coordinates[i]))
            b.addLine(to: CGPoint(x: coordinates[i], y: 0))
            b.addLine(to: CGPoint(x: coordinates[i - 1], y: 0))
            b.close()
            if i % 2 == 1{
                UIColor.blue.setFill()
            }
            else{
                UIColor.green.setFill()
            }
            b.fill()
            i += 1
        }
        
        
        // for corners
        let upLhs = CGPoint(x: 0, y: 0)
        let upRhs = CGPoint(x: rect.width, y: 0)
        let downRhs = CGPoint(x: rect.width, y: rect.height)
        let downLhs = CGPoint(x: 0, y: rect.height)
        let corner: CGFloat = 30
        let upLhsArc = UIBezierPath()
        upLhsArc.move(to: upLhs)
        upLhsArc.addLine(to: upLhs + .x(corner))
        upLhsArc.addArc(withCenter: upLhs ~> PointOffset(x: corner, y: corner), radius: corner, startAngle: .pi * 1.5, endAngle: .pi, clockwise: false)
        upLhsArc.close()
        
        let upRhsArc = UIBezierPath()
        upRhsArc.move(to: upRhs)
        upRhsArc.addLine(to: upRhs + .x(corner * -1))
        upRhsArc.addArc(withCenter: upRhs ~> PointOffset(x: corner * -1, y: corner), radius: corner, startAngle: .pi * -0.5, endAngle: 0, clockwise: true)
        upRhsArc.close()
        
        let downRhsArc = UIBezierPath()
        downRhsArc.move(to: downRhs)
        downRhsArc.addLine(to: downRhs + .x(corner * -1))
        downRhsArc.addArc(withCenter: downRhs ~> PointOffset(x: corner * -1, y: corner * -1), radius: corner, startAngle: .pi * 0.5, endAngle: 0, clockwise: false)
        downRhsArc.close()
        
        let downLhsArc = UIBezierPath()
        downLhsArc.move(to: downLhs)
        downLhsArc.addLine(to: downLhs + .x(corner))
        downLhsArc.addArc(withCenter: downLhs ~> PointOffset(x: corner , y: corner * -1), radius: corner, startAngle: .pi * 0.5, endAngle: .pi, clockwise: true)
        downLhsArc.close()
        // use your background color
        UIColor.white.setFill()
        upLhsArc.fill()
        upRhsArc.fill()
        downRhsArc.fill()
        downLhsArc.fill()
    }
}

帮助功能:

struct PointOffset{
    let x: CGFloat
    let y: CGFloat
}


enum PointDimension{
    case x(CGFloat), y(CGFloat)
}


func +(left: CGPoint, right: PointDimension) -> CGPoint {
    switch right {
    case .x(let v):
        return CGPoint(x: left.x + v, y: left.y)
    case .y(let v):
        return CGPoint(x: left.x, y: left.y + v)
    }
}


infix operator ~>: AdditionPrecedence
func ~>(left: CGPoint, right: PointOffset) -> CGPoint{
    return CGPoint(x: left.x + right.x, y: left.y + right.y)
}

下面是另一种改进@dengApro优秀代码的方法

提高渲染性能。

@dengApro很好的代码,在一些额外的地方填充颜色

然后做一些计算,以避免额外的工作

// coordinates's structure

// [[CGPoint]], 
// an array of an array , the inner array has two points
// the first point is at top, the second point is at bottom
public class ShapeView : UIView{
    public override func draw(_ rect: CGRect) {
        let list: [CGFloat] = [0, 0.5, 1, 1.6, 1.7, 2, 2.5, 2.7, 3]
        let h = rect.height
        let coordinates = list.reduce([[CGPoint]]()) { (result, val) -> [[CGPoint]] in
            if result.isEmpty{
                return [[CGPoint(x: val, y: val), CGPoint(x: val, y: val)]]
            }
            else{
                let x = h * val
                let first = CGPoint(x: x, y: 0)
                let y = h * min(1, val)
                var secondX: CGFloat = 0
                if val > 1{
                    secondX = x - h
                }
                return result + [[first, CGPoint(x: secondX, y: y)]]
            }
            
        }
        
        var i = 1
        let shallow = UIColor(red: 0.125, green: 0.259, blue: 0.443, alpha: 1.000)
        let deep = UIColor(red: 0.153, green: 0.314, blue: 0.525, alpha: 1.000)
        while i < list.count {
            let b = UIBezierPath()
            b.move(to: coordinates[i-1][0])
            b.addLine(to: coordinates[i][0])
            b.addLine(to: coordinates[i][1])
            b.addLine(to: coordinates[i-1][1])
           // print(coordinates[i-1][0],  coordinates[i][0],  coordinates[i][1], coordinates[i-1][1])
            b.close()
            if i % 2 == 1{
                shallow.setFill()
            }
            else{
                deep.setFill()
            }
            b.fill()
            i += 1
        }
    }
}

改进@dengST30的代码

改进点计算减少方法:

public class ShapeView : UIView{
    public override func draw(_ rect: CGRect) {
        let list: [CGFloat] = [0.5, 1, 1.6, 1.7, 2, 2.5, 2.7, 3]
        let h = rect.height
        let start = [CGPoint](repeating: CGPoint.zero, count: 2)
        let points = list.reduce([start]) { (result, val) -> [[CGPoint]] in
            let x = h * val
            let y = h * min(1, val)
            var secondX: CGFloat = 0
            if val > 1{
                secondX = x - h
            }
            return result + [[CGPoint(x: x, y: 0), CGPoint(x: secondX, y: y)]]
        }
        var i = 1
        while i < points.count {
            let b = UIBezierPath()
            b.move(to: points[i-1][0])
            b.addLine(to: points[i][0])
            b.addLine(to: points[i][1])
            b.addLine(to: points[i-1][1])
            b.close()
            if i % 2 == 1{
                UIColor.black.setFill()
            }
            else{
                UIColor.lightText.setFill()
            }
            b.fill()
            i += 1
        }
    }
}
公共类ShapeView:UIView{
公共覆盖函数绘图(rect:CGRect){
让列表:[CGFloat]=[0.5,1,1.6,1.7,2,2.5,2.7,3]
设h=垂直高度
让开始=[CGPoint](重复:CGPoint.zero,计数:2)
让points=list.reduce([start]){(result,val)->[[CGPoint]]in
设x=h*val
设y=h*min(1,val)
var secondX:CGFloat=0
如果val>1{
秒x=x-h
}
返回结果+[[CGPoint(x:x,y:0),CGPoint(x:secondX,y:y)]]
}
变量i=1
当我数的时候{
设b=UIBezierPath()
b、 移动(到:点[i-1][0])
b、 地址行(至:点[i][0])
b、 地址行(至:点[i][1])
b、 地址行(收件人:点[i-1][1])
b、 关闭()
如果i%2==1{
UIColor.black.setFill()
}
否则{
UIColor.lightText.setFill()
}
b、 填充()
i+=1
}
}
}

为什么不使用
CAGradientLayer
?CAGradientLayer和Beizerpath有什么区别?视图高度将根据屏幕高度更改*0.3我的视图大小基于80%的主屏幕宽度和30%的高度,这不起作用。如果我将大小设置为动态大小,则可以重新绘制画布。只需调用
view.setNeedsDisplay()
我创建了IBOutlet并调用了仍然不工作。重写creditCardVeiw.setNeedsDisplay()中的func viewDidLayoutSubviews(){DispatchQueue.main.async{[self]这不起作用。它是如何不起作用的。您发布的所需图像的高宽比为2:1。我在iPhone12Mini上试用了80%的主屏幕宽度和30%的高度。当前的宽度比是1.23:1。怀疑您给定的坐标应该<1对吗?我的视图大小基于主屏幕宽度的80%和高度的30%,如果我将大小设置为动态大小,这将不起作用。很容易将基于rect的大小替换为基于主屏幕的大小。只需在你脑海中设定坐标即可。重要的一点是你是如何划清界限的你救了我一天谢谢。我修正了它,我的视图大小是基于主屏幕宽度的80%和高度的30%,如果我将大小设置为动态大小,这是不起作用的,很容易更改。也许你应该发布另一个问题。你救了我一天,谢谢。我修正了它我的视图大小是基于主屏幕宽度的80%和高度的30%,如果我将大小设置为动态大小,这是不起作用的。谢谢你节省了我的时间。我修好了
// coordinates's structure

// [[CGPoint]], 
// an array of an array , the inner array has two points
// the first point is at top, the second point is at bottom
public class ShapeView : UIView{
    public override func draw(_ rect: CGRect) {
        let list: [CGFloat] = [0, 0.5, 1, 1.6, 1.7, 2, 2.5, 2.7, 3]
        let h = rect.height
        let coordinates = list.reduce([[CGPoint]]()) { (result, val) -> [[CGPoint]] in
            if result.isEmpty{
                return [[CGPoint(x: val, y: val), CGPoint(x: val, y: val)]]
            }
            else{
                let x = h * val
                let first = CGPoint(x: x, y: 0)
                let y = h * min(1, val)
                var secondX: CGFloat = 0
                if val > 1{
                    secondX = x - h
                }
                return result + [[first, CGPoint(x: secondX, y: y)]]
            }
            
        }
        
        var i = 1
        let shallow = UIColor(red: 0.125, green: 0.259, blue: 0.443, alpha: 1.000)
        let deep = UIColor(red: 0.153, green: 0.314, blue: 0.525, alpha: 1.000)
        while i < list.count {
            let b = UIBezierPath()
            b.move(to: coordinates[i-1][0])
            b.addLine(to: coordinates[i][0])
            b.addLine(to: coordinates[i][1])
            b.addLine(to: coordinates[i-1][1])
           // print(coordinates[i-1][0],  coordinates[i][0],  coordinates[i][1], coordinates[i-1][1])
            b.close()
            if i % 2 == 1{
                shallow.setFill()
            }
            else{
                deep.setFill()
            }
            b.fill()
            i += 1
        }
    }
}
    let v = ShapeView()
    v.frame = CGRect(x: 50, y: 100, width: 300, height: 150)
    v.layer.cornerRadius = 30
    v.clipsToBounds = true
    view.addSubview(v)
public class ShapeView : UIView{
    public override func draw(_ rect: CGRect) {
        let list: [CGFloat] = [0.5, 1, 1.6, 1.7, 2, 2.5, 2.7, 3]
        let h = rect.height
        let start = [CGPoint](repeating: CGPoint.zero, count: 2)
        let points = list.reduce([start]) { (result, val) -> [[CGPoint]] in
            let x = h * val
            let y = h * min(1, val)
            var secondX: CGFloat = 0
            if val > 1{
                secondX = x - h
            }
            return result + [[CGPoint(x: x, y: 0), CGPoint(x: secondX, y: y)]]
        }
        var i = 1
        while i < points.count {
            let b = UIBezierPath()
            b.move(to: points[i-1][0])
            b.addLine(to: points[i][0])
            b.addLine(to: points[i][1])
            b.addLine(to: points[i-1][1])
            b.close()
            if i % 2 == 1{
                UIColor.black.setFill()
            }
            else{
                UIColor.lightText.setFill()
            }
            b.fill()
            i += 1
        }
    }
}