You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI结合Slider与Button实现scrollTo滚动定位异常问题排查

修复方案

问题原因梳理

  1. 滚动先跳顶部的问题:
  • 你没有给Section绑定对应的id标识,scrollTo找不到目标视图就会先滚到列表顶部,再响应后续的定位逻辑;另外你Slider设置的最大值是42,但实际只定义了8-29层的Section,滑动到29以上的不存在的id也会触发跳顶部的问题。
  • 列表默认适配导航栏大标题的安全区域,滚动时锚点计算会有偏差,你代码里VStack顶部额外加的Spacer也会干扰布局计算。
  1. 按钮点击无法滚动的问题:
  • @State属性修改后不会立刻生效,你修改sliderValue后立即调用scrollTo取到的还是旧值,自然匹配不到目标Section。

修正代码

struct Floors: Identifiable {
    let id: String
    let name: String
}
struct UnitLine: Identifiable {
    let id = UUID()
    let name: String
}
 
struct UnitKeyboardView: View {
    @Environment(\.presentationMode) var presentationMode
    @State private var sliderValue = 8.0
    
    var body: some View {
        let floors = [Floors(id:"8",name:"8"),Floors(id:"9",name:"9"),Floors(id:"10",name:"10"),Floors(id:"11",name:"11"),Floors(id:"12",name:"12"),Floors(id:"13",name:"13"),Floors(id:"14",name:"14"),Floors(id:"15",name:"15"),Floors(id:"16",name:"16"),Floors(id:"17",name:"17"),Floors(id:"18",name:"18"),Floors(id:"19",name:"19"),Floors(id:"20",name:"20"),Floors(id:"21",name:"21"),Floors(id:"22",name:"22"),Floors(id:"23",name:"23"),Floors(id:"24",name:"24"),Floors(id:"25",name:"25"),Floors(id:"26",name:"26"),Floors(id:"27",name:"27"),Floors(id:"28",name:"28"),Floors(id:"29",name:"29")]
        let unitlines = [UnitLine(name:"01"),UnitLine(name:"02"),UnitLine(name:"03"),UnitLine(name:"04"),UnitLine(name:"05"),UnitLine(name:"06"),UnitLine(name:"07"),UnitLine(name:"08")]
        
        NavigationView {
            ScrollViewReader { proxy in
                VStack(spacing: 0) {
                    List {
                        ForEach(floors) { i in
                            Section(header: Text("Floor \(i.name)")) {
                                ForEach(unitlines) { u in
                                    Text(u.name)
                                        .padding(.trailing,200)
                                        .contentShape(Rectangle())
                                        .onTapGesture {
                                            print("tapped")
                                            presentationMode.wrappedValue.dismiss()
                                        }
                                }
                            }
                            .id(i.id) // 给Section绑定id,供scrollTo定位
                        }
                    }
                    .listStyle(.grouped) // 显式指定列表样式,避免系统默认样式差异导致的布局跳动
          
                    HStack {
                        Spacer()
                        
                        Text("Flr: \(Int(sliderValue))")
                            .font(.title)
                            .padding(10)
                        
                        Button {
                            if sliderValue > 8 {
                                let newValue = sliderValue - 1.0
                                sliderValue = newValue
                                // 直接用计算好的新值定位,不用等State更新
                                proxy.scrollTo(String(Int(newValue)), anchor: .topLeading)
                            }
                        } label: {
                            Image(systemName: "minus")
                        }
                        .frame(width:30, height:15)
                        .padding(10)
                        .background(Color.red)
                        .clipShape(Capsule())
                        
                                             
                        Slider(value: $sliderValue, in: 8...29, step: 1.0, onEditingChanged: { _ in
                            // 最大值改为29,和实际楼层数量匹配,避免滚动到不存在的id
                            withAnimation {
                                proxy.scrollTo(String(Int(sliderValue)), anchor: .topLeading)
                            }
                        })
                            .background(Color.cyan)
                            .border(Color.blue, width: 1)
                            .padding(10)

                        Button {
                            if sliderValue < 29 {
                                let newValue = sliderValue + 1.0
                                sliderValue = newValue
                                // 直接用计算好的新值定位
                                proxy.scrollTo(String(Int(newValue)), anchor: .topLeading)
                            }
                        } label: {
                            Image(systemName: "plus")
                        }
                            .frame(width:30, height:15)
                            .padding(10)
                            .background(Color.green)
                            .clipShape(Capsule())
                        Spacer()
                    }
                    .background(Color.gray)
                }
            }
            .navigationTitle("Select Address")
            // 如果不需要大标题,可加下面这行彻底避免导航栏高度变化导致的跳动
            // .navigationBarTitleDisplayMode(.inline)
        }
    }
}

内容的提问来源于stack exchange,提问作者Dave

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 13:54:02