我正在创建一个水平菜单,我使用水平ScrollView
和HStack
来查看它的项目。一切似乎都工作,但我有一个问题与ScrollViewReader
..正如你应该从代码时,currentIndex
的变化,我将其值传递给proxy.scrollTo()
方法,但我没有得到任何结果,ScrollView
没有按照currentIndex
的修改保持在原来的位置。你能告诉我哪里出错了吗?谢谢大家
struct ScrollableTabMenu<T:CaseIterable & Hashable & Identifiable>: View {
var items: [T]
var title: KeyPath<T, String>
@Binding var currentIndex: Int
@Namespace private var animation
var body: some View {
ScrollView(.horizontal) {
ScrollViewReader { proxy in
HStack {
ForEach(items) { screen in
let index = items.firstIndex(of: screen)!
Button {
currentIndex = index
} label: {
Text(screen[keyPath: title])
.padding()
.overlay(alignment: .bottom){
if currentIndex == index {
RoundedRectangle(cornerRadius: 6)
.frame(height: 1)
.matchedGeometryEffect(id: "AninamtionTAB", in: animation)
}
}
}
.buttonStyle(.plain)
}
}
.onChange(of: currentIndex, { _, newValue in
withAnimation {
proxy.scrollTo(newValue, anchor: .leading)
print(newValue)
}
})
}
}
.scrollTargetBehavior(.paging)
.scrollIndicators(.hidden)
.contentMargins(.horizontal, 16)
}
}
字符串
1条答案
按热度按时间wtzytmuj1#
scrollTo
获取您要滚动到的视图的id。您所有的按钮都具有由ForEach
自动给出的id,这是items
中T
的对应值,而不是Int
索引号。如果你想使用索引作为id,你应该在按钮上添加
.id(index)
。然而,索引是相当不稳定的--每当你添加/删除一个标签时,它们都会改变。我建议使用
Binding<T>
来表示当前标签。字符串
请注意,现在您甚至不需要添加自己的
.id(screen)
-ForEach
自动分配给按钮的id正是我们希望它们拥有的id。在这种情况下使用
.paging
的滚动行为是相当奇怪的。页面不一定与标签按钮对齐,所以当你点击一个标签时,按钮会向左滚动,并且可能会被“切断”,因为这恰好是一个新的“页面”开始的地方。我更喜欢使用
.scrollTargetBehavior(.viewAligned)
,并将HStack
设置为.scrollTargetLayout()
。我也不会使用
KeyPath<T, String>
。这不允许本地化。我会接受(T) -> Text
或(T) -> Label
,其中Label
是限制为View
的泛型类型参数。