ios - 使用 DragGesture 调整 SwiftUI View 的框架会在所有维度上调整其大小

标签 ios swift swiftui

我正在尝试在 SwiftUI 中实现一个简单的 View ,可以通过放置在其左下角的拖动 handle 来调整大小。可调整大小的 View 的尺寸是通过两个控制宽度和高度的 @State 变量设置的。这些变量在拖动 handle 捕获的 DragGesture 的 onChanged 处理程序中发生变化。

这有点起作用,但不是我期望的那样。当我在拖动 handle 上执行拖动手势时, View 的所有维度都会调整大小。我希望调整大小的方式与桌面窗口相同;拖动不应在所有方向上调整 View 大小。

下面是 iOS 模拟器的记录,显示了不正确的行为:

Resizing the view

我知道 SwiftUI View 的中心被认为是它的起源,这可能就是导致这种行为的原因。我不知道如何解决这个问题。

这是我的代码:

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 上添加了一个位置约束,该约束用于另一个手势(未显示),以便可以拖动 View 。

我猜这是有问题的,因为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)
    }
}

最佳答案

您说得对,问题是由您的 View 居中对齐引起的。

要解决此问题,您可以将 View 包装在 VStack 中,并应用不同的对齐方式,例如.topLeading 如果您希望它与左上角对齐。

您还必须确保此VStack 占用了 View 的可用空间。否则,它将缩小到可调整大小的框的大小,导致 View 保持中心对齐。您可以使用 .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 修饰符,尝试将 xy 值偏移 宽度的一半 code> 和 height 相对于 ZStack 左上角原点的位置:

.position(x: 400 + width / 2, y: 400 + height / 2)

关于ios - 使用 DragGesture 调整 SwiftUI View 的框架会在所有维度上调整其大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71890404/

相关文章:

ios - 在 swift 中使用本地化字符串进行枚举

ios - VStack 的帧大小没有填满整个屏幕

swift - 在 Swift 中从 NSTextView 获取文本

ios - 在 Swift 中使用选择器的正确方法

ios - 如何在swiftUI中显示登录 View 后的 View

firebase - 当一个函数需要前一个函数的值时,用于 Firebase 实时数据库查找的完成处理程序

ios - View 框架高度降低并出现黑条

ios - SFAuthenticationSession 如何在 Safari 中存储 session 相关的 cookie

iphone - 调用了 numberOfRowsInSection 但未调用 cellForRowAtIndexPath

ios - Firebase iOS - 当我知道一个值存在时,快照突然返回 null