SwiftUI - 图形绘制

在UIKit中的图形绘制大多都是基于Quartz2D的,它的API使用起来较为繁琐,使用不当时还会导致性能问题。SwiftUI在这方面做了改进,使得绘制图形变成一件简单的事情。

通过几个例子来了解一下常用API,其中包括,基础图形,直线,曲线。

基础图形

使用方法很简单,初始化一个Rectangle,在添加一个frame修饰符,在添加一个fill修饰符用于填充颜色即可。为了达到演示的效果,我们稍微丰富一下,使用几个额外的修饰符,代码如下:

GeometryReader { geometry in
    ZStack {
        ForEach(0..<3) { i in
            Rectangle()
                .fill(
                    LinearGradient(gradient: .init(colors: [.green, .blue]), startPoint: .init(x: 0, y: 1), endPoint: .init(x: 1, y: 0))
                )
                .frame(width: geometry.size.width * 0.7, height: geometry.size.width * 0.7)
                .rotationEffect(.degrees(Double(i) * 60))
        }
        Image("baymax-white")
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: geometry.size.width * 0.5)
    }
}

效果图如下所示:


rectangle.png

其中,fill可以传入一个颜色,或如示例中的渐变色;ForEach可以遍历生成一组view,在示例中生成了三个矩形,每个矩形根据当前index和rotationEffect旋转一定的角度。比较特别的是一个容器对象GeometryReader,通过这个容器,可以得到容器内部元素的size。其他的形状如:Circle,Ellipse,Rounded Rectangle,Capsule可以如法炮制。

Path

  1. 直线
    当内建的形状不能满足需求时,可以使用Path来自己绘制一个图形,示例代码中通过Path绘制了一个简单的梯形:
Path { path in
    path.move(to: CGPoint(x: 120, y: 20))
    path.addLine(to: CGPoint(x: 180, y: 180))
    path.addLine(to: CGPoint(x: 20, y: 180))
    path.addLine(to: CGPoint(x: 80, y: 20))
}

看一个稍微复杂一点的实例:

GeometryReader { geometry in
    ZStack {
        Path { path in
            let size = min(geometry.size.width, geometry.size.height)
            let nearLine = size * 0.1
            let farLine = size * 0.9
            path.move(to: CGPoint(x: size / 2 + nearLine, y: nearLine))
            path.addLine(to: CGPoint(x: farLine, y: farLine))
            path.addLine(to: CGPoint(x: nearLine, y: farLine))
            path.addLine(to: CGPoint(x: size / 2 - nearLine, y: nearLine))
        }
        .fill(Color.init(red: 0.4, green: 0.4, blue: 0.4))
        
        Path { path in
            let size = min(geometry.size.width, geometry.size.height)
            let nearLine = size * 0.1
            let farLine = size * 0.9
            let middle = size / 2
            path.move(to: .init(x: middle, y: farLine))
            path.addLine(to: .init(x: middle, y: nearLine))
        }
        .stroke(Color.white, style: .init(lineWidth: 3.0, dash: [geometry.size.width / 20, geometry.size.width / 30], dashPhase: 0))
        
        Image(systemName: "car.fill")
            .resizable()
            .frame(width: geometry.size.width / 4, height: geometry.size.width / 4)
            .foregroundColor(Color.white)
            .offset(x: -geometry.size.width / 6.72, y: -geometry.size.width / 2.75)
    }
}

示例代码的效果图如下所示:


path.png
  1. 曲线
    绘制曲线同样使用Path,不同的是将addLine改为addQuadCurve,在addQuadCurve中除了指定终点外,还需要一个control point,示例代码如下所示:
GeometryReader { geometry in
    HStack {
        Path { path in
            let size = min(geometry.size.width, geometry.size.height)
            let nearLine = size * 0.1
            let farLine = size * 0.9
            let mid = size / 2
            path.move(to: .init(x: mid, y: nearLine))
            path.addQuadCurve(to: .init(x: farLine, y: mid), control: .init(x: size, y: 0))
            path.addQuadCurve(to: .init(x: mid, y: farLine), control: .init(x: size, y: size))
            path.addQuadCurve(to: .init(x: nearLine, y: mid), control: .init(x: 0, y: size))
            path.addQuadCurve(to: .init(x: mid, y: nearLine), control: .init(x: 0, y: 0))
        }
        .fill(Color.yellow)
    }
}

绘制的结果如下图所示:


curv.png

题外话

当使用Image元素时,会发现它不受frame修饰符的控制,在屏幕上始终显示图片的原始大小。若希望将它约束在frame所指定的范围内时,需要添加resizable修饰符,此时它的长宽比例将随frame的宽高改变,呈现一个stretch状态。若想继续保留原有比例,则需要另一个修饰符aspectRatio

你可能感兴趣的:(SwiftUI - 图形绘制)