Flutter浮动窗口管理插件flutter_floatwing的使用
Flutter浮动窗口管理插件flutter_floatwing的使用
1. 插件简介
flutter_floatwing
是一个用于在 Android 上创建和管理浮动窗口(overlay windows)的 Flutter 插件。它允许你使用纯 Flutter 代码来构建浮动窗口,并提供了多种功能,如自动调整大小、多窗口支持、事件机制等。
2. 主要特性
- 纯 Flutter:你可以用纯 Flutter 代码编写整个浮动窗口。
- 简单易用:只需一行代码即可启动浮动窗口。
- 自动调整大小:根据 Flutter 小部件的大小自动调整 Android 视图。
- 多窗口支持:可以在一个应用中创建多个浮动窗口,并且窗口可以有子窗口。
- 通信能力:主应用和窗口之间可以进行通信,窗口之间也可以互相通信。
- 事件机制:可以监听窗口生命周期和其他操作(如拖动)的事件,灵活控制窗口行为。
3. 预览
夜间模式 | 简单示例 | 辅助触摸模拟 |
---|---|---|
4. 安装
-
打开
pubspec.yaml
文件,在dependencies
中添加flutter_floatwing
:dependencies: flutter_floatwing: ^最新版本
-
安装依赖:
- 终端:运行
flutter pub get
- Android Studio/IntelliJ:点击
pubspec.yaml
顶部的 “Packages get” - VS Code:点击
pubspec.yaml
顶部的 “Get Packages”
- 终端:运行
或者直接在命令行中添加:
flutter pub add flutter_floatwing
5. 快速开始
5.1 添加权限
由于 flutter_floatwing
使用的是 Android 的系统警报窗口(SYSTEM_ALERT_WINDOW),因此需要在 AndroidManifest.xml
中添加权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
5.2 创建路由
在主应用中为浮动窗口添加路由:
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: "/",
routes: {
"/": (_) => HomePage(),
// 为浮动窗口添加路由
"/my-overlay-window": (_) => MyOverlayWindow(),
},
);
}
5.3 检查并请求权限
在启动浮动窗口之前,需要检查并请求系统警报窗口权限,并初始化 flutter_floatwing
插件:
// 检查并请求权限
FloatwingPlugin().checkPermission().then((v) {
if (!v) FloatwingPlugin().openPermissionSetting();
});
// 初始化插件
FloatwingPlugin().initialize();
5.4 创建并启动浮动窗口
定义窗口配置并启动浮动窗口:
// 定义窗口配置并启动窗口
WindowConfig(route: "/my-overlay-window")
.to() // 创建窗口对象
.create(start: true); // 创建并启动浮动窗口
6. 完整示例 Demo
以下是一个完整的示例,展示了如何使用 flutter_floatwing
创建和管理浮动窗口。
import 'package:flutter/material.dart';
import 'package:flutter_floatwing/flutter_floatwing.dart';
void main() {
runApp(MyApp());
}
[@pragma](/user/pragma)("vm:entry-point")
void floatwing() {
runApp(((_) => NonrmalView()).floatwing().make());
}
void floatwing2(Window w) {
runApp(MaterialApp(
// floatwing on widget can't use Window.of(context)
// to access window instance
// should use FloatwingPlugin().currentWindow
home: NonrmalView().floatwing(),
));
}
class MyApp extends StatefulWidget {
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var _configs = [
WindowConfig(
id: "normal",
route: "/normal",
draggable: true,
),
WindowConfig(
id: "assitive_touch",
route: "/assitive_touch",
draggable: true,
),
WindowConfig(
id: "night",
route: "/night",
width: WindowSize.MatchParent,
height: WindowSize.MatchParent,
clickable: false,
)
];
Map<String, WidgetBuilder> _builders = {
"normal": (_) => NonrmalView(),
"assitive_touch": (_) => AssistiveTouch(),
"night": (_) => NightView(),
};
Map<String, Widget Function(BuildContext)> _routes = {};
[@override](/user/override)
void initState() {
super.initState();
_routes["/"] = (_) => HomePage(configs: _configs);
_configs.forEach((c) => {
if (c.route != null && _builders[c.id] != null)
{_routes[c.route!] = _builders[c.id]!.floatwing(debug: false)}
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: "/",
routes: _routes,
);
}
}
class HomePage extends StatefulWidget {
final List<WindowConfig> configs;
const HomePage({Key? key, required this.configs}) : super(key: key);
[@override](/user/override)
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
[@override](/user/override)
void initState() {
super.initState();
FloatwingPlugin().initialize();
initAsyncState();
}
List<Window> _windows = [];
Map<Window, bool> _readys = {};
bool _ready = false;
initAsyncState() async {
var p1 = await FloatwingPlugin().checkPermission();
var p2 = await FloatwingPlugin().isServiceRunning();
// 获取权限
if (!p1) {
FloatwingPlugin().openPermissionSetting();
return;
}
// 启动服务
if (!p2) {
FloatwingPlugin().startService();
}
_createWindows();
setState(() {
_ready = true;
});
}
_createWindows() async {
await FloatwingPlugin().isServiceRunning().then((v) async {
if (!v)
await FloatwingPlugin().startService().then((_) {
print("启动后台服务成功");
});
});
_windows.forEach((w) {
var _w = FloatwingPlugin().windows[w.id];
if (_w != null) {
// 替换 w 为 _w
_readys[w] = true;
return;
}
w.on(EventType.WindowCreated, (window, data) {
_readys[window] = true;
setState(() {});
}).create();
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Floatwing 示例'),
),
body: _ready
? ListView(
children: _windows.map((e) => _item(e)).toList(),
)
: Center(
child: ElevatedButton(
onPressed: () {
initAsyncState();
},
child: Text("开始")),
),
);
}
_debug(Window w) {
Navigator.of(context).pushNamed(w.config!.route!);
}
Widget _item(Window w) {
return Card(
margin: EdgeInsets.all(10),
child: Padding(
padding: EdgeInsets.all(10),
child: Column(
children: [
Text(w.id,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
SizedBox(height: 10),
Container(
width: double.infinity,
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: Color.fromARGB(255, 214, 213, 213),
borderRadius: BorderRadius.all(Radius.circular(4))),
child: Text(w.config?.toString() ?? ""),
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: (_readys[w] == true) ? () => w.start() : null,
child: Text("打开"),
),
TextButton(
onPressed: w.config?.route != null ? () => _debug(w) : null,
child: Text("调试")),
TextButton(
onPressed: (_readys[w] == true)
? () => {w.close(), w.share("close")}
: null,
child: Text("关闭", style: TextStyle(color: Colors.red)),
),
],
)
],
)),
);
}
}
// 示例页面
class NonrmalView extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("普通窗口")),
body: Center(child: Text("这是一个普通的浮动窗口")),
);
}
}
class AssistiveTouch extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("辅助触摸")),
body: Center(child: Text("这是一个辅助触摸窗口")),
);
}
}
class NightView extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("夜间模式")),
body: Center(child: Text("这是一个全屏的夜间模式窗口")),
);
}
}
更多关于Flutter浮动窗口管理插件flutter_floatwing的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter浮动窗口管理插件flutter_floatwing的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用 flutter_floatwing
插件来管理 Flutter 应用中的浮动窗口的示例代码。这个插件允许你在 Android 和 iOS 上创建和管理浮动窗口。
首先,确保你已经在 pubspec.yaml
文件中添加了 flutter_floatwing
依赖:
dependencies:
flutter:
sdk: flutter
flutter_floatwing: ^最新版本号 # 请替换为实际最新版本号
然后,运行 flutter pub get
来获取依赖。
接下来是具体的代码实现。
1. 初始化浮动窗口插件
在你的 Flutter 应用的入口文件(通常是 main.dart
)中,初始化 FlutterFloatwing
插件:
import 'package:flutter/material.dart';
import 'package:flutter_floatwing/flutter_floatwing.dart';
void main() {
runApp(MyApp());
// 初始化 FlutterFloatwing 插件
FlutterFloatwing.instance.init();
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
2. 创建浮动窗口
接下来,你可以创建一个浮动窗口。例如,在 HomePage
中添加一个按钮,点击按钮时显示浮动窗口:
import 'package:flutter/material.dart';
import 'package:flutter_floatwing/flutter_floatwing.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Float Window Example'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
_showFloatWindow();
},
child: Text('Show Float Window'),
),
),
);
}
void _showFloatWindow() {
FlutterFloatwing.instance.createFloatWindow(
FloatWindowParams(
context: context,
width: 300,
height: 400,
x: 100,
y: 200,
isDraggable: true,
isResizable: true,
child: FloatWindowContent(),
),
);
}
}
class FloatWindowContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Material(
color: Colors.white,
elevation: 8.0,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('This is a float window!'),
ElevatedButton(
onPressed: () {
FlutterFloatwing.instance.closeAllFloatWindows();
},
child: Text('Close'),
),
],
),
),
);
}
}
3. 权限处理
请注意,在 Android 上使用浮动窗口通常需要请求特定的权限,如 SYSTEM_ALERT_WINDOW
。你可以在 MainActivity.kt
或 MainActivity.java
中处理这些权限请求。
对于 Kotlin:
package com.example.yourapp
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import androidx.annotation.NonNull
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.SYSTEM_ALERT_WINDOW) != PackageManager.PERMISSION_GRANTED) {
val intent = Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:$packageName")
)
startActivityForResult(intent, REQUEST_CODE_OVERLAY_PERMISSION)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_OVERLAY_PERMISSION) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.SYSTEM_ALERT_WINDOW) == PackageManager.PERMISSION_GRANTED) {
// Permission granted, do something
} else {
// Permission denied, show a message to the user
}
}
}
companion object {
private const val REQUEST_CODE_OVERLAY_PERMISSION = 1000
}
}
对于 Java:
package com.example.yourapp;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import io.flutter.embedding.android.FlutterActivity;
public class MainActivity extends FlutterActivity {
private static final int REQUEST_CODE_OVERLAY_PERMISSION = 1000;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.SYSTEM_ALERT_WINDOW) != PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_CODE_OVERLAY_PERMISSION);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_OVERLAY_PERMISSION) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.SYSTEM_ALERT_WINDOW) == PackageManager.PERMISSION_GRANTED) {
// Permission granted, do something
} else {
// Permission denied, show a message to the user
}
}
}
}
这段代码展示了如何使用 flutter_floatwing
插件来创建和管理浮动窗口,并处理必要的权限请求。确保在发布应用时,仔细阅读插件的文档,以了解所有可用的功能和最佳实践。