Segue跳转时全局隐藏键盘过渡动画的实现方法咨询
嘿,这个注册流程里的键盘跳转动画问题我太懂了,之前做用户引导页的时候也被这个小细节折腾过,给你几个从局部到全局的解决方案,按需选就行:
方案一:局部处理(针对单个Segue)
如果只是特定几个Segue需要处理,直接在源ViewController和目标VC里加几行代码就行:
- 在源VC的
prepare(for:sender:)方法里,禁用动画收起当前键盘:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { super.prepare(for: segue, sender: sender) // 禁用动画收起键盘 UIView.performWithoutAnimation { self.view.endEditing(true) } }
- 在目标VC的
viewWillAppear(_:)里,同样禁用动画让目标文本框成为第一响应者:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 直接让目标文本框获取焦点,无动画 UIView.performWithoutAnimation { self.targetTextField.becomeFirstResponder() } }
这样两个操作都跳过了动画,用户看起来就像键盘直接“移”到了新页面的输入框上,没有关了又开的突兀感。
方案二:全局处理(所有Segue自动生效)
如果整个APP里有很多这种场景,不想每个VC都写重复代码,就用全局扩展+通知监听的方式,一劳永逸:
第一步:给UIWindow加个转场状态标记
先扩展UIWindow,用来记录当前是否正在进行ViewController转场:
import UIKit extension UIWindow { private struct AssociatedKeys { static var isTransitioning = "isTransitioning" } var isTransitioning: Bool { get { return objc_getAssociatedObject(self, &AssociatedKeys.isTransitioning) as? Bool ?? false } set { objc_setAssociatedObject(self, &AssociatedKeys.isTransitioning, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } }
第二步:监听转场通知,标记转场状态
在AppDelegate或者SceneDelegate里注册通知,记录转场的开始和结束:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 监听转场开始 NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "UIViewControllerTransitionCoordinatorDidBeginAnimation"), object: nil, queue: .main) { _ in UIApplication.shared.keyWindow?.isTransitioning = true } // 监听转场结束 NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "UIViewControllerTransitionCoordinatorDidEndAnimation"), object: nil, queue: .main) { _ in UIApplication.shared.keyWindow?.isTransitioning = false } // 监听键盘隐藏通知,取消转场时的键盘动画 NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { notification in guard let window = UIApplication.shared.keyWindow, window.isTransitioning else { return } // 把键盘隐藏动画时长设为0,取消动画 notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] = 0 notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] = UIView.AnimationCurve.linear.rawValue } return true }
第三步:全局让目标VC的输入框自动获取焦点(可选)
如果你的注册流程里每个VC的输入框都需要自动成为第一响应者,可以给UIViewController加个扩展,统一处理:
extension UIViewController { open override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 找到当前VC里的第一个UITextField,自动获取焦点(无动画) if let firstTextField = view.subviews.first(where: { $0 is UITextField }) as? UITextField { UIView.performWithoutAnimation { firstTextField.becomeFirstResponder() } } } }
当然你也可以根据自己的需求调整,比如指定某个tag的文本框,或者用IBOutlet关联的方式。
注意事项
- 如果你用的是导航控制器的push/pop,方案一和方案二都能生效;
- 方案二里的通知名称
UIViewControllerTransitionCoordinatorDidBeginAnimation是系统内部的通知,虽然不是公开API,但实际使用中很稳定; - 如果你的APP支持多场景(iPad分屏),记得把
keyWindow换成当前场景的window。
内容的提问来源于stack exchange,提问作者thelearner
相关产品推荐
相关产品推荐

