SwiftUI:在视图中缩放形状

SwiftUI: Scaling a Shape in a View

我有一个 SubView 完美设计的 320x320 :)。我想让它缩小到最小 100x100。现在我在每个 Shape 中使用一个比例因子。问题:在可重用的 SwiftUI View 中是否有更通用的缩放方式 Shapes(尺寸、线条宽度和长度以及矩形宽度和高度)?谢谢。

查看:

代码:

import SwiftUI

private struct SecondsFace: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let square = CGRect(x: rect.minX, y: rect.minY, width: min(rect.maxX-rect.minX,rect.maxY-rect.minY), height: min(rect.maxX-rect.minX,rect.maxY-rect.minY))
        let scaleFactor = CGFloat(square.width / 320.0)
        var seconds : Path = Path()
        seconds.addLines([CGPoint(x: (320.0/2.0-14.0)*scaleFactor, y: 0),CGPoint(x: (320.0/2-4.0)*scaleFactor, y: 0)])
        for i in 0...59 {
            path.addPath(seconds, transform: .init(rotationAngle: 2.0 * CGFloat.pi * CGFloat(i)/60.0))
        }
        return path.offsetBy(dx: (320.0/2.0)*scaleFactor, dy: (320.0/2.0)*scaleFactor)
    }
}

private struct HoursFace: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let square = CGRect(x: rect.minX, y: rect.minY, width: min(rect.maxX-rect.minX,rect.maxY-rect.minY), height: min(rect.maxX-rect.minX,rect.maxY-rect.minY))
        let scaleFactor = CGFloat(square.width / 320.0)
        var seconds : Path = Path()
        seconds.addLines([CGPoint(x: (320.0/2.0-16)*scaleFactor, y: 0),CGPoint(x: (320.0/2.0-2.0)*scaleFactor, y: 0)])
        for i in 0...11 {
            path.addPath(seconds, transform: .init(rotationAngle: 2.0 * CGFloat.pi * CGFloat(i)/12.0))
        }
        return path.offsetBy(dx: (320.0/2.0)*scaleFactor, dy: (320.0/2.0)*scaleFactor)
    }
}

struct ThreeHoursFace: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let square = CGRect(x: rect.minX, y: rect.minY, width: min(rect.maxX-rect.minX,rect.maxY-rect.minY), height: min(rect.maxX-rect.minX,rect.maxY-rect.minY))
        let scaleFactor = CGFloat(square.width / 320.0)
        let threehours : Path = Path(CGRect(x: (320.0/2.0-20.0)*scaleFactor, y: -2.0*scaleFactor, width: 20.0*scaleFactor, height: 4.0*scaleFactor))
        for i in 0...3 {
            path.addPath(threehours, transform: .init(rotationAngle: 2.0 * CGFloat.pi * CGFloat(i)/4.0))
            }
        return path.offsetBy(dx: (320.0/2.0)*scaleFactor, dy: (320.0/2.0)*scaleFactor)
    }
}

struct SubView: View {
    @Binding var color : ColorValue

    var body: some View {
        ZStack {
            SecondsFace()
            .stroke(Color.green, style: StrokeStyle(lineWidth: 1, lineCap: .square, lineJoin: .bevel))
            HoursFace()
            .stroke(Color.red, style: StrokeStyle(lineWidth: 3, lineCap: .square, lineJoin: .bevel))
            ThreeHoursFace()
            .fill(Color.blue)
        }
        .aspectRatio(1, contentMode: .fit)
        .clipped(antialiased: true)
        .background(Color(red: 0.9, green: 0.9, blue: 0.9, opacity: 1.0))
    }
 }

struct SubViewPreview: PreviewProvider {

    @State static var currentColor : ColorValue = ColorValue(color: UIColor.red)

    static var previews: some View {
        SubView(color: $currentColor)
    }
}

通过缩放重复使用的视图:

(线宽缩放还有个小问题...)

代码:

import Foundation
import SwiftUI

struct MainView: View {

    @State var color = ColorValue(color: UIColor.red)

