Flutter软键盘按键检测回调:自定义触觉振动实现遇阻求助
解决方案:通过iOS原生插件监听系统软键盘按键事件
Flutter框架本身没有提供直接监听系统软键盘按键按下的API,你之前尝试的FocusNode、RawKeyboardListener等方法仅对硬件键盘生效,系统软键盘的事件不会通过这些回调传递。要实现需求,必须通过自定义iOS原生插件来捕捉软键盘按键事件,再传递给Flutter触发振动。
具体实现步骤
1. 自定义Flutter插件(iOS端)
通过方法交换(Swizzling)Hook系统输入控件的按键事件,将事件传递给Flutter,也可以直接在原生端触发触觉振动。
import UIKit import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller = window?.rootViewController as! FlutterViewController let hapticChannel = FlutterMethodChannel(name: "com.yourdomain.haptic_keyboard", binaryMessenger: controller.binaryMessenger) // 交换UITextView的keyDown方法,捕捉按键事件 let originalSelector = #selector(UITextView.keyDown(_:)) let swizzledSelector = #selector(UITextView.swizzled_keyDown(_:)) if let originalMethod = class_getInstanceMethod(UITextView.self, originalSelector), let swizzledMethod = class_getInstanceMethod(UITextView.self, swizzledSelector) { method_exchangeImplementations(originalMethod, swizzledMethod) } // 保存MethodChannel供交换后的方法调用 HapticChannel.shared.channel = hapticChannel GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } // 全局存储MethodChannel class HapticChannel { static let shared = HapticChannel() var channel: FlutterMethodChannel? } extension UITextView { @objc func swizzled_keyDown(_ key: UIKey) { // 先调用原方法保证正常输入逻辑 self.swizzled_keyDown(key) // 方式1:给Flutter发送事件,由Flutter触发振动 HapticChannel.shared.channel?.invokeMethod("keyPressed", arguments: nil) // 方式2:直接在原生端触发触觉振动(延迟更低) let generator = UIImpactFeedbackGenerator(style: .light) generator.impactOccurred() } }
2. Flutter端接收事件并触发振动
通过MethodChannel监听原生传递的按键事件,调用你的自定义振动插件。
import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final MethodChannel _hapticChannel = const MethodChannel('com.yourdomain.haptic_keyboard'); final FocusNode _focusNode = FocusNode(); @override void initState() { super.initState(); // 监听原生传递的按键事件 _hapticChannel.setMethodCallHandler((call) async { if (call.method == 'keyPressed') { // 调用你的自定义振动插件 HapticsPlugin().click(); } }); } @override void dispose() { _focusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('软键盘触觉反馈')), body: Center( child: EditableText( focusNode: _focusNode, controller: TextEditingController(), style: const TextStyle(fontSize: 16), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, ), ), ), ); } } // 你的自定义振动插件类 class HapticsPlugin { void click() { // 这里是你的振动实现逻辑 print('触发触觉振动'); } }
关键说明
- 方法交换(Swizzling)需谨慎:如果你的项目中有其他第三方库也修改了
UITextView的keyDown方法,可能会产生冲突。可以添加判断,仅对Flutter专属的输入控件(如FlutterTextInputView)生效。 - 原生端直接振动:在iOS端直接触发振动可以减少跨平台通信的延迟,体验更流畅。
- 兼容性:上述代码适配iOS 13+,低版本需使用旧版
keyDown(_ event: UIEvent?)方法。
内容的提问来源于stack exchange,提问作者Mikael Wills
相关产品推荐
相关产品推荐

