ScrollViewReader的scrollTo方法失效:水平菜单滚动不跟随currentIndex变化求助
问题排查与修复
核心问题1:ScrollViewReader的嵌套顺序错误
你的代码把ScrollViewReader放在了ScrollView内部,这会导致滚动代理(proxy)无法正确关联到外部的ScrollView,自然无法触发滚动操作。必须让ScrollViewReader包裹ScrollView,才能让proxy获取到正确的滚动上下文。
核心问题2:scrollTo的目标ID不匹配
你调用proxy.scrollTo(newValue)时传入的是Int类型的index,但ScrollView里的可滚动元素是T类型的菜单项(ForEach遍历的是items数组的元素),两者ID类型不匹配,proxy找不到对应的滚动目标,所以没反应。
修复后的完整代码
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 { // 调整ScrollViewReader位置,包裹ScrollView ScrollViewReader { proxy in ScrollView(.horizontal) { HStack { // 用enumerated()遍历,避免强制解包索引 ForEach(Array(items.enumerated()), id: \.element.id) { index, screen in 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) // 给每个按钮绑定index作为ID,和scrollTo目标匹配 .id(index) } } .onChange(of: currentIndex, { _, newValue in withAnimation { proxy.scrollTo(newValue, anchor: .leading) print(newValue) } }) } .scrollTargetBehavior(.paging) .scrollIndicators(.hidden) .contentMargins(.horizontal, 16) } } }
额外优化说明
- 用
Array(items.enumerated())遍历替代firstIndex(of:)!,避免强制解包带来的崩溃风险 - 如果需要让选中项滚动到视图中间,可将
anchor: .leading改为anchor: .center
内容的提问来源于stack exchange,提问作者kAiN
相关产品推荐
相关产品推荐

