我正在尝试在 SwiftUI 中实现带有文本标记的离散洗涤器,如下所示。我的问题是我无法确定先验HStack
内部的高度ScrollView
,因此我尝试使用onGeometryChange
修饰符,但它不起作用(即覆盖文本被截断)。一种解决方法是使用并根据几何代理GeometryReader
分配高度,但我想知道是否有另一种不使用的方法。HStack
GeometryReader
struct ScrollScrubber: View {
var config:ScrubberConfig
@State var viewSize:CGSize?
var body: some View {
let horizontalPadding = (viewSize?.width ?? 0)/2
ScrollView(.horizontal) {
HStack(spacing:config.spacing) {
let totalSteps = config.steps * config.count
ForEach(0...totalSteps, id: \.self) { index in
let remainder = index % config.steps
Divider()
.background( remainder == 0 ? Color.primary : Color.gray)
.frame(width: 0, height: remainder == 0 ? 20 : 10, alignment: .center)
.frame(maxHeight: 20, alignment: .bottom)
.overlay(alignment: .bottom) {
if remainder == 0 {
Text("\(index / config.steps)")
.font(.caption)
.fontWeight(.semibold)
.textScale(.secondary)
.fixedSize()
.offset(y:20)
}
}
}
}
.frame(height:viewSize?.height)
}
.scrollIndicators(.hidden)
.safeAreaPadding(.horizontal, horizontalPadding)
.onGeometryChange(for: CGSize.self) { proxy in
proxy.size
} action: { newValue in
viewSize = newValue
print("View Size \(newValue)")
}
}
}
struct ScrubberConfig:Equatable {
var count:Int
var steps:Int
var spacing:CGFloat
}
#Preview {
ScrollScrubber(config: .init(count: 100, steps: 5, spacing: 5.0))
.frame(height:60)
}
如果您确实希望滚动视图的高度占据所有可用空间,那么
GeometryReader
在这里使用是完全合适的。这没有什么错。否则,您必须使用其他填充可用空间的视图(例如Color.clear
),并测量该视图的几何形状。显然,只使用 a
GeometryReader
更方便。在这个特殊情况下,如果您只想阻止
Text
s 被剪切,您可以通过放置滚动视图来禁用剪切scrollClipDisabled()
。无需执行任何与几何相关的操作,您可以删除frame
滚动视图上的 。请注意,
Text
s 仍将在 的边界之外ScrollView
。如果您希望它们在边界内,请考虑使用 来VStack
布局刻度线和文本:这假设所有文本都具有相同的高度。如果您不能假设这一点,您可以
Text
使用首选项键找到所有 s 的最大高度。然后,将 的高度设置HStack
为文本的最大高度加上分隔符的最大高度(即 20)。