如何使 CGAffineTransform 的参数在 Shape 中自动更新,同时将所有路径保持在 SwiftUI 的可见视图中?

问题描述 投票:0回答:1

我有一个来自形状的矩形视图。最后,我需要在添加自定义路径时使用 CGAffineTransform。当我使用 CGAffineTransform 时,需要在形状内部计算和更新参数 atx 以保持整个最终路径可见。目前,我不知道在更改视图大小时让 atx 自行更新的确切方法。我必须使用滑块手动调整它们,滑块不是应用程序或程序的一部分,它只是一个调试工具。正如您在视频中看到的,通过更改 atx 的值,我可以将整个路径保持在框架内,但用户需要自动发生。那么,如何让 atx 自动更新,同时将整个路径保留在框架中?

第 1 部分:

enter image description here

第 2 部分:

enter image description here

代码:

import SwiftUI

struct ContentView: View {

    @State private var a: Double = 0.8
    @State private var b: Double = 0
    @State private var c: Double = -0.17
    @State private var d: Double = 1
    @State private var tx: Double = 100
    @State private var ty: Double = 0

    var body: some View {
        
        FinalShape(a: a, b: b, c: c, d: d, tx: tx, ty: ty)
            .strokeBorder(style: StrokeStyle(lineWidth: 5.0, lineCap: .round, lineJoin: .round))
            .background(Color.purple)
            .cornerRadius(5.0)
            .padding()

        VStack {

            HStack {
                Text("a:")
                Slider(value: $a, in: -1...1)
            }
            
            HStack {
                Text("b:")
                Slider(value: $b, in: -1...1)
            }
            
            HStack {
                Text("c:")
                Slider(value: $c, in: -1...1)
            }
            
            HStack {
                Text("d:")
                Slider(value: $d, in: -1...1)
            }
            
            HStack {
                Text("tx:")
                Slider(value: $tx, in: -200...200)
            }
            
            HStack {
                Text("ty:")
                Slider(value: $ty, in: -200...200)
            }
 
        }
        .padding()

        HStack {
            VStack(alignment: .leading) {
                Text("a:" + String(describing: a))
                Text("b:" + String(describing: b))
                Text("c:" + String(describing: c))
                Text("d:" + String(describing: d))
                Text("tx:" + String(describing: tx))
                Text("ty:" + String(describing: ty))
            }
            
            Spacer()
        }
        .padding()

    }
}


struct FinalShape: InsettableShape {

    var a: Double
    var b: Double
    var c: Double
    var d: Double
    var tx: Double
    var ty: Double
    
    var insetAmount: CGFloat = CGFloat.zero

    func path(in rect: CGRect) -> Path {
        return Path { path in

            let transform = CGAffineTransform(a: a, b: b, c: c, d: d, tx: tx, ty: ty)

            path.addPath(RecShape(insetAmount: insetAmount).path(in: CGRect(origin: CGPoint(x: rect.minX, y: rect.minY), size: rect.size)), transform: transform)

        }
    }
    
    func inset(by amount: CGFloat) -> some InsettableShape {
        var myShape: Self = self
        myShape.insetAmount += amount
        return myShape
    }
}


struct RecShape: InsettableShape {
    var insetAmount: CGFloat = CGFloat.zero
    func path(in rect: CGRect) -> Path {
        return Path { path in
            path.addRect(CGRect(origin: CGPoint(x: rect.minX + insetAmount, y: rect.minY + insetAmount), size: CGSize(width: rect.width - 2*insetAmount, height: rect.height - 2*insetAmount)))
        }
    }
    func inset(by amount: CGFloat) -> some InsettableShape {
        var myShape: Self = self
        myShape.insetAmount += amount
        return myShape
    }
}
swiftui
1个回答
0
投票

我假设

b
c
d
ty
都是固定的。

回想一下描述点如何通过仿射变换进行变换的方程。

x' = ax + cy + tx
y' = bx + dy + ty

根据您的 gif,您似乎希望矩形的

minX
maxX
在应用转换后不发生变化。我们可以建立两个方程并找到两个未知数
a
tx
。这里我考虑了两个点 (minX, maxY) 和 (maxX, minY)。

minX = a * minX + c * maxY + tx
maxX = a * maxX + c * minY + tx

解决完这些之后,你可以这样写:

func path(in rect: CGRect) -> Path {
    let insettedRect = rect.insetBy(dx: insetAmount, dy: insetAmount)
    
    // I just used the path from a Rectangle() here, but you can use any path you like
    let path = Rectangle().path(in: insettedRect)
    
    let numerator = (insettedRect.minX - c * insettedRect.maxY - insettedRect.maxX - c * insettedRect.minY)
    let a = numerator / (insettedRect.minX - insettedRect.maxX)
    let tx = insettedRect.maxX - a * insettedRect.maxX + c * insettedRect.minY
    return path.applying(CGAffineTransform(a, b, c, d, tx, ty))
}

“插入”对于这个形状意味着什么是值得商榷的。在这里,我只是插入了给定的

rect
,但我建议根本不要使其可插入。

使用示例:

FinalShape(b: 0, c: -0.17, d: 1, ty: 0)
            .strokeBorder(style: StrokeStyle(lineWidth: 5.0, lineCap: .round, lineJoin: .round))
            .background(Color.purple)
            .padding()

请注意,仍然可以传入

d
ty
的值,使得形状垂直超出矩形。
a
tx
的值无法帮助您实现此目的,因为
a
tx
控制水平轴上的变换。

© www.soinside.com 2019 - 2024. All rights reserved.