SwiftUI:如何绘制填充和描边的形状?

orj*_*orj 6 swift swiftui

在UIKit中,绘制描边和填充的路径/形状非常简单。

例如,下面的代码绘制了一个蓝色的红色圆圈。

override func draw(_ rect: CGRect) {
    guard let ctx = UIGraphicsGetCurrentContext() else { return }

    let center = CGPoint(x: rect.midX, y: rect.midY)

    ctx.setFillColor(UIColor.red.cgColor)
    ctx.setStrokeColor(UIColor.blue.cgColor)

    let arc = UIBezierPath(arcCenter: center, radius: rect.width/2, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)

    arc.stroke()
    arc.fill()
}
Run Code Online (Sandbox Code Playgroud)

SwiftUI如何做到这一点?

Swift UI似乎支持:

Circle().stroke(Color.blue)
// and/or
Circle().fill(Color.red)
Run Code Online (Sandbox Code Playgroud)

但不是

Circle().fill(Color.red).stroke(Color.blue) // Value of type 'ShapeView<StrokedShape<Circle>, Color>' has no member 'fill'
// or 
Circle().stroke(Color.blue).fill(Color.red) // Value of type 'ShapeView<Circle, Color>' has no member 'stroke'
Run Code Online (Sandbox Code Playgroud)

我应该只是ZStack两个圈子吗?这似乎有点愚蠢。

Bur*_*lek 52

您还可以使用 strokeBorder 和背景组合。

代码:

         Circle()
            .strokeBorder(Color.blue,lineWidth: 4)
            .background(Circle().foregroundColor(Color.red))
Run Code Online (Sandbox Code Playgroud)

结果 :

在此处输入图片说明

  • 这可能是我见过的最简单的解决方案。不知道我是如何错过 iOS 13 中的描边边框的。仍然认为让描边和填充一起工作会是一个更好的 API。:) (4认同)

loc*_*wei 14

我的解决方法:

import SwiftUI

extension Shape {
    /// fills and strokes a shape
    public func fill<S:ShapeStyle>(
        _ fillContent: S, 
        stroke       : StrokeStyle
    ) -> some View {
        ZStack {
            self.fill(fillContent)
            self.stroke(style:stroke)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

例子:


struct ContentView: View {
    // fill gradient
    let gradient = RadialGradient(
        gradient   : Gradient(colors: [.yellow, .red]), 
        center     : UnitPoint(x: 0.25, y: 0.25), 
        startRadius: 0.2, 
        endRadius  : 200
    )
    // stroke line width, dash
    let w: CGFloat   = 6       
    let d: [CGFloat] = [20,10]
    // view body
    var body: some View {
        HStack {
            Circle()
                // ?? Shape.fill(_:stroke:)
                .fill(Color.red, stroke: StrokeStyle(lineWidth:w, dash:d))
            Circle()
                .fill(gradient, stroke: StrokeStyle(lineWidth:w, dash:d))
        }.padding().frame(height: 300)
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

填充和描边圆圈


Mat*_*ini 11

似乎是ZStack或者.overlay现在。

根据 Xcode,视图层次结构几乎相同。

struct ContentView: View {

    var body: some View {

        VStack {
            Circle().fill(Color.red)
                .overlay(Circle().stroke(Color.blue))
            ZStack {
                 Circle().fill(Color.red)
                 Circle().stroke(Color.blue)
            }
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

输出

在此处输入图片说明


查看层次结构

在此处输入图片说明

  • 是的,目前看来这是唯一的办法。我已向 Apple 提供了“反馈”,认为这并不理想,并认为这是 API 中的疏忽。 (3认同)

Imr*_*ran 10

您可以在实心圆的顶部绘制带有笔触的圆

struct ContentView: View {
    var body: some View {
        Circle()
        .overlay(
            Circle()
           .stroke(Color.green,lineWidth: 5)
          ).foregroundColor(Color.red)
   }
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


cof*_*der 8

另一个更简单的选项,只需使用 ZStack 将笔划堆叠在填充顶部

    ZStack{
        Circle().fill()
            .foregroundColor(.red)
        Circle()
            .strokeBorder(Color.blue, lineWidth: 4)
    }
Run Code Online (Sandbox Code Playgroud)

结果是


man*_*man 6

为了将来的参考,@Imran 的解决方案有效,但您还需要通过填充来考虑总框架中的笔画宽度:

struct Foo: View {
    private let lineWidth: CGFloat = 12
    var body: some View {
        Circle()
            .stroke(Color.purple, lineWidth: self.lineWidth)
        .overlay(
            Circle()
                .fill(Color.yellow)
        )
        .padding(self.lineWidth)
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述