我有一个来自形状的矩形视图。最后,我需要在添加自定义路径时使用 CGAffineTransform。当我使用 CGAffineTransform 时,需要在形状内部计算和更新参数 a 和 tx 以保持整个最终路径可见。目前,我不知道在更改视图大小时让 a 和 tx 自行更新的确切方法。我必须使用滑块手动调整它们,滑块不是应用程序或程序的一部分,它只是一个调试工具。正如您在视频中看到的,通过更改 a 和 tx 的值,我可以将整个路径保持在框架内,但用户需要自动发生。那么,如何让 a 和 tx 自动更新,同时将整个路径保留在框架中?
第 1 部分:
第 2 部分:
代码:
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
}
}
我假设
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
控制水平轴上的变换。