    var body: some View {
        VStack {
            HStack(spacing: 10) {
                SubView(color: $color)
            }
            .padding(10)
            HStack(spacing: 10) {
                SubView(color: $color)
                SubView(color: $color)
            }
            .padding(10)
            HStack(spacing: 10) {
                SubView(color: $color)
                SubView(color: $color)
                SubView(color: $color)
            }
            .padding(10)
        }
    }

}

struct ShapeView_Previews: PreviewProvider {
    static var previews: some View {
        MainView()
    }
}

这是不准确的部分重叠的结果。我喜欢它在 SubView 的结构更改后的样子(或类似的东西,即上刻度应该比下刻度更宽)

struct SubViewA: View {
    @Binding var color : ColorValue

    var body: some View {
        ZStack {
            SecondsFace()
            .stroke(Color.green, style: StrokeStyle(lineWidth: 1, lineCap: .square, lineJoin: .bevel))
            HoursFace()
            .stroke(Color.red, style: StrokeStyle(lineWidth: 2, lineCap: .square, lineJoin: .bevel))
            ThreeHoursFace()
            .stroke(Color.blue, style: StrokeStyle(lineWidth: 2, lineCap: .square, lineJoin: .bevel))
        }
        .aspectRatio(1, contentMode: .fit)
        .clipped(antialiased: true)
        .background(Color(red: 0.9, green: 0.9, blue: 0.9, opacity: 1.0))
    }
 }

我现在正在 applying(CGAffineTransform(a:, b: , c: , d:, tx: , ty: )) 使用 Shape 中的结果 path

代码:

import SwiftUI

private struct SecondsFace: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let seconds : Path = Path(CGRect(x: (320.0/2.0-14.0), y: -1.0, width: 10.0, height: 2.0))
        for i in 0...59 {
            path.addPath(seconds, transform: .init(rotationAngle: 2.0 * CGFloat.pi * CGFloat(i)/60.0))
        }
        let scaleFactor = CGFloat(min(rect.maxX-rect.minX,rect.maxY-rect.minY) / 320.0)
        return path.applying(CGAffineTransform(a: scaleFactor, b: 0.0, c: 0.0, d: scaleFactor, tx: (320.0/2.0)*scaleFactor, ty: (320.0/2.0)*scaleFactor))
    }
}

private struct HoursFace: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let seconds : Path = Path(CGRect(x: (320.0/2.0-16.0), y: -2.0, width: 14.0, height: 4.0))
        for i in 0...11 {
            path.addPath(seconds, transform: .init(rotationAngle: 2.0 * CGFloat.pi * CGFloat(i)/12.0))
        }
        let scaleFactor = CGFloat(min(rect.maxX-rect.minX,rect.maxY-rect.minY) / 320.0)
        return path.applying(CGAffineTransform(a: scaleFactor, b: 0.0, c: 0.0, d: scaleFactor, tx: (320.0/2.0)*scaleFactor, ty: (320.0/2.0)*scaleFactor))
    }
}

struct ThreeHoursFace: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let threehours : Path = Path(CGRect(x: (320.0/2.0-24.0), y: -4.0, width: 24.0, height: 8.0))
        for i in 0...3 {
            path.addPath(threehours, transform: .init(rotationAngle: 2.0 * CGFloat.pi * CGFloat(i)/4.0))
        }
        let scaleFactor = CGFloat(min(rect.maxX-rect.minX,rect.maxY-rect.minY) / 320.0)
        return path.applying(CGAffineTransform(a: scaleFactor, b: 0.0, c: 0.0, d: scaleFactor, tx: (320.0/2.0)*scaleFactor, ty: (320.0/2.0)*scaleFactor))
    }
}

struct SubView: View {
    @Binding var color : ColorValue

    var body: some View {
        ZStack {
            SecondsFace()
            .fill(Color.green)
            HoursFace()
            .fill(Color.red)
            ThreeHoursFace()
            .fill(Color.blue)
        }
        .aspectRatio(1, contentMode: .fit)
        .clipped(antialiased: true)
        .background(Color(red: 0.9, green: 0.9, blue: 0.9, opacity: 1.0))
    }
 }

struct SubViewPreview: PreviewProvider {

    @State static var currentColor : ColorValue = ColorValue(color: UIColor.red)

    static var previews: some View {
        SubView(color: $currentColor)
    }
}

看: