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

iOS 15/Xcode 13环境下如何让ScrollView在键盘弹出时保持当前滚动位置?

解决iOS15下ScrollView键盘弹出时保持滚动位置的问题

嘿,我刚好在iOS15/Xcode13环境下做过类似的需求,完全懂你想要的Messenger那种键盘弹出时滚动位置丝毫不乱的效果!默认情况下系统会自动上移ScrollView内容导致位置偏移,咱们手动接管这个逻辑就能实现,直接看修改后的代码和解释:

修改后的完整代码

import SwiftUI

struct TestKeyboardScrollView2: View {
    @State var textfield: String = ""
    // 保存当前滚动到的行索引
    @State private var currentScrollIndex: Int? = nil
    // 记录键盘高度,用来调整内容内边距
    @State private var keyboardHeight: CGFloat = 0
    
    var body: some View {
        VStack {
            ScrollViewReader { proxy in
                ScrollView {
                    LazyVStack {
                        ForEach(1...100, id: \.self) { index in
                            Text("Row \(index)")
                                .id(index) // 给每一行设置唯一标识,方便定位
                                .onAppear {
                                    // 当行出现在屏幕上时,更新当前滚动的索引
                                    currentScrollIndex = index
                                }
                        }
                    }
                    // 底部内边距随键盘高度变化,避免内容被键盘遮挡
                    .padding(.bottom, keyboardHeight)
                }
                .onChange(of: keyboardHeight) { newHeight in
                    // 键盘弹出时,滚动回之前记录的位置
                    if let index = currentScrollIndex, newHeight > 0 {
                        withAnimation(.interactiveSpring()) {
                            proxy.scrollTo(index, anchor: .top)
                        }
                    }
                }
            }
            
            TextField("Write here...", text: $textfield)
                .textFieldStyle(.roundedBorder)
        }
        .padding()
        .onAppear {
            // 监听键盘弹出通知
            NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { notification in
                guard let userInfo = notification.userInfo,
                      let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
                // 计算实际键盘高度(减去底部安全区域,避免多算刘海屏的底部间距)
                keyboardHeight = keyboardFrame.height - (UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0)
            }
            
            // 监听键盘收起通知
            NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in
                keyboardHeight = 0
            }
        }
        .onDisappear {
            // 页面消失时移除通知监听,避免内存泄漏
            NotificationCenter.default.removeObserver(self)
        }
    }
}

核心逻辑解释

  1. ScrollViewReader的作用:它是iOS14+引入的组件,能让我们手动控制ScrollView的滚动位置,这里用来在键盘弹出时精准定位回之前的行。
  2. 记录当前滚动位置:通过给每一行添加onAppear,实时更新currentScrollIndex,这样我们就能知道当前屏幕上显示的是哪一行。
  3. 键盘通知监听:获取键盘的高度,动态调整ScrollView底部的内边距,既避免内容被键盘挡住,又能触发滚动恢复的逻辑。
  4. 平滑滚动恢复:用withAnimation配合scrollTo方法,让滚动恢复的动画和系统键盘弹出的动画保持一致,体验更自然。

测试的时候你滚动到第100行,点击TextField弹出键盘,ScrollView会稳稳停在第100行,完全符合你想要的Messenger交互效果~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 18:37:41