概述

#

一段時間以來(數年),Flutter 一直實現了兩個按鍵事件系統。新系統已與舊的平臺特定原始按鍵事件系統達到同等水平,而原始系統已被棄用。

背景

#

在最初的按鍵事件子系統中,在框架和客戶端應用程式中處理每個平臺的細微差別導致程式碼過於複雜,而且舊系統未能正確反映系統上按鍵事件的真實狀態。

舊版 API RawKeyboard 已棄用,未來將被移除。HardwareKeyboardKeyEvent API 取代了此舊版 API。此更改的一個示例是 FocusNode.onKeyEvent 取代了 FocusNode.onKey

RawKeyboard 的行為比 HardwareKeyboard 提供的事件模型更不統一,也不如其規則。請考慮以下示例:

  • 按下事件並不總是與釋放事件匹配,反之亦然(已按鍵集合被靜默更新)。
  • 按下事件的邏輯鍵可能與釋放事件的邏輯鍵不同。
  • 按下事件和重複事件不易區分(需要手動跟蹤)。
  • 鎖定模式(如大寫鎖定)僅記錄了其“啟用”狀態。無法獲取其按下狀態。

因此,新的基於 KeyEvent/HardwareKeyboard 的系統應運而生,為了儘量減少破壞性更改,它與舊系統並行實現,並打算最終棄用舊系統。現在是時候了,應用程式開發人員應遷移其程式碼,以避免在棄用 API 被移除時發生的破壞性更改。

變更說明

#

以下是已棄用的 API。

已棄用但有同等功能的 API

#

已停用的 API

#

一旦只有一個按鍵事件系統,或者其功能不再提供,這些 API 就不再需要了。

遷移指南

#

Flutter 框架庫已完成遷移。如果您的程式碼使用了上一節中列出的任何類或方法,請遷移到這些新 API。

遷移使用 RawKeyEvent 的程式碼

#

對於大多數情況,所有 RawKeyEvent API 都有相應的 KeyEvent API 可用。

RawKeyEventData 物件或其子類中包含的與平臺特定資訊相關的某些 API 已被移除,不再受支援。一個例外是,RawKeyEventDataAndroid.eventSource 資訊現在可以作為 KeyEvent.deviceType 以更獨立於平臺的形式訪問。

#

如果舊程式碼使用了 RawKeyEvent.isKeyPressedRawKeyEvent.isControlPressedRawKeyEvent.isShiftPressedRawKeyEvent.isAltPressedRawKeyEvent.isMetaPressed API,現在 HardwareKeyboard 單例例項上也有等效的函式,但 [KeyEvent] 上不可用。RawKeyEvent.isKeyPressed 可作為 HardwareKeyboard.isLogicalKeyPressed 使用。

之前

dart
KeyEventResult _handleKeyEvent(RawKeyEvent keyEvent) {
  if (keyEvent.isControlPressed ||
      keyEvent.isShiftPressed ||
      keyEvent.isAltPressed ||
      keyEvent.isMetaPressed) {
    print('Modifier pressed: $keyEvent');
  }
  if (keyEvent.isKeyPressed(LogicalKeyboardKey.keyA)) {
    print('Key A pressed.');
  }
  return KeyEventResult.ignored;
}

之後

dart
KeyEventResult _handleKeyEvent(KeyEvent _) {
  if (HardwareKeyboard.instance.isControlPressed ||
      HardwareKeyboard.instance.isShiftPressed ||
      HardwareKeyboard.instance.isAltPressed ||
      HardwareKeyboard.instance.isMetaPressed) {
    print('Modifier pressed: $keyEvent');
  }
  if (HardwareKeyboard.instance.isLogicalKeyPressed(LogicalKeyboardKey.keyA)) {
    print('Key A pressed.');
  }
  return KeyEventResult.ignored;
}

為焦點設定 onKey

#

如果舊程式碼使用了 Focus.onKeyFocusScope.onKeyFocusNode.onKeyFocusScopeNode.onKey 引數,那麼現在有等效的 Focus.onKeyEventFocusScope.onKeyEventFocusNode.onKeyEventFocusScopeNode.onKeyEvent 引數,它們提供 KeyEvent 而不是 RawKeyEvent

之前

dart
Widget build(BuildContext context) {
  return Focus(
    onKey: (RawKeyEvent keyEvent) {
      print('Key event: $keyEvent');
      return KeyEventResult.ignored;
    }
    child: child,
  );
}

之後

dart
Widget build(BuildContext context) {
  return Focus(
    onKeyEvent: (KeyEvent keyEvent) {
      print('Key event: $keyEvent');
      return KeyEventResult.ignored;
    }
    child: child,
  );
}

重複按鍵事件處理

#

如果您之前依賴 RawKeyEvent.repeat 屬性來確定一個按鍵是否為重複按鍵事件,現在這已被分離到一個單獨的 KeyRepeatEvent 型別。

之前

dart
KeyEventResult _handleKeyEvent(RawKeyEvent keyEvent) {
  if (keyEvent is RawKeyDownEvent) {
    print('Key down: ${keyEvent.data.logicalKey.keyLabel}(${keyEvent.repeat ? ' (repeated)' : ''})');
  }
  return KeyEventResult.ignored;
}

之後

dart
KeyEventResult _handleKeyEvent(KeyEvent _) {
  if (keyEvent is KeyDownEvent || keyEvent is KeyRepeatEvent) {
    print('Key down: ${keyEvent.logicalKey.keyLabel}(${keyEvent is KeyRepeatEvent ? ' (repeated)' : ''})');
  }
  return KeyEventResult.ignored;
}

雖然 KeyRepeatEvent 不是 KeyDownEvent 的子類,但它也是一個按鍵按下事件。不要假定 keyEvent is! KeyDownEvent 只允許按鍵釋放事件。同時檢查 KeyDownEventKeyRepeatEvent

時間線

#

已釋出版本:3.18.0-7.0.pre
穩定版本:3.19.0

參考資料

#

替換 API 文件

相關問題

相關 PR