SwiftUI -如何获得新创建按钮的准确中心坐标/位置



我是swift的新手,我遇到了一个问题,我在网上搜索了一整天,但仍然没有找到解决方案。

有一个类似的问题,我也尝试使用同步手势来获得位置,但它相当不精确,并且在我拖动的方向上有相对偏差。所以我想知道有没有其他的方法来调用我的代码后按钮渲染,也给我的按钮的参考,以便我可以得到的位置?我发现我可以使用startLocation属性,但它可能不是按钮的中心点,因为它取决于用户拖动的起始位置。

SwiftUI -如何获得坐标/位置点击按钮

问题:如何获得x和y位置相对于屏幕的按钮渲染后?

我的目标:我想根据指定按钮的位置生成一些其他视图。一旦用户按下该按钮,它和其他几个视图就会弹出,当用户释放该按钮时就会消失。因此需要一个精确的原始位置来计算新的位置。

这个功能我想创建是有点像游戏应用程序,但我试图创建一个正常的简单的应用程序。非常感谢它,如果有人能帮助!

实现这一目标的一种方法是使用"锚点首选项"。

这个想法是,创建按钮的边界锚并将其存储到锚首选项中。

为了获得一个实际的边界值,我们需要一个GeometryProxy,在那里我们关联边界锚并获得边界值。

当我们有了边界值,我们将它存储在一个状态变量中,当按钮动作执行时,它们可以被访问。

下面的解决方案创建了许多按钮,这些按钮的边界可以通过Dictionary访问,其中键是按钮的标签。

import SwiftUI
struct ContentView: View {
let labels = (0...4).map { "- ($0) -" }
@State private var bounds: [String: CGRect] = [:]
var body: some View {
VStack {
ForEach(labels, id: .self) { label in
Button(action: {
let bounds = bounds[label]
print(bounds ?? "")
}) {
Text(verbatim: label)
}
// Store bounds anchors into BoundsAnchorsPreferenceKey:
.anchorPreference(
key: BoundsAnchorsPreferenceKey.self,
value: .bounds,
transform: { [label: $0] })
}
}
.frame(width: 300, height: 300, alignment: .center)
.backgroundPreferenceValue(BoundsAnchorsPreferenceKey.self) { anchors in
// Get bounds relative to VStack:
GeometryReader { proxy in
let localBoundss = anchors.mapValues { anchor in
CGRect(origin: proxy[anchor].origin, size: proxy[anchor].size)
}
Color.clear.border(Color.blue, width: 1)
.preference(key: BoundsPreferenceKey.self, value: localBoundss)
}
}
.onPreferenceChange(BoundsPreferenceKey.self) { bounds in
// Store bounds into the state variable:
self.bounds = bounds
}
}
}
extension CGRect: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(origin.x)
hasher.combine(origin.y)
hasher.combine(size.width)
hasher.combine(size.height)
}
}
struct BoundsAnchorsPreferenceKey: PreferenceKey {
typealias Value = [String: Anchor<CGRect>]
static var defaultValue: Value = [:]
static func reduce(value: inout Value, nextValue: () -> Value) {
value = value.merging(nextValue()) { (_, new) in new }
}
}
struct BoundsPreferenceKey: PreferenceKey {
typealias Value = [String:  CGRect]
static var defaultValue: Value = [:]
static func reduce(value: inout Value, nextValue: () -> Value) {
value = value.merging(nextValue()) { (_, new) in new }
}
}

import PlaygroundSupport
PlaygroundPage.current.setLiveView(
NavigationView {
ContentView()
}
.navigationViewStyle(.stack)
)

解决方案看起来有点复杂,但没有使用任何"技巧"。我们可以使用ViewModifiers来缓解这个问题。

最新更新