Interactive Keyboard Dismiss失效:TextField随键盘交互位移异常
解决SwiftUI中Overlay输入框与键盘交互不同步的问题
问题分析
核心问题在于Overlay层的输入框未绑定键盘高度的动态变化:仅给ScrollView添加了底部内边距适配键盘,但输入框的位置完全独立于键盘高度,导致交互关闭键盘时,输入框无法跟随键盘的实时高度变化同步移动,直到键盘完全消失才会回到原位。同时原代码未利用键盘通知中的系统动画参数,动画曲线和时长与系统键盘不匹配,进一步加剧了视觉错位。
修复方案
- 将Overlay输入框的位置与
keyboardHeight绑定,通过offset实现跟随键盘移动 - 利用键盘通知中的系统动画参数,让UI动画与键盘动画完全同步
- 给Overlay层添加对应动画,确保输入框移动过程平滑
修改后的完整代码
import SwiftUI import Combine struct InteractiveTopKeyboard: View { @State var text = "" @State private var keyboardHeight: CGFloat = 0 @State private var isKeyboardVisible = false private let keyboardWillShow = NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification) private let keyboardWillHide = NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification) var body: some View { NavigationStack { VStack { ScrollView { LazyVStack { ForEach(0..<20, id: \.self) { _ in RoundedRectangle(cornerRadius: 25.0) .foregroundStyle(.blue) .frame(height: 300) .rotationEffect(.degrees(180.0)) .scaleEffect(x: -1, y: 1, anchor: .center) } } } .rotationEffect(.degrees(180.0)) .scaleEffect(x: -1, y: 1, anchor: .center) .scrollDismissesKeyboard(.interactively) .padding(.bottom, keyboardHeight) .animation(.easeOut(duration: 0.3), value: keyboardHeight) } .ignoresSafeArea() .onAppear { addKeyboardObservers() } .onDisappear { removeKeyboardObservers() } .overlay(alignment: .bottom) { HStack { Spacer() TextField("Enter text", text: $text) .padding(.horizontal) .padding(.vertical, 8) .background(.gray) .clipShape(Capsule()) Spacer() } .padding(.top, 5) .padding(.bottom, 30) .background(.ultraThinMaterial) // 绑定输入框位置到键盘高度,实现同步移动 .offset(y: -keyboardHeight) // 给输入框添加动画,保证移动平滑 .animation(.easeOut(duration: 0.3), value: keyboardHeight) } } } private func addKeyboardObservers() { keyboardWillShow .merge(with: keyboardWillHide) .sink { notification in if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect { // 获取系统键盘的动画参数,让UI动画完全匹配 let animationDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double ?? 0.3 withAnimation(Animation.easeOut(duration: animationDuration)) { isKeyboardVisible = notification.name == UIResponder.keyboardWillShowNotification keyboardHeight = isKeyboardVisible ? keyboardFrame.height : 0 } } } .store(in: &cancellables) } private func removeKeyboardObservers() { cancellables.removeAll() } @State private var cancellables: Set<AnyCancellable> = [] }
关键修改点说明
输入框位置绑定:
添加.offset(y: -keyboardHeight),让输入框在键盘弹出时向上移动对应高度,键盘收起时自动回到原位,完全跟随键盘高度变化。同步系统动画:
从键盘通知中提取动画时长参数,确保UI动画的时长与系统键盘完全一致,避免视觉上的错位感。Overlay层动画:
给输入框添加与ScrollView一致的动画绑定,保证输入框移动过程平滑过渡,和键盘的交互体验统一。
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

