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

SwiftUI实现ScrollView随键盘弹出自动上移的问题求助

解决SwiftUI ScrollView键盘适配问题(仿WhatsApp/Telegram聊天界面)

核心思路

要实现键盘弹出时ScrollView内容自动上移并聚焦最后一条消息,需要两步:

  • 监听键盘高度变化,动态调整布局内边距/偏移
  • 结合ScrollViewReader在键盘弹出时自动滚动到最后一项

具体实现代码

修改你的代码,添加键盘监听和自动滚动逻辑:

import SwiftUI

struct ChatView: View {
    @State private var fullText = ""
    @State private var selectedIndex = 0
    @State private var keyboardHeight: CGFloat = 0 // 存储键盘高度
    private let colors: [Color] = [.red, .blue, .green, .orange]
    
    // 保留你原有计算item尺寸的逻辑
    private func height(index: Int) -> CGFloat {
        index == selectedIndex ? 100 : 60
    }
    
    var body: some View {
        ZStack {
            ScrollViewReader { proxy in
                Button("Move to #8") {
                    withAnimation {
                        proxy.scrollTo(8)
                        selectedIndex = 8
                    }
                }
                
                ScrollView(.vertical, showsIndicators: false) {
                    LazyVStack(spacing: 10) {
                        ForEach(0...50, id: \.self) { index in
                            Text("Item \(index)")
                                .font(.title)
                                .foregroundStyle(.white)
                                .frame(width: height(index: index), height: height(index: index))
                                .background(colors[index % colors.count])
                                .cornerRadius(8)
                                .id(index)
                        }
                    }
                    .padding(.bottom, keyboardHeight + 10) // 动态留出键盘空间
                }
                // 键盘弹出时自动滚动到最后一项
                .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
                    guard let info = notification.userInfo,
                          let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
                    
                    keyboardHeight = keyboardFrame.height
                    
                    withAnimation(.easeOut(duration: 0.25)) {
                        proxy.scrollTo(50, anchor: .bottom) // 滚动到最后一个item
                    }
                }
                // 键盘收起时恢复状态
                .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
                    withAnimation(.easeOut(duration: 0.25)) {
                        keyboardHeight = 0
                    }
                }
                // 支持滑动收起键盘
                .keyboardDismissMode(.interactive)
            }
            
            VStack {
                TextField("Message", text: $fullText)
                    .textFieldStyle(.roundedBorder)
            }
            .padding(.horizontal)
            .padding(.bottom, keyboardHeight) // 让输入框跟着键盘上移
            .frame(maxHeight: .infinity, alignment: .bottom)
        }
        .padding()
    }
}

关键细节说明

  • 键盘高度监听:通过NotificationCenter捕获键盘显示/隐藏事件,获取实际高度后动态调整布局内边距
  • 自动滚动逻辑:键盘弹出时调用scrollTo,将最后一条内容锚定到视图底部,确保不被键盘遮挡
  • 平滑过渡:用withAnimation包裹状态变化,让键盘弹出/收起时的布局切换更自然
  • 输入框适配:给底部TextField添加对应键盘高度的底部padding,保证输入框始终处于键盘上方

扩展优化建议

  • 如果消息是动态加载的(比如从接口获取),把固定的50替换为消息数组的count - 1,实现动态滚动到最新消息
  • 可以增加判断逻辑:仅当最后一条消息原本就在视图底部时,才触发自动滚动,避免打断用户手动滚动的操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:22:55