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

SwiftUI ScrollView点击下方TextField跳回之前聚焦输入框问题咨询

问题原因

这个滚动回弹属于SwiftUI的已知异常表现,并非预期的正常交互逻辑,触发的核心原因有两个:

  • 你的示例代码中所有TextField都绑定了同一个@State var text变量,当任意输入框触发内容变更时,会导致整个ScrollView视图重绘,SwiftUI的聚焦定位逻辑会错误识别到第一个绑定该变量的输入框位置,触发滚动回弹。
  • SwiftUI ScrollView默认自带的「自动滚动到聚焦响应者」逻辑在多个同类型输入框共存时存在计算误差,优先定位到首个匹配的输入框而非当前点击的输入框。

修复方案

方案1:使用独立状态绑定(优先推荐)

给每个TextField分配独立的状态变量,避免单个输入框变更触发全局重绘。如果需要统一管理所有输入内容,可以用数组形式存储状态:

struct ContentView: View {
    // 按输入框数量初始化对应容量的字符串数组
    @State var textList = Array(repeating: "", count: 18)
    
    var body: some View {
        ScrollView {
            VStack(spacing: 10) {
                ForEach(0..<9, id: \.self) { index in
                    TextField("输入框\(index+1)", text: $textList[index])
                        .frame(height: 55)
                        .frame(maxWidth: .infinity)
                        .background(Color.gray)
                        .foregroundColor(.black)
                }
                ForEach(9..<18, id: \.self) { index in
                    TextField("输入框\(index+1)", text: $textList[index])
                        .frame(height: 55)
                        .frame(maxWidth: .infinity)
                        .background(Color.gray)
                        .foregroundColor(.black)
                }
            }
        }
        // iOS 16+ 新增修饰符,优化键盘与滚动的联动逻辑
        .scrollDismissesKeyboard(.interactively)
        .padding(.horizontal)
        .frame(maxWidth: .infinity)
        .background(Color.white)
    }
}

方案2:兼容低版本手动控制滚动

如果需要兼容iOS 15及更早版本,或确实需要所有输入框绑定同一个变量,可以配合ScrollViewReader和@FocusState手动控制聚焦时的滚动位置,覆盖系统的错误逻辑:

struct ContentView: View {
    @State var text = ""
    @FocusState var focusedIndex: Int?
    
    var body: some View {
        ScrollViewReader { proxy in
            ScrollView {
                VStack(spacing: 10) {
                    ForEach(0..<18, id: \.self) { index in
                        TextField("输入框\(index+1)", text: $text)
                            .frame(height: 55)
                            .frame(maxWidth: .infinity)
                            .background(Color.gray)
                            .foregroundColor(.black)
                            .id(index)
                            .focused($focusedIndex, equals: index)
                    }
                }
            }
            .onChange(of: focusedIndex) { newValue in
                guard let index = newValue else { return }
                // 手动滚动到当前聚焦的输入框位置
                withAnimation {
                    proxy.scrollTo(index, anchor: .center)
                }
            }
            .padding(.horizontal)
            .frame(maxWidth: .infinity)
            .background(Color.white)
        }
    }
}

临时全局配置

如果改动成本较高,可以先在页面初始化时配置UIScrollView的全局行为,缓解该问题:

init() {
    UIScrollView.appearance().keyboardDismissMode = .onDrag
    UIScrollView.appearance().contentInsetAdjustmentBehavior = .scrollableAxes
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 20:27:02