使用 DragGesture 调整 SwiftUI 视图的框架会在所有维度上调整其大小
Adjusting the frame of a SwiftUI view with a DragGesture resizes it in all dimensions
我正在尝试在 SwiftUI 中实现一个简单的视图,可以通过放置在其左下角的拖动手柄来调整其大小。可调整大小的视图的尺寸是通过两个控制宽度和高度的@State 变量设置的。这些变量在拖动手柄捕获的 DragGesture 的 onChanged 处理程序中发生变化。
有点用,但不是我期望的方式。当我在拖动手柄上执行拖动手势时,视图会在所有维度上调整大小。我希望调整大小以与桌面相同的方式工作 window;拖动不应在所有方向调整视图大小。
下面是来自 iOS 模拟器的记录,显示了不正确的行为:
我知道 SwiftUI 视图的中心被认为是它的起源,这可能是导致此行为的原因。我不确定如何解决这个问题。
这是我的代码:
import SwiftUI
struct ContentView: View {
// Initialise to a size proportional to the screen dimensions.
@State private var width = UIScreen.main.bounds.size.width / 3.5
@State private var height = UIScreen.main.bounds.size.height / 1.5
var body: some View {
// This is the view that's going to be resized.
ZStack(alignment: .bottomTrailing) {
Text("Hello, world!")
.frame(width: width, height: height)
// This is the "drag handle" positioned on the lower-left corner of this stack.
Text("")
.frame(width: 30, height: 30)
.background(.red)
.gesture(
DragGesture()
.onChanged { value in
// Enforce minimum dimensions.
width = max(100, width + value.translation.width)
height = max(100, height + value.translation.height)
}
)
}
.frame(width: width, height: height, alignment: .center)
.border(.red, width: 5)
.background(.yellow)
.padding()
}
}
编辑:对于上面的最小示例,我删除的内容过于自由。以下代码片段在 ZStack 上添加了一个 position
约束,它用于另一个手势(未显示),因此可以拖动视图。
我猜这是有问题的,因为 position
指定了从 ZStack 的中心到父 VStack 的相对坐标,并且随着 ZStack 的大小调整,它被“移动”以保持位置约束。
import SwiftUI
struct ContentView: View {
// Initialise to a size proportional to the screen dimensions.
@State private var width = UIScreen.main.bounds.size.width / 3.5
@State private var height = UIScreen.main.bounds.size.height / 1.5
var body: some View {
VStack {
// This is the view that's going to be resized.
ZStack(alignment: .bottomTrailing) {
Text("Hello, world!")
.frame(width: width, height: height)
// This is the "drag handle" positioned on the lower-left corner of this stack.
Text("")
.frame(width: 30, height: 30)
.background(.red)
.gesture(
DragGesture()
.onChanged { value in
// Enforce minimum dimensions.
width = max(100, width + value.translation.width)
height = max(100, height + value.translation.height)
}
)
}
.frame(width: width, height: height)
.border(.red, width: 5)
.background(.yellow)
.padding()
// This position constraint causes the ZStack to grow/shrink in all dimensions
// when resized.
.position(x: 400, y: 400)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
}
你是对的,这个问题是由你的观点引起的center-aligned。
要解决此问题,您可以将视图包裹在 VStack
中并应用不同的对齐方式,例如.topLeading
如果您希望它与 top-left.
对齐
您还必须确保此 VStack
占用了可用的 space 视图。否则,它将缩小到可调整大小框的大小,导致视图保持 center-aligned。您可以使用 .frame(maxWidth: .infinity, maxHeight: .infinity)
.
实现此目的
TL;DR
将可调整大小的框放置在带有 .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
修饰符的 VStack
中。
VStack { // <-- Wrapping VStack with alignment modifier
// This is the view that's going to be resized.
ZStack(alignment: .bottomTrailing) {
Text("Hello, world!")
.frame(width: width, height: height)
// This is the "drag handle" positioned on the lower-left corner of this stack.
Text("")
.frame(width: 30, height: 30)
.background(.red)
.gesture(
DragGesture()
.onChanged { value in
// Enforce minimum dimensions.
width = max(100, width + value.translation.width)
height = max(100, height + value.translation.height)
}
)
}
.frame(width: width, height: height, alignment: .topLeading)
.border(.red, width: 5)
.background(.yellow)
.padding()
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
编辑
在 ZStack 上使用额外的 position
修饰符,尝试将 x
和 y
值偏移 width
和 height
的一半以定位相对于 ZStack 的 top-left 原点:
.position(x: 400 + width / 2, y: 400 + height / 2)
我正在尝试在 SwiftUI 中实现一个简单的视图,可以通过放置在其左下角的拖动手柄来调整其大小。可调整大小的视图的尺寸是通过两个控制宽度和高度的@State 变量设置的。这些变量在拖动手柄捕获的 DragGesture 的 onChanged 处理程序中发生变化。
有点用,但不是我期望的方式。当我在拖动手柄上执行拖动手势时,视图会在所有维度上调整大小。我希望调整大小以与桌面相同的方式工作 window;拖动不应在所有方向调整视图大小。
下面是来自 iOS 模拟器的记录,显示了不正确的行为:
我知道 SwiftUI 视图的中心被认为是它的起源,这可能是导致此行为的原因。我不确定如何解决这个问题。
这是我的代码:
import SwiftUI
struct ContentView: View {
// Initialise to a size proportional to the screen dimensions.
@State private var width = UIScreen.main.bounds.size.width / 3.5
@State private var height = UIScreen.main.bounds.size.height / 1.5
var body: some View {
// This is the view that's going to be resized.
ZStack(alignment: .bottomTrailing) {
Text("Hello, world!")
.frame(width: width, height: height)
// This is the "drag handle" positioned on the lower-left corner of this stack.
Text("")
.frame(width: 30, height: 30)
.background(.red)
.gesture(
DragGesture()
.onChanged { value in
// Enforce minimum dimensions.
width = max(100, width + value.translation.width)
height = max(100, height + value.translation.height)
}
)
}
.frame(width: width, height: height, alignment: .center)
.border(.red, width: 5)
.background(.yellow)
.padding()
}
}
编辑:对于上面的最小示例,我删除的内容过于自由。以下代码片段在 ZStack 上添加了一个 position
约束,它用于另一个手势(未显示),因此可以拖动视图。
我猜这是有问题的,因为 position
指定了从 ZStack 的中心到父 VStack 的相对坐标,并且随着 ZStack 的大小调整,它被“移动”以保持位置约束。
import SwiftUI
struct ContentView: View {
// Initialise to a size proportional to the screen dimensions.
@State private var width = UIScreen.main.bounds.size.width / 3.5
@State private var height = UIScreen.main.bounds.size.height / 1.5
var body: some View {
VStack {
// This is the view that's going to be resized.
ZStack(alignment: .bottomTrailing) {
Text("Hello, world!")
.frame(width: width, height: height)
// This is the "drag handle" positioned on the lower-left corner of this stack.
Text("")
.frame(width: 30, height: 30)
.background(.red)
.gesture(
DragGesture()
.onChanged { value in
// Enforce minimum dimensions.
width = max(100, width + value.translation.width)
height = max(100, height + value.translation.height)
}
)
}
.frame(width: width, height: height)
.border(.red, width: 5)
.background(.yellow)
.padding()
// This position constraint causes the ZStack to grow/shrink in all dimensions
// when resized.
.position(x: 400, y: 400)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
}
你是对的,这个问题是由你的观点引起的center-aligned。
要解决此问题,您可以将视图包裹在 VStack
中并应用不同的对齐方式,例如.topLeading
如果您希望它与 top-left.
您还必须确保此 VStack
占用了可用的 space 视图。否则,它将缩小到可调整大小框的大小,导致视图保持 center-aligned。您可以使用 .frame(maxWidth: .infinity, maxHeight: .infinity)
.
TL;DR
将可调整大小的框放置在带有 .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
修饰符的 VStack
中。
VStack { // <-- Wrapping VStack with alignment modifier
// This is the view that's going to be resized.
ZStack(alignment: .bottomTrailing) {
Text("Hello, world!")
.frame(width: width, height: height)
// This is the "drag handle" positioned on the lower-left corner of this stack.
Text("")
.frame(width: 30, height: 30)
.background(.red)
.gesture(
DragGesture()
.onChanged { value in
// Enforce minimum dimensions.
width = max(100, width + value.translation.width)
height = max(100, height + value.translation.height)
}
)
}
.frame(width: width, height: height, alignment: .topLeading)
.border(.red, width: 5)
.background(.yellow)
.padding()
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
编辑
在 ZStack 上使用额外的 position
修饰符,尝试将 x
和 y
值偏移 width
和 height
的一半以定位相对于 ZStack 的 top-left 原点:
.position(x: 400 + width / 2, y: 400 + height / 2)