Flutter隐藏鼠标光标:Windows平台Bug的规避方案及替代方法
规避Flutter Windows平台鼠标光标不即时隐藏的问题
先看触发问题的代码:
class ExampleWidget extends StatefulWidget { const ExampleWidget({Key? key}) : super(key: key); @override State<ExampleWidget> createState() => _ExampleState(); } class _ExampleState extends State<ExampleWidget> { bool showCursor = false; @override Widget build(BuildContext context) { return MouseRegion( cursor: showCursor ? SystemMouseCursors.basic : SystemMouseCursors.none, ); } }
在Windows平台下,这段代码存在异常:当showCursor设为false时,只有用户移动鼠标,光标才会隐藏;如果设置后用户未移动鼠标,光标会持续显示,直到鼠标有移动动作才会更新状态。这是Flutter引擎的已知Bug。
下面提供几种实用的规避方案:
方案一:强制重建MouseRegion组件
给MouseRegion绑定一个和showCursor关联的Key,当showCursor状态变化时,Key同步变更,强制组件重建,从而立即触发光标状态更新:
class ExampleWidget extends StatefulWidget { const ExampleWidget({Key? key}) : super(key: key); @override State<ExampleWidget> createState() => _ExampleState(); } class _ExampleState extends State<ExampleWidget> { bool showCursor = false; @override Widget build(BuildContext context) { return MouseRegion( key: ValueKey(showCursor), // 用showCursor作为Key,状态变化时触发组件重建 cursor: showCursor ? SystemMouseCursors.basic : SystemMouseCursors.none, ); } }
方案二:通过平台通道直接调用Windows API
绕开Flutter引擎的限制,直接调用Windows原生API控制光标显示:
Flutter端代码
import 'package:flutter/services.dart'; // 封装光标控制方法 class CursorController { static const MethodChannel _channel = MethodChannel('cursor_control'); static Future<void> hideCursor() async { await _channel.invokeMethod('hide'); } static Future<void> showCursor() async { await _channel.invokeMethod('show'); } }
Windows端代码修改
在项目Windows目录下的runner.cpp中添加平台通道实现:
#include <windows.h> #include "flutter_window.h" #include "flutter/generated_plugin_registrant.h" // 注册光标控制通道 void RegisterCursorChannel(FlutterWindow* window) { auto channel = std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>( window->flutter_engine()->messenger(), "cursor_control", &flutter::StandardMethodCodec::GetInstance()); channel->SetMethodCallHandler( [](const flutter::MethodCall<flutter::EncodableValue>& call, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { if (call.method_name() == "hide") { ShowCursor(FALSE); result->Success(); } else if (call.method_name() == "show") { ShowCursor(TRUE); result->Success(); } else { result->NotImplemented(); } }); } int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t* command_line, _In_ int show_command) { // ... 保留原有代码 ... FlutterWindow window(project); RegisterCursorChannel(&window); // 注册光标控制通道 // ... 保留原有代码 ... }
在Widget中使用
class _ExampleState extends State<ExampleWidget> { bool showCursor = false; @override void didUpdateWidget(covariant ExampleWidget oldWidget) { super.didUpdateWidget(oldWidget); // 光标状态变化时调用原生方法 if (showCursor != oldWidget.showCursor) { showCursor ? CursorController.showCursor() : CursorController.hideCursor(); } } @override Widget build(BuildContext context) { return Container(); // 无需再依赖MouseRegion } }
方案三:使用第三方封装包
可以选择维护活跃的跨平台光标控制第三方包,直接调用封装好的方法来隐藏/显示光标,省去自己编写原生代码的麻烦。
内容的提问来源于stack exchange,提问作者Gieted
相关产品推荐
相关产品推荐

