Flutter 是一个跨平台的开发框架,它允许开发者使用相同的代码库来构建 iOS、Android、Web 和桌面应用程序。
最近想了想,自己一直在用flutter开发特定端的应用,但是对于其他端的端特性case,如桌面端的菜单、多窗口、鼠标事件,需要怎么处理还没什么概念,本文旨在简单探索这方面的内容。
首先就是判断平台了,可以通过如下方式
import 'dart:io' show Platform;
void checkPlatform() {
if (kIsWeb) {
print('Running on the web.');
} else {
if (Platform.isAndroid) {
print('Running on Android.');
} else if (Platform.isIOS) {
print('Running on iOS.');
} else if (Platform.isLinux) {
print('Running on Linux.');
} else if (Platform.isMacOS) {
print('Running on macOS.');
} else if (Platform.isWindows) {
print('Running on Windows.');
}
}
}
这里flutter似乎是把这个事交给社区插件来做了,最著名的是permission_handler插件,原理后面探讨,大致用法如下
import 'package:permission_handler/permission_handler.dart';
Future requestPermissions() async {
var status = await Permission.camera.status;
if (!status.isGranted) {
await Permission.camera.request();
}
status = await Permission.location.status;
if (!status.isGranted) {
await Permission.location.request();
}
}
这个是谷歌官方已经为我们抽象出来了用法,比如摄像头有cameraController
import 'package:camera/camera.dart';
List? cameras;
Future main() async {
cameras = await availableCameras();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CameraApp(),
);
}
}
class CameraApp extends StatefulWidget {
@override
_CameraAppState createState() => _CameraAppState();
}
class _CameraAppState extends State {
CameraController? controller;
@override
void initState() {
super.initState();
controller = CameraController(cameras![0], ResolutionPreset.medium);
controller!.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (!controller!.value.isInitialized) {
return Container();
}
return AspectRatio(
aspectRatio: controller!.value.aspectRatio,
child: CameraPreview(controller!),
);
}
}
如下demo是监听Ctrl+S这个快捷键的示例
具体来说就是需要LogicalKeySet来接受LogicalKeyboardKey的键盘快捷键,并且使用Shortcuts
小部件来设置快捷键与意图SaveIntent之间的映射关系,意图内部就是保存的具体操作,然后Actions
小部件来定义当某个意图发生时应该执行的动作,需要注意的是shortcuts组件只会监听当前具有焦点的小部件的快捷键事件,所以我们用一个focus包裹并设置autofocus为true,构建时候获取焦点。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ShortcutKeysApp(),
);
}
}
class ShortcutKeysApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Shortcuts(
shortcuts: {
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyS): SaveIntent(),
},
child: Actions(
actions: {
SaveIntent: SaveAction(),
},
child: Focus(
autofocus: true,
child: Builder(
builder: (context) {
return ElevatedButton(
onPressed: () {
SaveIntent().dispatch(context);
},
child: Text('Save'),
);
},
),
),
),
);
}
}
class SaveIntent extends Intent {
const SaveIntent();
}
class SaveAction extends Action {
@override
Object? invoke(covariant SaveIntent intent) {
// Implement
print('Save action invoked');
return null;
}
}
这个比较简单,用Listener就可以了
onPointerDown
: 当用户按下鼠标按钮或触摸屏幕时触发。onPointerMove
: 当用户移动鼠标或手指时触发。onPointerUp
: 当用户释放鼠标按钮或移开手指时触发。import 'package:flutter/material.dart';
class MouseEventsWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Listener(
onPointerDown: (event) {
print('Pointer down at: ${event.position}');
},
onPointerMove: (event) {
print('Pointer move at: ${event.position}');
},
onPointerUp: (event) {
print('Pointer up at: ${event.position}');
},
child: Container(
width: 200,
height: 200,
color: Colors.blue,
child: Center(
child: Text('Do something with your mouse here'),
),
),
);
}
}
flutter目前是没有提供桌面菜单的原生支持的, 可以使用第三方插件如menubar 或 flutter_platform_menu_bar
import 'package:menubar/menubar.dart';
void setupMenu() {
setApplicationMenu([
Submenu(label: 'File', children: [
MenuItem(label: 'New', onClicked: () => print('New clicked')),
MenuItem(label: 'Open', onClicked: () => print('Open clicked')),
]),
Submenu(label: 'Edit', children: [
MenuItem(label: 'Undo', onClicked: () => print('Undo clicked')),
MenuItem(label: 'Redo', onClicked: () => print('Redo clicked')),
]),
]);
}
flutter没有提供多窗口支持,可以使用三方插件flutter_multi_window
import 'package:flutter_multi_window/flutter_multi_window.dart';
void openNewWindow() async {
// 创建新的窗口
await FlutterMultiWindow.createWindow('window_key');
}
// 处理来自其他窗口的消息
FlutterMultiWindow.setWindowCallback((message) {
print('Received message: $message');
});