求助:获取ScrollView内按钮点击位置的优化方案
解决方案:利用背景层嵌入GeometryReader
你可以把GeometryReader放到按钮的.background修饰符中,这样它会自动匹配按钮的实际尺寸(包括不同语言文本的宽度),不会撑满父视图空间。这种方式既保留了获取位置的能力,又能让按钮自适应内容宽度。
修改后的代码:
Button(action: { isFilterShown = true }) { HStack { Image(systemName: "slider.horizontal.3") .font(.system(size: 18, weight: .light)) .foregroundColor(Color(.label)) Text("_filter_") .font(.regular(size: 16)) .foregroundColor(Color(.label)) } .padding(8) .background( GeometryReader { geometry in Color.clear // 透明背景,不影响视觉 .preference(key: ButtonPositionKey.self, value: geometry.frame(in: .global)) } ) .onPreferenceChange(ButtonPositionKey.self) { newPosition in optionPosition = newPosition } .background(RoundedRectangle(cornerRadius: 8).fill(Color(.secondarySystemBackground))) } // 定义PreferenceKey用来传递位置信息 private struct ButtonPositionKey: PreferenceKey { static var defaultValue: CGRect = .zero static func reduce(value: inout CGRect, nextValue: () -> CGRect) { value = nextValue() } }
关键细节说明:
- 自适应尺寸:
GeometryReader作为按钮内容的背景存在,它的尺寸会完全贴合按钮的实际大小,自动适配不同语言文本的宽度,不会像原来那样撑满父视图。 - 精准位置传递:通过
PreferenceKey传递位置信息,能确保获取到滚动后的最新坐标——因为每次ScrollView滚动时,按钮的位置变化会触发GeometryReader更新,进而同步更新optionPosition。 - 无视觉干扰:用
Color.clear作为GeometryReader的背景,不会改变按钮原有的视觉样式。
简化替代方案(仅点击时获取位置):
如果不需要实时跟踪按钮位置,只在点击瞬间获取的话,也可以用UIViewRepresentable封装一个轻量视图,但上面的PreferenceKey方案更贴合SwiftUI原生开发逻辑。
内容的提问来源于stack exchange,提问作者Son Le
相关产品推荐
相关产品推荐

