swift - SwiftUI - 如何获取单击按钮的坐标/位置
问题描述
简短版:如何Button
在 SwiftUI 中获取点击的坐标?
我正在寻找这样的东西(伪代码),geometry.x
当前视图中单击的按钮的位置在哪里:
GeometryReader { geometry in
return Button(action: { self.xPos = geometry.x}) {
HStack {
Text("Sausages")
}
}
}
长版:我开始使用 SwiftUI 和 Swift,所以想知道如何在概念上最好地实现这一点。
举一个我正在玩的具体例子:
想象一个标签系统,我想将下划线指示器移动到单击按钮的位置。
[旁白]这篇文章中有一个答案,它在视觉上做了我想要的,但它似乎相当复杂:如何在 SwiftUI 中查看另一个视图的大小 [/aside]
这是我的外部结构,它构建了标签栏和我试图调整大小和位置的矩形(当前指示器):
import SwiftUI
import UIKit
struct TabBar: View {
var tabs:ITabGroup
@State private var selected = "Popular"
@State private var indicatorX: CGFloat = 0
@State private var indicatorWidth: CGFloat = 10
@State private var selectedIndex: Int = 0
var body: some View {
ScrollView(.horizontal) {
HStack(spacing: 0) {
ForEach(tabs.tabs) { tab in
EachTab(tab: tab, choice: self.$selected, tabs: self.tabs, x: self.$indicatorX, wid: self.$indicatorWidth)
}
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 40, maxHeight: 40).padding(.leading, 10)
.background(Color(UIColor(hex: "#333333")!))
Rectangle()
.frame(width: indicatorWidth, height: 3 )
.foregroundColor(Color(UIColor(hex: "#1fcf9a")!))
.animation(Animation.spring())
}.frame(height: 43, alignment: .leading)
}
}
这是我的结构,它创建每个选项卡项并包含一个嵌套func
以获取单击项的宽度:
struct EachTab: View {
// INCOMING!
var tab: ITab
@Binding var choice: String
var tabs: ITabGroup
@Binding var x: CGFloat
@Binding var wid: CGFloat
@State private var labelWidth: CGRect = CGRect()
private func tabWidth(labelText: String, size: CGFloat) -> CGFloat {
let label = UILabel()
label.text = labelText
label.font = label.font.withSize(size)
let labelWidth = label.intrinsicContentSize.width
return labelWidth
}
var body: some View {
Button(action: { self.choice = self.tab.title; self.x = HERE; self.wid = self.tabWidth(labelText: self.choice, size: 13)}) {
HStack {
// Determine Tab colour based on whether selected or default within black or green rab set
if self.choice == self.tab.title {
Text(self.tab.title).foregroundColor(Color(UIColor(hex: "#FFFFFF")!)).font(.system(size: 13)).padding(.trailing, 10).animation(nil)
} else {
Text(self.tab.title).foregroundColor(Color(UIColor(hex: "#dddddd")!)).font(.system(size: 13)).padding(.trailing, 10).animation(nil)
}
}
}
// TODO: remove default transition fade on button click
}
}
创建一个非 SwiftUIUILabel
来获取宽度Button
似乎有点不稳定。有没有更好的办法?
有没有一种简单的方法来获取点击的 SwiftUI 的坐标Button
?
解决方案
您可以使用最小拖动距离为 0 的 DragGesture 识别器,它为您提供位置信息。但是,如果将 DragGesture 与按钮结合使用,则在正常单击按钮时不会触发拖动手势。只有当拖动在按钮之外结束时才会触发。
您可以完全摆脱按钮,但当然会丢失默认按钮样式。
在这种情况下,视图将如下所示:
struct MyView: View {
@State var xPos: CGFloat = 0
var body: some View {
GeometryReader { geometry in
HStack {
Text("Sausages: \(self.xPos)")
}
}.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global).onEnded { dragGesture in
self.xPos = dragGesture.location.x
})
}
}
该coordinateSpace
参数指定您是否希望触摸位置在.local
或.global
空间中。在本地空间中,位置相对于您已将手势附加到的视图。例如,如果我Text
在屏幕中间有一个视图,我的本地y
位置将几乎为 0,而我的全局位置将是y
屏幕高度的一半。
这让我有点吃惊,但这个例子展示了这个想法:
struct MyView2: View {
@State var localY: CGFloat = 0
@State var globalY: CGFloat = 0
var body: some View {
VStack {
Text("local y: \(self.localY)")
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local).onEnded { dragGesture in
self.localY = dragGesture.location.y
})
Text("global y: \(self.globalY)")
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global).onEnded { dragGesture in
self.globalY = dragGesture.location.y
})
}
}
}
推荐阅读
- python - 如何使用值符合条件的列名填充熊猫数据框中的列?
- java - JDBC 查询运行很慢
- node.js - 升级到 Nodejs 12.2 后解构赋值目标异常无效
- php - 我如何在 Elastic Search 中获得完全匹配过滤器结果
- java - 验证服务器到服务器的通信
- typo3 - 如何设置 tt_address 4.x 以使用 TYPO3 9 LTS 中的 insert_records
- javascript - req.checkBody 不是函数,express-validator 中间件不起作用
- php - array_push 与多维数组
- css - 如何使波浪下划线延伸覆盖Chrome中的所有字符
- numpy - Distributions.jl 不接受我的(非正定)协方差函数(而 numpy 接受)