基礎知識
1. 物理鍵盤(Physical Keyboard)
定義
物理鍵盤指的是設備上真實存在的、可以按壓的鍵盤。例如:
- 早期的 Android 手機(如黑莓、摩托羅拉 Milestone)自帶的 QWERTY 鍵盤
- 外接的藍牙/USB 鍵盤
- 平板或 Chromebook 上的實體鍵盤
特點
- 輸入響應快,無需屏幕空間
- 支持快捷鍵、組合鍵
- 適合大量文字輸入或開發者使用
開發相關
- 可以通過?KeyEvent?監聽物理鍵盤事件
- 物理鍵盤連接時,系統通常會自動隱藏軟鍵盤
2. 軟件盤(Soft Keyboard / 虛擬鍵盤)
定義
軟件盤是指在屏幕上彈出的虛擬鍵盤。絕大多數 Android 設備都內置了軟鍵盤(如 Gboard、百度輸入法等)。
特點
- 觸摸屏幕輸入
- 可根據輸入場景切換布局(數字、符號、表情等)
- 支持多語言、手寫、語音輸入等擴展功能
- 會占用部分屏幕空間
開發相關
- 通過?InputMethodManager?控制軟鍵盤的顯示與隱藏
- 可以在?EditText?上設置輸入類型(如數字、密碼等)
- 軟鍵盤彈出時,可能會影響界面布局(如遮擋輸入框),需要合理處理(如使用?android:windowSoftInputMode)
3. 物理鍵盤與軟鍵盤的關系
- 如果設備連接了物理鍵盤,Android 系統通常會自動隱藏軟鍵盤,除非用戶手動調出。
- 開發者可以通過代碼判斷當前是否有物理鍵盤連接(如?Configuration.keyboard)。
- 某些場景下,開發者可以強制顯示軟鍵盤,即使有物理鍵盤。
4. 常見開發場景
- 監聽鍵盤事件:通過?onKeyDown、onKeyUp?監聽物理鍵盤輸入。
- 軟鍵盤控制:通過?InputMethodManager.showSoftInput()?和?hideSoftInputFromWindow()?控制軟鍵盤。
- 適配鍵盤彈出:使用?android:windowSoftInputMode?控制界面適配。
5. 相關 API
- KeyEvent:物理鍵盤事件
- InputMethodManager:軟鍵盤管理
- Configuration.keyboard:判斷當前鍵盤類型
需求
一個需求,當連接外接鍵盤的時候,用外接,沒有就用系統的。
Android 系統默認就會這樣處理,但如果你需要更精確的控制,可以通過以下方式實現:
1. 檢測鍵盤類型
首先需要檢測當前是否有物理鍵盤連接:
public class KeyboardManager {/*** 檢測是否有物理鍵盤連接*/public static boolean hasPhysicalKeyboard(Context context) {Configuration config = context.getResources().getConfiguration();return config.keyboard == Configuration.KEYBOARD_QWERTY ||config.keyboard == Configuration.KEYBOARD_12KEY;}/*** 檢測是否有外接鍵盤*/public static boolean hasExternalKeyboard(Context context) {// 方法1:通過Configuration檢測Configuration config = context.getResources().getConfiguration();boolean hasHardwareKeyboard = config.keyboard != Configuration.KEYBOARD_UNDEFINED;// 方法2:通過InputDevice檢測(更精確)InputManager inputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE);int[] deviceIds = inputManager.getInputDeviceIds();for (int deviceId : deviceIds) {InputDevice device = inputManager.getInputDevice(deviceId);if (device != null && device.isExternal()) {// 檢查是否是鍵盤設備int sources = device.getSources();if ((sources & InputDevice.SOURCE_KEYBOARD) != 0) {return true;}}}return hasHardwareKeyboard;}/*** 根據鍵盤狀態顯示或隱藏軟鍵盤*/public static void handleKeyboard(Context context, View view) {if (hasExternalKeyboard(context)) {// 有外接鍵盤時,隱藏軟鍵盤hideSoftKeyboard(context, view);} else {// 沒有外接鍵盤時,顯示軟鍵盤showSoftKeyboard(context, view);}}/*** 顯示軟鍵盤*/public static void showSoftKeyboard(Context context, View view) {InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);if (imm != null) {imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);}}/*** 隱藏軟鍵盤*/public static void hideSoftKeyboard(Context context, View view) {InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);if (imm != null) {imm.hideSoftInputFromWindow(view.getWindowToken(), 0);}}
}
2. 在Activity中使用
public class MainActivity extends AppCompatActivity {private EditText editText;private KeyboardManager keyboardManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);editText = findViewById(R.id.edit_text);// 監聽鍵盤狀態變化registerKeyboardStateReceiver();// 初始處理鍵盤狀態handleKeyboardState();}private void handleKeyboardState() {if (KeyboardManager.hasExternalKeyboard(this)) {// 有外接鍵盤時的處理editText.setHint("使用外接鍵盤輸入");KeyboardManager.hideSoftKeyboard(this, editText);} else {// 沒有外接鍵盤時的處理editText.setHint("點擊輸入");editText.setOnFocusChangeListener((v, hasFocus) -> {if (hasFocus) {KeyboardManager.showSoftKeyboard(this, editText);}});}}private void registerKeyboardStateReceiver() {// 注冊配置變化監聽器registerReceiver(new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if (Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {// 鍵盤配置發生變化時重新處理handleKeyboardState();}}}, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));}@Overrideprotected void onDestroy() {super.onDestroy();// 記得注銷廣播接收器}
}
3. 在布局文件中配置
<EditTextandroid:id="@+id/edit_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="輸入文字"android:inputType="text"android:windowSoftInputMode="adjustResize" />
4. 更高級的實現(監聽鍵盤連接/斷開)
public class KeyboardStateManager {private Context context;private OnKeyboardStateChangeListener listener;public interface OnKeyboardStateChangeListener {void onExternalKeyboardConnected();void onExternalKeyboardDisconnected();}public KeyboardStateManager(Context context, OnKeyboardStateChangeListener listener) {this.context = context;this.listener = listener;}public void startMonitoring() {// 監聽USB設備連接IntentFilter usbFilter = new IntentFilter();usbFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);usbFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);context.registerReceiver(new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {// 檢查是否是鍵盤設備UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);if (isKeyboardDevice(device)) {listener.onExternalKeyboardConnected();}} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);if (isKeyboardDevice(device)) {listener.onExternalKeyboardDisconnected();}}}}, usbFilter);}private boolean isKeyboardDevice(UsbDevice device) {if (device == null) return false;// 檢查設備類是否為HID(Human Interface Device)return device.getDeviceClass() == UsbConstants.USB_CLASS_HID;}
}
5. 使用示例
// 在Activity中使用
KeyboardStateManager keyboardStateManager = new KeyboardStateManager(this, new KeyboardStateManager.OnKeyboardStateChangeListener() {@Overridepublic void onExternalKeyboardConnected() {// 外接鍵盤連接時的處理KeyboardManager.hideSoftKeyboard(MainActivity.this, editText);Toast.makeText(MainActivity.this, "外接鍵盤已連接", Toast.LENGTH_SHORT).show();}@Overridepublic void onExternalKeyboardDisconnected() {// 外接鍵盤斷開時的處理Toast.makeText(MainActivity.this, "外接鍵盤已斷開", Toast.LENGTH_SHORT).show();}
});keyboardStateManager.startMonitoring();
主要特點:
- 自動檢測:通過?Configuration?和?InputDevice?檢測鍵盤狀態
- 實時響應:監聽配置變化和USB設備連接/斷開
- 智能切換:根據鍵盤狀態自動顯示/隱藏軟鍵盤
- 用戶體驗:提供適當的提示和反饋
這樣實現后,你的應用就能智能地在物理鍵盤和軟鍵盤之間切換了!