ios ScrollViewReader ScrollTo notWorking

zynd9foi  于 12个月前  发布在  iOS
关注(0)|答案(1)|浏览(84)

我正在创建一个水平菜单,我使用水平ScrollViewHStack来查看它的项目。一切似乎都工作,但我有一个问题与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)
    }
}

字符串

wtzytmuj

wtzytmuj1#

scrollTo获取您要滚动到的视图的id。您所有的按钮都具有由ForEach自动给出的id,这是itemsT的对应值,而不是Int索引号。
如果你想使用索引作为id,你应该在按钮上添加.id(index)
然而,索引是相当不稳定的--每当你添加/删除一个标签时,它们都会改变。我建议使用Binding<T>来表示当前标签。

@Binding var currentTab: T
var body: some View {
              
    ScrollView(.horizontal) {
        ScrollViewReader { proxy in
            HStack {
                ForEach(items) { screen in
                    let index = items.firstIndex(of: screen)!
                    Button {
                        currentTab = screen
                    } label: {
                        Text(screen[keyPath: title])
                            .padding()
                            .overlay(alignment: .bottom){
                                if currentTab == screen  {
                                    RoundedRectangle(cornerRadius: 6)
                                        .frame(height: 1)
                                        .matchedGeometryEffect(id: "AninamtionTAB", in: animation)
                                }
                            }
                    }
                    .buttonStyle(.plain)
                }
            }
            .onChange(of: currentTab, { _, newValue in
                withAnimation {
                    proxy.scrollTo(newValue, anchor: .leading)
                }
            })

字符串
请注意,现在您甚至不需要添加自己的.id(screen)-ForEach自动分配给按钮的id正是我们希望它们拥有的id。
在这种情况下使用.paging的滚动行为是相当奇怪的。页面不一定与标签按钮对齐,所以当你点击一个标签时,按钮会向左滚动,并且可能会被“切断”,因为这恰好是一个新的“页面”开始的地方。
我更喜欢使用.scrollTargetBehavior(.viewAligned),并将HStack设置为.scrollTargetLayout()
我也不会使用KeyPath<T, String>。这不允许本地化。我会接受(T) -> Text(T) -> Label,其中Label是限制为View的泛型类型参数。

相关问题