当用户将焦点放在可编辑的文本组件(例如 TextField
)上时,
并且设备连接了硬件键盘,
所有输入均由系统处理
您可以通过处理按键事件来提供键盘快捷键。
默认键盘快捷键
以下键盘快捷键可供直接使用。
键盘快捷键 | 操作 | 支持快捷键的可组合项 |
---|---|---|
Shift + Ctrl + 向左箭头/向右箭头 | 选择直到单词开头/结尾的文字 | BasicTextField 、TextField |
Shift + Ctrl + 向上箭头/向下箭头 | 选择段落开头/结尾处的文本 | BasicTextField 、TextField |
Shift+Alt+向上键/向下键,或 Shift+Meta+向左键/向右键 | 选择文本到文本开头/结尾处的文本 | BasicTextField 、TextField |
Shift + 向左箭头/向右箭头 | 选择角色 | BasicTextField 、TextField |
Ctrl+A | 全选 | BasicTextField 、TextField |
Ctrl+C/Ctrl+X/Ctrl+V | 复制/剪切/粘贴 | BasicTextField 、TextField |
Ctrl+Z/Ctrl+Shift+Z | 撤消/重做 | BasicTextField 、TextField |
PageDown/PageUp | 滚动 | LazyColumn 、verticalScroll 修饰符、scrollable 修饰符 |
重要事件
在 Compose 中,您可以使用
onKeyEvent
修饰符。
该修饰符接受一个 lambda,该 lambda 会在修改后的组件收到按键事件时被调用。关键事件描述为 KeyEvent
对象。
您可以通过引用传递给 onKeyEvent
修饰符的 lambda 中的对象来获取每个按键事件的信息。
按键操作会发送两个按键事件。其中一个在用户按下按键时触发;另一个在用户松开按键时触发。您可以通过引用 KeyEvent
对象的 type
属性来区分这两种关键事件。
onKeyEvent
lambda 的返回值表示
关键事件是否得到处理。
如果您的应用处理按键事件,请返回 true
,这会停止事件传播。
以下代码段展示了如何调用 doSomething()
函数
当用户释放 Box
组件上的 S 键时触发:
Box(
modifier = Modifier.focusable().onKeyEvent {
if(
it.type == KeyEventType.KeyUp &&
it.key == Key.S
) {
doSomething()
true
} else {
false
}
}
) {
Text("Press S key")
}
辅助键
KeyEvent
对象具有以下属性,用于指示是否按下了修饰键:
具体描述您的应用处理的关键事件。
以下代码段调用 doSomething()
函数
仅在用户仅释放 S 键时才启用。
如果用户按下任何修饰符键(例如 Shift 键),应用不会调用该函数。
Box(
modifier = Modifier.focusable().onKeyEvent{
if(
it.type == KeyEventType.KeyUp &&
it.key == Key.S &&
!it.isAltPressed &&
!it.isCtrlPressed &&
!it.isMetaPressed &&
!it.isShiftPressed
) {
doSomething()
true
} else {
false
}
}
) {
Text("Press S key with a modifier key")
}
空格键和 Enter 键点击事件
空格键和 Enter 键也会触发点击事件。 例如,用户可以切换(播放或暂停)媒体播放 按空格键或 Enter 键 按如下方式处理点击事件:
MoviePlayer(
modifier = Modifier.clickable { togglePausePlay() }
)
clickable
修饰符会拦截按键事件,并在按下 Spacebar 或 Enter 键时调用 onClick()
回调。因此,在代码段中按 Spacebar 或 Enter 键即可调用 togglePausePlay()
函数。
未消耗的关键事件
未使用的按键事件会从发生事件的组件传播到封闭的外部组件。在以下示例中,当 S 键被释放时,InnerComponent
会消耗按键事件,因此 OuterComponent
不会收到因释放 S 键而触发的任何按键事件。因此,系统永远不会调用 actionB()
函数。
InnerComponent
上的其他按键事件,例如释放 D 键;
可由 OuterComponent
处理。
之所以调用 actionC()
函数,是因为以下事件的按键事件:
释放 D 键会传播到 OuterComponent
。
OuterComponent(
modifier = Modifier.onKeyEvent {
when {
it.type == KeyEventType.KeyUp && it.key == Key.S -> {
actionB() // This function is never called.
true
}
it.type == KeyEventType.KeyUp && it.key == Key.D -> {
actionC()
true
}
else -> false
}
}
) {
InnerComponent(
modifier = Modifier.onKeyEvent {
if(it.type == KeyEventType.KeyUp && it.key == Key.S) {
actionA()
true
} else {
false
}
}
)
}
onKeyPreviewEvent
修饰符
在某些用例中,您需要拦截按键事件
然后才能触发默认操作。
向 TextField
添加自定义快捷方式是一种常见的做法。
借助以下代码段,用户可以通过按 tab 键移至下一个可聚焦的组件。
val focusManager = LocalFocusManager.current
var textFieldValue by remember { mutableStateOf(TextFieldValue()) }
TextField(
textFieldValue,
onValueChange = {
textFieldValue = it
},
modifier = Modifier.onPreviewKeyEvent {
if (it.type == KeyEventType.KeyUp && it.key == Key.Tab) {
focusManager.moveFocus(FocusDirection.Next)
true
} else {
false
}
}
)
默认情况下,每当用户按下 Tab 键时,TextField
组件都会添加一个 Tab 字符,即使使用 onKeyEvent
修饰符处理按键事件也是如此。如需在不添加任何 Tab 字符的情况下移动键盘焦点,请先处理按键事件,然后再触发与按键事件关联的操作,如代码段所示。onKeyPreviewEvent()
lambda 会拦截按键事件
返回 true
。
父级组件可以拦截其子级上发生的按键事件。在以下代码段中,previewSKey()
函数调用了
当用户按 S 键时,
而不是调用 actionForPreview()
函数。
Column(
modifier = Modifier.onPreviewKeyEvent{
if(it.key == Key.S){
previewSKey()
true
}else{
false
}
}
) {
Box(
modifier = Modifier
.focusable()
.onPreviewKeyEvent {
actionForPreview(it)
false
}
.onKeyEvent {
actionForKeyEvent(it)
true
}
) {
Text("Press any key")
}
}
当用户按 Tab 键时,系统也不会触发 Box
组件的 onPreviewKeyEvent()
lambda。系统会先对父级组件调用 onPreviewKeyEvent()
lambda,然后再调用子级组件中的 onPreviewKeyEvent()
。您可以通过利用此行为来实现整个屏幕的键盘快捷键。
其他资源
- 键盘快捷键辅助工具:显示 让用户能够搜索应用提供的键盘快捷键。