Highlight
iOS 17 将键盘移至独立进程以提升安全性和内存效率,同时增强了
UIKeyboardLayoutGuide,新增followsUndockedKeyboard、usesBottomSafeArea和keyboardDismissPadding属性,让开发者用 Auto Layout 约束即可处理浮动键盘、分屏场景和键盘收起动画,无需手动计算键盘高度。
核心内容
进程外键盘(Out-of-Process Keyboard)
iOS 17 中,键盘的视图和逻辑从 App 进程中独立出来。这带来两个好处:
- 安全性:App 无法直接接触键盘进程中的用户输入,减少隐私泄露风险
- 内存效率:整个系统只需一个键盘实例,而不是每个 App 各一份
对大多数 App 这个变化是透明的。但如果代码对文本输入、选择变化的时序特别敏感,需要注意新的异步行为。
Stage Manager 带来的布局挑战
全屏模式下,键盘适配很简单:把视图上移键盘高度即可。但 Stage Manager 打破了这一假设:
- App 可能不是全屏的,键盘场景和 App 窗口不再对齐
- 需要计算的是键盘和 App 窗口的交集高度,而不是键盘的完整高度
- 多个窗口可能同时存在,每个都需要独立的适配计算
传统的 UIKeyboardWillShowNotification 方式在 Stage Manager 下需要额外处理屏幕坐标转换和多窗口场景。
UIKeyboardLayoutGuide 增强
iOS 15 引入的 UIKeyboardLayoutGuide 在 iOS 17 中获得三项新能力:
followsUndockedKeyboard:控制是否跟踪浮动键盘的位置变化usesBottomSafeArea:控制键盘收起时布局是否回到安全区域底部keyboardDismissPadding:设置键盘收起时的额外间距
Messages 和 Spotlight 都已迁移到 UIKeyboardLayoutGuide 方案,Apple 建议开发者优先使用这种方式,而非手动监听键盘通知。
详细内容
基础用法:Keyboard Layout Guide
(06:21)
// 将文本视图底部与键盘顶部对齐
view.keyboardLayoutGuide.topAnchor.constraint(
equalTo: textView.bottomAnchor
).isActive = true
关键点:
keyboardLayoutGuide是UIView的属性,代表键盘在视图坐标系中的布局区域topAnchor对应键盘的顶部边界- 当键盘弹出时,
topAnchor自动上移,带动约束的视图一起移动 - 当键盘收起时,
topAnchor回到屏幕底部,视图自动复位 - 无需手动监听通知,Auto Layout 自动处理动画
控制安全区域行为:usesBottomSafeArea
(07:56)
// 禁用底部安全区域,让键盘收起时布局回到视图底部而非安全区域
view.keyboardLayoutGuide.usesBottomSafeArea = false
// 文本框顶部与背景顶部保持系统间距
textField.topAnchor.constraint(
equalToSystemSpacingBelow: backdrop.topAnchor,
multiplier: 1.0
).isActive = true
// 键盘顶部至少在文本框底部一个系统间距之下
view.keyboardLayoutGuide.topAnchor.constraint(
greaterThanOrEqualToSystemSpacingBelow: textField.bottomAnchor,
multiplier: 1.0
).isActive = true
// 键盘顶部与背景底部对齐(键盘收起时)
view.keyboardLayoutGuide.topAnchor.constraint(
equalTo: backdrop.bottomAnchor
).isActive = true
// 安全区域底部始终不低于文本框底部
view.safeAreaLayoutGuide.bottomAnchor.constraint(
greaterThanOrEqualTo: textField.bottomAnchor
).isActive = true
关键点:
usesBottomSafeArea = false让键盘收起时keyboardLayoutGuide.topAnchor回到视图底部,而不是安全区域底部- 这对需要填满整个屏幕的布局很重要
greaterThanOrEqualToSystemSpacingBelow确保键盘和文本框之间至少有一个系统间距- 多条约束组合处理键盘弹出和收起两种状态
键盘收起间距:keyboardDismissPadding
(09:40)
var dismissPadding = aboveKeyboardView.bounds.size.height
// 设置键盘收起时的额外间距
view.keyboardLayoutGuide.keyboardDismissPadding = dismissPadding
关键点:
keyboardDismissPadding控制键盘收起后,布局与屏幕底部之间的额外间距- 适用于键盘上方有工具栏或附加视图的场景
- 当键盘收起时,这些附加视图需要保留在屏幕内
手动处理键盘通知(备用方案)
(12:11)
如果必须使用键盘通知,iOS 17 提供了更精确的屏幕级信息:
func handleWillShowOrHideKeyboardNotification(notification: NSNotification) {
// 从通知获取 UIScreen 对象(iOS 16.1 新增)
guard let screen = notification.object as? UIScreen else { return }
// 确认通知的屏幕与当前视图所在屏幕一致
guard screen.isEqual(view.window?.screen) else { return }
// 获取键盘结束位置的屏幕坐标
let endFrameKey = UIResponder.keyboardFrameEndUserInfoKey
guard let keyboardFrameEnd = notification.userInfo?[endFrameKey] as? CGRect else { return }
// 从屏幕坐标系转换到视图本地坐标系
let fromCoordinateSpace: UICoordinateSpace = screen.coordinateSpace
let toCoordinateSpace: UICoordinateSpace = view
let convertedKeyboardFrameEnd = fromCoordinateSpace.convert(keyboardFrameEnd, to: toCoordinateSpace)
// 计算键盘与视图的交集
let viewIntersection = view.bounds.intersection(convertedKeyboardFrameEnd)
var bottomOffset = view.safeAreaInsets.bottom
// 如果键盘与视图相交,使用交集高度作为偏移量
if !viewIntersection.isEmpty {
bottomOffset = viewIntersection.size.height
}
// 更新约束并执行动画
movingBottomConstraint.constant = bottomOffset
// 使用通知中的动画参数执行布局更新
// ...
}
关键点:
- iOS 16.1 起,
UIKeyboardWillShowNotification的object是UIScreen,可以精确知道哪个屏幕的键盘变化 - 必须用
screen.isEqual(view.window?.screen)过滤,避免多窗口场景下的错误处理 - 坐标转换必须用
UICoordinateSpace.convert(_:to:),不能直接用CGRect运算 - 计算的是键盘与视图的交集高度,而不是键盘完整高度,这对 Stage Manager 分屏场景至关重要
内联预测:Inline Predictions
(14:38)
// 启用内联文本预测
textView.inlinePredictionType = .yes
// 禁用内联文本预测
textField.inlinePredictionType = .no
关键点:
inlinePredictionType控制是否显示内联文本预测(灰色建议文字)- 三个选项:
.default(系统决定)、.no(禁用)、.yes(启用) - 适用于密码输入框、验证码输入等不应显示预测的场景
- 遵循
UITextInputTraits协议的所有文本输入控件都支持
核心启发
1. 用 Keyboard Layout Guide 重构所有键盘适配代码
做什么:把项目中所有手动监听 UIKeyboardWillShowNotification 的代码替换为 UIKeyboardLayoutGuide 约束。
为什么值得做:UIKeyboardLayoutGuide 自动处理浮动键盘、分屏、多窗口等复杂场景,代码量减少 80% 以上,且行为更可靠。
怎么开始:找到所有键盘通知的监听代码,删除通知注册和回调,在 viewDidLoad 中添加 keyboardLayoutGuide.topAnchor 约束。测试浮动键盘、分屏、旋转等场景。
2. 为 Stage Manager 优化多窗口应用
做什么:确保 iPad 多窗口场景下,每个窗口独立正确处理键盘弹出。
为什么值得做:Stage Manager 下多个 App 窗口可以同时显示,每个窗口都可能需要键盘适配。错误的实现会导致一个窗口的键盘影响另一个窗口的布局。
怎么开始:在 iPad 上开启 Stage Manager,打开应用的多个窗口,在每个窗口中触发键盘,验证布局只影响当前窗口。使用 notification.object as? UIScreen 过滤通知。
3. 为敏感输入禁用内联预测
做什么:在密码框、验证码框、信用卡号输入框中显式设置 inlinePredictionType = .no。
为什么值得做:内联预测会在输入框中显示灰色建议文字,对于敏感信息这既是隐私问题也是用户体验问题。
怎么开始:遍历所有文本输入控件,对涉及敏感信息的字段设置 inlinePredictionType = .no。同时检查 autocorrectionType 和 autocapitalizationType 是否也配置正确。
4. 实现键盘上方工具栏的平滑收起
做什么:在键盘上方放置自定义工具栏,键盘收起时工具栏平滑过渡到屏幕底部。
为什么值得做:很多应用(如笔记、文档编辑)在键盘上方有格式工具栏。keyboardDismissPadding 让这种布局无需手动计算即可正确工作。
怎么开始:设置 view.keyboardLayoutGuide.keyboardDismissPadding = toolbarHeight,然后将工具栏底部约束到 keyboardLayoutGuide.topAnchor。
关联 Session
- Animate symbols in your app — SF Symbols 动画
- Build better document-based apps — 构建更好的文档类应用
- Create a more responsive camera experience — 创建响应式相机体验
- Create animated symbols — 创建动画符号
评论
GitHub Issues · utterances