我在运行时添加了UIView个代码.

我想画一个UIBezierPath,但这是否意味着我必须覆盖UIView的drawRect

或者,有没有其他方法可以在定制的UIView号上画上它?

以下是生成UIView的代码:

UIView* shapeView = [[UIView alloc]initWithFrame:CGRectMake(xOrigin,yOrigin+(i*MENU_BLOCK_FRAME_HEIGHT), self.shapeScroll.frame.size.width, MENU_BLOCK_FRAME_HEIGHT)];
shapeView.clipsToBounds = YES;

下面是创建和返回UIBezierPath的函数:

- (UIBezierPath*)createPath
{
    UIBezierPath* path = [[UIBezierPath alloc]init];
    [path moveToPoint:CGPointMake(100.0, 50.0)];
    [path addLineToPoint:CGPointMake(200.0,50.0)];
    [path addLineToPoint:CGPointMake(200.0, 200.0)];
    [path addLineToPoint:CGPointMake(100.0, 200.0)];
    [path closePath];
    return path;
}

推荐答案

就在不久之前,我甚至不知道贝塞尔曲线的发音,更不用说知道如何使用贝塞尔曲线路径来定制形状了.以下是我所学到的.事实证明,他们并不像一开始看起来那么可怕.

How to draw a Bézier path in a custom view

以下是主要步骤:

  1. 设计所需形状的轮廓.
  2. 将轮廓路径分割为直线段、圆弧段和曲线段.
  3. 以编程方式构建该路径.
  4. 使用drawRectCAShapeLayer绘制路径.

Design shape outline

你可以做任何事情,但作为一个例子,我 Select 了下面的形状.它可能是键盘上的一个弹出键.

enter image description here

Divide the path into segments

回顾您的形状设计,将其分解为更简单的直线元素(对于直线)、圆弧元素(对于圆和圆角元素)和曲线元素(对于其他元素).

下面是我们的示例设计:

enter image description here

  • 黑色是线段
  • 浅蓝色是圆弧段
  • 红色是曲线
  • 橙色圆点是曲线的控制点
  • 绿点是路径段之间的点
  • 虚线显示边框
  • 深蓝色数字是按它们将以编程方式添加的顺序排列的线段

Build the path programmatically

我们将任意从左下角开始,顺时针方向工作.我将使用图像中的网格来获取点的x和y值.我将在这里对所有内容进行硬编码,但在真正的项目中当然不会这样做.

基本流程是:

  1. 创建一个新的UIBezierPath
  2. moveToPoint Select 路径上的起点
  3. Add segments to the path
    • 电话:addLineToPoint
    • 弧度:addArcWithCenter
    • 曲线:addCurveToPoint
  4. closePath结束路径

下面是在上图中创建路径的代码.

func createBezierPath() -> UIBezierPath {

    // create a new path
    let path = UIBezierPath()

    // starting point for the path (bottom left)
    path.move(to: CGPoint(x: 2, y: 26))

    // *********************
    // ***** Left side *****
    // *********************

    // segment 1: line
    path.addLine(to: CGPoint(x: 2, y: 15))

    // segment 2: curve
    path.addCurve(to: CGPoint(x: 0, y: 12), // ending point
        controlPoint1: CGPoint(x: 2, y: 14),
        controlPoint2: CGPoint(x: 0, y: 14))

    // segment 3: line
    path.addLine(to: CGPoint(x: 0, y: 2))

    // *********************
    // ****** Top side *****
    // *********************

    // segment 4: arc
    path.addArc(withCenter: CGPoint(x: 2, y: 2), // center point of circle
        radius: 2, // this will make it meet our path line
        startAngle: CGFloat(M_PI), // π radians = 180 degrees = straight left
        endAngle: CGFloat(3*M_PI_2), // 3π/2 radians = 270 degrees = straight up
        clockwise: true) // startAngle to endAngle goes in a clockwise direction

    // segment 5: line
    path.addLine(to: CGPoint(x: 8, y: 0))

    // segment 6: arc
    path.addArc(withCenter: CGPoint(x: 8, y: 2),
                          radius: 2,
                          startAngle: CGFloat(3*M_PI_2), // straight up
        endAngle: CGFloat(0), // 0 radians = straight right
        clockwise: true)

    // *********************
    // ***** Right side ****
    // *********************

    // segment 7: line
    path.addLine(to: CGPoint(x: 10, y: 12))

    // segment 8: curve
    path.addCurve(to: CGPoint(x: 8, y: 15), // ending point
        controlPoint1: CGPoint(x: 10, y: 14),
        controlPoint2: CGPoint(x: 8, y: 14))

    // segment 9: line
    path.addLine(to: CGPoint(x: 8, y: 26))

    // *********************
    // **** Bottom side ****
    // *********************

    // segment 10: line
    path.close() // draws the final line to close the path

    return path
}

