PicaComic 多窗口通信机制:桌面端数据共享实现
PicaComic 多窗口通信机制:桌面端数据共享实现
引言
在桌面端应用中,多窗口通信是一个常见的需求,它允许不同窗口之间共享数据和状态,提升用户体验。PicaComic作为一款使用Flutter构建的漫画应用,在桌面端实现了高效的多窗口通信机制。本文将深入探讨PicaComic的多窗口通信实现方式,包括状态管理、窗口管理和数据共享等关键技术点。
状态管理基础
PicaComic采用了自定义的状态管理方案,核心类为StateController。该类提供了状态注册、查找、更新等功能,为多窗口通信奠定了基础。
StateController类
StateController是一个抽象类,提供了状态管理的核心功能。它通过静态方法put和find实现了状态的注册和查找,支持带标签的状态管理,方便区分不同实例。
abstract class StateController {
static final _controllers = <StateControllerWrapped>[];
static T put<T extends StateController>(T controller,
{Object? tag, bool autoRemove = false}) {
_controllers.add(StateControllerWrapped(controller, autoRemove, tag));
return controller;
}
static T find<T extends StateController>({Object? tag}) {
try {
return _controllers
.lastWhere((element) =>
element.controller is T && (tag == null || tag == element.tag))
.controller as T;
} catch (e) {
throw StateError("$T with tag $tag Not Found");
}
}
// 其他方法...
}
源码路径:lib/foundation/state_controller.dart
StateBuilder组件
StateBuilder是一个泛型组件,用于构建依赖于StateController的UI。它会在初始化时查找或创建指定类型的StateController,并在状态更新时重建UI。
class StateBuilder<T extends StateController> extends StatefulWidget {
const StateBuilder({
super.key,
this.init,
this.dispose,
this.initState,
this.tag,
required this.builder,
this.id,
});
final Widget Function(T controller) builder;
// 其他属性和方法...
}
源码路径:lib/foundation/state_controller.dart
窗口管理
PicaComic在桌面端使用了window_manager插件进行窗口管理,并通过自定义的WindowFrame组件实现了窗口标题栏和边框的定制。
App类中的平台判断
App类中定义了一系列静态属性,用于判断当前运行的平台,这对于区分桌面端和移动端的窗口行为非常重要。
class App {
static bool get isAndroid => Platform.isAndroid;
static bool get isIOS => Platform.isIOS;
static bool get isWindows => Platform.isWindows;
static bool get isLinux => Platform.isLinux;
static bool get isMacOS => Platform.isMacOS;
static bool get isDesktop =>
Platform.isWindows || Platform.isLinux || Platform.isMacOS;
static bool get isMobile => Platform.isAndroid || Platform.isIOS;
// 其他属性和方法...
}
WindowFrame组件
WindowFrame组件是PicaComic桌面端窗口的核心容器,它包含了自定义的标题栏、窗口控制按钮和侧边栏等元素。
class WindowFrame extends StatelessWidget {
const WindowFrame(this.child, {super.key});
final Widget child;
@override
Widget build(BuildContext context) {
StateController.putIfNotExists<WindowFrameController>(
WindowFrameController());
if (App.isMobile) return child;
return StateBuilder<WindowFrameController>(builder: (controller) {
// 构建窗口框架...
});
}
// 其他方法...
}
源码路径:lib/components/window_frame.dart
WindowFrameController
WindowFrameController是WindowFrame组件的状态控制器,管理窗口的主题、边框显示等状态。
class WindowFrameController extends StateController {
bool useDarkTheme = false;
bool isHideWindowFrame = false;
void setDarkTheme() {
useDarkTheme = true;
update();
}
void resetTheme() {
useDarkTheme = false;
update();
}
VoidCallback openSideBar = () {};
void hideWindowFrame() {
isHideWindowFrame = true;
update();
}
void showWindowFrame() {
isHideWindowFrame = false;
update();
}
}
源码路径:lib/components/window_frame.dart
多窗口通信实现
PicaComic的多窗口通信主要依赖于全局状态管理和窗口事件监听。通过将状态存储在全局的StateController中,不同窗口可以共享和更新同一份状态。
全局状态共享
PicaComic使用StateController的静态方法put和find来实现全局状态的注册和查找。例如,在应用初始化时注册一个全局的WindowFrameController:
StateController.putIfNotExists<WindowFrameController>(WindowFrameController());
然后在其他窗口中通过find方法获取该控制器:
var controller = StateController.find<WindowFrameController>();
这样,不同窗口就可以通过同一个WindowFrameController实例来共享状态和触发更新。
窗口事件监听
PicaComic使用window_manager插件监听窗口事件,如最大化、最小化、关闭等,并在事件发生时更新状态或执行相应操作。
class _WindowButtonsState extends State<WindowButtons> with WindowListener {
bool isMaximized = false;
@override
void initState() {
windowManager.addListener(this);
windowManager.isMaximized().then((value) {
if (value) {
setState(() {
isMaximized = true;
});
}
});
super.initState();
}
@override
void onWindowMaximize() {
setState(() {
isMaximized = true;
});
super.onWindowMaximize();
}
@override
void onWindowUnmaximize() {
setState(() {
isMaximized = false;
});
super.onWindowUnmaximize();
}
// 其他事件处理方法...
}
源码路径:lib/components/window_frame.dart
数据持久化
为了在窗口关闭后保留状态,PicaComic实现了窗口位置和大小的持久化存储。
class WindowPlacement {
final Rect rect;
final bool isMaximized;
// 其他属性和方法...
Future<void> writeToFile() async {
var file = File("${App.dataPath}/window_placement");
await file.writeAsString(jsonEncode({
'width': rect.width,
'height': rect.height,
'x': rect.topLeft.dx,
'y': rect.topLeft.dy,
'isMaximized': isMaximized
}));
}
static Future<WindowPlacement> loadFromFile() async {
try {
var file = File("${App.dataPath}/window_placement");
if (!file.existsSync()) {
return defaultPlacement;
}
var json = jsonDecode(await file.readAsString());
var rect =
Rect.fromLTWH(json['x'], json['y'], json['width'], json['height']);
return WindowPlacement(rect, json['isMaximized']);
} catch (e) {
return defaultPlacement;
}
}
}
源码路径:lib/components/window_frame.dart
实际应用场景
多窗口漫画阅读
在PicaComic中,用户可以同时打开多个窗口阅读不同的漫画。通过全局状态管理,这些窗口可以共享用户的阅读历史、收藏列表等数据。
主题同步
当用户在一个窗口中切换主题时,WindowFrameController会更新全局状态,其他窗口会通过状态监听自动应用新的主题设置。
void setDarkTheme() {
useDarkTheme = true;
update();
}
void resetTheme() {
useDarkTheme = false;
update();
}
源码路径:lib/components/window_frame.dart
窗口位置记忆
PicaComic会记住每个窗口的位置和大小,当用户重新打开窗口时,会恢复到上次关闭时的状态。
static Future<WindowPlacement> loadFromFile() async {
try {
var file = File("${App.dataPath}/window_placement");
if (!file.existsSync()) {
return defaultPlacement;
}
var json = jsonDecode(await file.readAsString());
var rect =
Rect.fromLTWH(json['x'], json['y'], json['width'], json['height']);
return WindowPlacement(rect, json['isMaximized']);
} catch (e) {
return defaultPlacement;
}
}
源码路径:lib/components/window_frame.dart
总结
PicaComic通过自定义的StateController实现了全局状态管理,结合window_manager插件提供的窗口操作能力,构建了一个高效的多窗口通信机制。这种机制不仅满足了漫画阅读场景下的多窗口需求,也为其他桌面端Flutter应用提供了参考。
核心实现包括:
- 使用
StateController进行全局状态管理 - 通过
WindowFrame和WindowFrameController管理窗口状态 - 利用文件存储持久化窗口位置和大小
- 通过状态更新实现多窗口数据同步
这种设计既充分利用了Flutter的跨平台特性,又针对桌面端进行了专门的优化,为用户提供了流畅的多窗口体验。
参考资料
更多推荐



所有评论(0)