Flutter浮动窗口管理插件floating_windows的使用
Flutter浮动窗口管理插件floating_windows的使用
特性
- 屏幕顶部浮动的小部件
- 可调整大小和位置的浮动小部件
- 可选择在树结构内浮动的空间(可选)
- 带有边距的限制边界
- 在弹出和关闭屏幕时进行状态管理(需要RouteObserver来管理弹出)
开始使用
在你的pubspec.yaml
文件中添加依赖:
dependencies:
flutter:
sdk: flutter
floating_windows: ^1.0.0
导入包:
import 'package:floating_windows/floating_windows.dart';
使用方法
首先创建一个FloatingOverlayController
实例。以下是绝对大小控制的例子:
final controller1 = FloatingOverlayController.absoluteSize(
maxSize: const Size(800, 800),
minSize: const Size(400, 300),
start: Offset.zero,
padding: const EdgeInsets.all(20.0),
constrained: true,
);
final controller2 = FloatingOverlayController.absoluteSize(
maxSize: const Size(800, 800),
minSize: const Size(400, 300),
start: const Offset(100, 100),
padding: const EdgeInsets.all(20.0),
constrained: true,
);
final controller3 = FloatingOverlayController.absoluteSize(
maxSize: const Size(800, 800),
minSize: const Size(300, 500),
start: const Offset(300, 300),
padding: const EdgeInsets.all(20.0),
constrained: true,
);
也可以使用相对大小控制:
final controller = FloatingOverlayController.relativeSize(
maxScale: 2.0,
minScale: 1.0,
start: Offset.zero,
padding: const EdgeInsets.all(20.0),
constrained: true,
);
然后将FloatingOverlay
插入到你的Widget树中,并给它控制器、子组件和浮动子组件:
FloatingOverlay(
controllers: [controller1, controller2, controller3],
floatingChildren: [
SizedBox(
width: 400,
height: 300,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
border: Border.all(
color: Colors.black,
width: 5.0,
),
),
),
),
SizedBox(
width: 400,
height: 300,
child: Container(
decoration: BoxDecoration(
color: Colors.amber,
border: Border.all(
color: Colors.black,
width: 5.0,
),
),
),
),
SizedBox(
width: 300,
height: 500,
child: Container(
decoration: BoxDecoration(
color: Colors.red,
border: Border.all(
color: Colors.black,
width: 5.0,
),
),
),
),
],
child: Container(),
)
你可以通过控制器来显示或隐藏浮动子组件:
controller.hide();
controller.isFloating;
controller.show();
controller.toggle();
完整示例Demo
以下是一个完整的示例,展示了如何使用floating_windows
插件:
import 'package:flutter/material.dart';
import 'package:floating_windows/floating_windows.dart';
import 'package:provider/provider.dart';
import 'dart:math' as math;
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
final routeObserver = RouteObserver();
return MaterialApp(
title: 'Floating Windows Example',
navigatorObservers: [routeObserver],
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Provider<RouteObserver>(
create: (_) => routeObserver,
child: const HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
final controller1 = FloatingOverlayController.absoluteSize(
maxSize: const Size(800, 800),
minSize: const Size(400, 300),
start: Offset.zero,
padding: const EdgeInsets.all(20.0),
constrained: true,
);
final controller2 = FloatingOverlayController.absoluteSize(
maxSize: const Size(800, 800),
minSize: const Size(400, 300),
start: const Offset(100, 100),
padding: const EdgeInsets.all(20.0),
constrained: true,
);
final controller3 = FloatingOverlayController.absoluteSize(
maxSize: const Size(800, 800),
minSize: const Size(300, 500),
start: const Offset(300, 300),
padding: const EdgeInsets.all(20.0),
constrained: true,
);
final routeObserver = Provider.of<RouteObserver>(context, listen: false);
return Scaffold(
appBar: AppBar(
title: const Text('Floating Windows Example'),
centerTitle: true,
),
body: FloatingOverlay(
routeObserver: routeObserver,
controllers: [controller1, controller2, controller3],
floatingChildren: [
SizedBox(
width: 400,
height: 300,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
border: Border.all(
color: Colors.black,
width: 5.0,
),
),
),
),
SizedBox(
width: 400,
height: 300,
child: Container(
decoration: BoxDecoration(
color: Colors.amber,
border: Border.all(
color: Colors.black,
width: 5.0,
),
),
),
),
SizedBox(
width: 300,
height: 500,
child: Container(
decoration: BoxDecoration(
color: Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0),
border: Border.all(
color: Colors.black,
width: 5.0,
),
),
),
),
],
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
title: 'Toggle Overlay 1',
onPressed: () {
controller1.toggle();
},
),
CustomButton(
title: 'Toggle Overlay 2',
onPressed: () {
controller2.toggle();
},
),
CustomButton(
title: 'Toggle Overlay 3',
onPressed: () {
controller3.toggle();
},
),
CustomButton(
title: 'Set Screen Center Offset',
onPressed: () {
final size = MediaQuery.of(context).size;
final rect = Rect.fromPoints(
Offset.zero,
Offset(size.width, size.height),
);
controller1.offset = rect.center;
},
),
CustomButton(
title: 'Set Scale to 2.0',
onPressed: () {
controller1.scale = 2.0;
},
),
CustomButton(
title: 'New Page',
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const NewPage()),
);
},
),
CustomButton(
title: 'New Page with AnimationController',
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Provider<RouteObserver>(
create: (_) => routeObserver,
child: const AnimationPage(),
),
),
);
},
),
],
),
),
),
);
}
}
class CustomButton extends StatelessWidget {
const CustomButton({
Key? key,
required this.onPressed,
required this.title,
}) : super(key: key);
final VoidCallback onPressed;
final String title;
[@override](/user/override)
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
child: Text(title),
onPressed: onPressed,
),
);
}
}
class NewPage extends StatelessWidget {
const NewPage({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('New Page'), centerTitle: true),
);
}
}
class AnimationPage extends StatefulWidget {
const AnimationPage({Key? key}) : super(key: key);
[@override](/user/override)
_AnimationPageState createState() => _AnimationPageState();
}
class _AnimationPageState extends State<AnimationPage> with SingleTickerProviderStateMixin {
late final AnimationController animationController;
late final FloatingOverlayController controller;
[@override](/user/override)
void initState() {
animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
controller = FloatingOverlayController.absoluteSize(
maxSize: const Size(200, 200),
minSize: const Size(100, 100),
padding: const EdgeInsets.all(20.0),
constrained: true,
);
super.initState();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Floating Overlay Example'),
centerTitle: true,
),
body: FloatingOverlay(
routeObserver: Provider.of<RouteObserver>(context, listen: false),
controllers: [controller],
floatingChildren: [
SizedBox.square(
dimension: 100.0,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
border: Border.all(
color: Colors.black,
width: 5.0,
),
),
),
),
],
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
child: const Text('Toggle Overlay'),
onPressed: () {
controller.toggle();
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
child: const Text('New Page'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const NewPage()),
);
},
),
),
],
),
),
),
);
}
}
更多关于Flutter浮动窗口管理插件floating_windows的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter浮动窗口管理插件floating_windows的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter应用中使用floating_windows
插件来管理浮动窗口的示例代码。floating_windows
插件允许你在Android和iOS平台上创建和管理浮动窗口(也称为小窗口或悬浮窗)。
首先,你需要在你的pubspec.yaml
文件中添加floating_windows
依赖:
dependencies:
flutter:
sdk: flutter
floating_windows: ^0.3.0 # 请注意版本号,使用最新版本
然后运行flutter pub get
来获取依赖。
接下来是一个简单的示例,展示了如何使用floating_windows
插件来创建一个浮动窗口:
import 'package:flutter/material.dart';
import 'package:floating_windows/floating_windows.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Floating Windows Example'),
),
body: Center(
child: ElevatedButton(
onPressed: _createFloatingWindow,
child: Text('Create Floating Window'),
),
),
),
);
}
void _createFloatingWindow() async {
// 检查平台是否支持浮动窗口
if (!await FloatingWindows.isSupported) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Floating windows are not supported on this platform.')),
);
return;
}
// 创建浮动窗口
final windowInfo = await FloatingWindows.create({
'width': 300,
'height': 400,
'x': 0, // 窗口初始位置的x坐标
'y': 0, // 窗口初始位置的y坐标
});
// 构建浮动窗口的内容
final floatingWidget = MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Floating Window'),
),
body: Center(
child: Text('This is a floating window!'),
),
),
);
// 显示浮动窗口
await FloatingWindows.show(
windowInfo.id,
floatingWidget,
);
}
}
在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个按钮。点击按钮时,会检查当前平台是否支持浮动窗口。如果支持,则创建一个浮动窗口并显示它。
注意事项
- 权限:在Android上,显示浮动窗口通常需要
SYSTEM_ALERT_WINDOW
权限。你可能需要引导用户到系统的设置页面手动授予该权限。 - 平台差异:iOS和Android对浮动窗口的支持和限制有所不同。在实际开发中,你可能需要根据平台差异做额外的适配。
- 插件版本:插件的API可能会随着版本更新而变化,请参考最新的插件文档以获取最新的使用方法和最佳实践。
这个示例代码提供了一个基本的起点,你可以根据自己的需求进一步扩展和定制浮动窗口的功能和外观。