注意:通过在单个命令中添加一条直线和一条圆弧(因为圆弧有一个隐含的起点),可以减少上面的一些代码.有关更多详细信息,请参见here.

Draw the path

我们可以在图层中绘制路径,也可以在drawRect中绘制路径.

Method 1: Draw path in a layer

我们的自定义类如下所示.当视图初始化时,我们将Bezier路径添加到新的CAShapeLayer.

import UIKit
class MyCustomView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    func setup() {

        // Create a CAShapeLayer
        let shapeLayer = CAShapeLayer()

        // The Bezier path that we made needs to be converted to 
        // a CGPath before it can be used on a layer.
        shapeLayer.path = createBezierPath().cgPath

        // apply other properties related to the path
        shapeLayer.strokeColor = UIColor.blue.cgColor
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.lineWidth = 1.0
        shapeLayer.position = CGPoint(x: 10, y: 10)

        // add the new layer to our custom view
        self.layer.addSublayer(shapeLayer)
    }

    func createBezierPath() -> UIBezierPath {

        // see previous code for creating the Bezier path
    }
}

在视图控制器中创建视图,如下所示

override func viewDidLoad() {
    super.viewDidLoad()

    // create a new UIView and add it to the view controller
    let myView = MyCustomView()
    myView.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
    myView.backgroundColor = UIColor.yellow
    view.addSubview(myView)

}

我们得到了...

enter image description here

嗯,那有点小,因为我把所有的数字都硬编码进go 了.不过,我可以将路径大小放大,如下所示:

let path = createBezierPath()
let scale = CGAffineTransform(scaleX: 2, y: 2)
path.apply(scale)
shapeLayer.path = path.cgPath

enter image description here

Method 2: Draw path in 100

使用draw比绘制到图层慢,因此如果您不需要此方法,则不推荐使用此方法.

以下是我们的自定义视图的修订代码:

import UIKit
class MyCustomView: UIView {

    override func draw(_ rect: CGRect) {

        // create path (see previous code)
        let path = createBezierPath()

        // fill
        let fillColor = UIColor.white
        fillColor.setFill()

        // stroke
        path.lineWidth = 1.0
        let strokeColor = UIColor.blue
        strokeColor.setStroke()

        // Move the path to a new location
        path.apply(CGAffineTransform(translationX: 10, y: 10))

        // fill and stroke the path (always do these last)
        path.fill()
        path.stroke()

    }

    func createBezierPath() -> UIBezierPath {

        // see previous code for creating the Bezier path
    }
}

这给了我们同样的结果.

enter image description here

Further study

really推荐看以下material .正是它们最终让我可以理解贝塞尔曲线的道路.(并教我如何发音:/ˈbɛzi eɪ/.)

Ios相关问答推荐

在金属中设置纹理的UV坐标以编程方式变形纹理

当重新呈现UI时,嵌套的 struct 值如何与@Observable一起工作?

为什么EKEventStore().questFullAccessToEvents()可以与模拟器一起使用,而不能与真实设备一起使用?

如何在KMM项目中处理PHPickerViewController的回调?

确保方法调配的安全有效实施

为什么IOS多行文本输入在React原生纸张对话框中无法正常工作?

为什么applicationState发布者只发布一次?

如何制作支持不同语言的iOS应用

如何链式设置 AttributeContainer 的 UIKit 属性?

Swift中是否有一种方法可以为可选属性创建一个计算(computed)属性

Flutter动画放大图

当 Swift 枚举具有 any existential 作为其关联值之一时,我如何使它符合 `Equatable`?

var name: String 时 print(nil) 和 print(name) 的区别? = 无

Xcode 不支持 iOS 15.6

集成 IDNow SDK 时未找到 Xcode FLAnimatedImage.h 文件问题

@Environment 的存在会导致列表在滚动时不断重建其内容

使用 Vim 代替(或与)Xcode 进行 iOS 开发

Xcode - 错误 ITMS-90635 - Bundle 包中的 Mach-O 无效 - 提交到 App Store

从 NSData 或 UIImage 中查找图像类型

Flutter:如何创建一个新项目