From 120cccf23535f0999a7bf4b77c48a9f7339e0d9e Mon Sep 17 00:00:00 2001 From: WoNiu Date: Tue, 2 Apr 2024 20:29:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=8D=E6=AC=A1=E4=BF=AE=E6=94=B9=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/windows/show_animation_utils.dart | 147 ++++++++++++++++++++ lib/windows/synchronization_web_tool.dart | 43 +++++- lib/windows/web_grid_view.dart | 115 ++++++++++++++++ lib/windows/windowsJs.dart | 63 +++++---- lib/windows/windows_main_page.dart | 157 ++++++++++------------ lib/windows/windows_web_page.dart | 5 +- 6 files changed, 415 insertions(+), 115 deletions(-) create mode 100644 lib/windows/show_animation_utils.dart create mode 100644 lib/windows/web_grid_view.dart diff --git a/lib/windows/show_animation_utils.dart b/lib/windows/show_animation_utils.dart new file mode 100644 index 0000000..faa113c --- /dev/null +++ b/lib/windows/show_animation_utils.dart @@ -0,0 +1,147 @@ + +import 'package:flutter/material.dart'; + +enum TransitionType { + ///左侧弹出 + inFromLeft, + ///右侧弹出 + inFromRight, + ///顶部弹出 + inFromTop, + ///底部弹出 + inFromBottom, + ///缩放 + scale, + ///渐变 + fade, + ///旋转缩放 + rotation, + ///放大 + size, +} + + + //弹出动画 + // barrierDismissible:点击背景是否消失 + // child,builder:子 widget + // useRootNavigator: 是否推入传入 context的 导航器 + // routeSettings: 弹窗路由设置 + Future showAnimationDialog({ + required BuildContext context, + bool barrierDismissible = true, + Widget? child, + WidgetBuilder? builder, + bool useRootNavigator = true, + RouteSettings? routeSettings, + TransitionType? transitionType, + }) { + assert(child == null || builder == null); + assert(debugCheckHasMaterialLocalizations(context)); + + final ThemeData theme = Theme.of(context); + return showGeneralDialog( + context: context, + pageBuilder: (BuildContext buildContext, Animation animation, Animation secondaryAnimation) { + final Widget pageChild = child ?? Builder(builder: builder!); + return SafeArea( + child: Builder(builder: (BuildContext context) { + return Theme(data: theme, child: pageChild); + }), + ); + }, + barrierDismissible: barrierDismissible, ///点击背景是否消失 + barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + barrierColor: Colors.black38, ///背景色 + transitionDuration: const Duration(milliseconds: 200),///动画时间 + transitionBuilder: (context, animation1, animation2, child) { ///动画效果 + return _buildDialogTransitions(context, animation1, animation2, child, transitionType?? TransitionType.inFromBottom); + }, + useRootNavigator: useRootNavigator, + routeSettings: routeSettings, + ); + } + + + ///返回动画效果 + Widget _buildDialogTransitions( + BuildContext context, Animation animaton1, Animation secondaryAnimation, Widget child, TransitionType type) { + + /// 渐变效果 + if (type == TransitionType.fade) { + return FadeTransition( + // 从0开始到1 + opacity: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( + // 传入设置的动画 + parent: animaton1, + // 设置效果,快进漫出 这里有很多内置的效果 + curve: Curves.fastOutSlowIn, + )), + child: child, + ); + + ///缩放 + } else if (type == TransitionType.scale) { + return ScaleTransition( + scale: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: animaton1, curve: Curves.easeOutBack)),//Curves.easeOutBack + child: child, + ); + + /// 旋转加缩放动画效果 + } else if (type == TransitionType.rotation) { + + return RotationTransition( + turns: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( + parent: animaton1, + curve: Curves.fastOutSlowIn, + )), + child: ScaleTransition( + scale: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), + child: child, + ), + ); + + /// 左滑出动画效果 + } else if (type == TransitionType.inFromLeft) { + + return SlideTransition( + position: Tween(begin: Offset(-1.0, 0.0), end: Offset(0.0, 0.0)) + .animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), + child: child, + ); + + /// 右滑出动画效果 + } else if (type == TransitionType.inFromRight) { + return SlideTransition( + position: Tween(begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0)) + .animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), + child: child, + ); + + /// 顶部滑出动画效果 + } else if (type == TransitionType.inFromTop) { + return SlideTransition( + position: Tween(begin: Offset(0.0, -1.0), end: Offset(0.0, 0.0)) + .animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), + child: child, + ); + + /// 底部滑出动画效果 + } else if (type == TransitionType.inFromBottom) { + return SlideTransition( + position: Tween(begin: Offset(0.0, 1.0), end: Offset(0.0, 0.0)) + .animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), + child: child, + ); + + /// 放大出显动画效果 + } else if (type == TransitionType.size) { + return ScaleTransition( + child: child, + scale: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), + ); + } else { + return child; + } + } + + diff --git a/lib/windows/synchronization_web_tool.dart b/lib/windows/synchronization_web_tool.dart index ec0529a..a1c8611 100644 --- a/lib/windows/synchronization_web_tool.dart +++ b/lib/windows/synchronization_web_tool.dart @@ -6,10 +6,51 @@ import 'package:webview_windows/webview_windows.dart'; class SynchronizationWebTool{ + // 私有构造函数 + SynchronizationWebTool._(); + // 私有静态变量,保存类的唯一实例 + static SynchronizationWebTool? _instance; + + // 公开的静态方法,返回类的唯一实例 + static SynchronizationWebTool getInstance() { + _instance ??= SynchronizationWebTool._(); + return _instance!; + } + + bool webSync = false; + /// 主控 late WebviewController mainController; /// 受控 - List childController = []; + List _childControllers = []; + + setChildController(List childControllers){ + + for (var controller in childControllers) { + controller.addScriptToExecuteOnDocumentCreated(WindowsJs.clickEventJs); + controller.addScriptToExecuteOnDocumentCreated(WindowsJs.onloadZoom(90)); + } + + mainController = childControllers.first; + _childControllers = childControllers.sublist(1,10); + + mainController.addScriptToExecuteOnDocumentCreated(WindowsJs.clickEventJs); + mainController.webMessage.listen((event) { + print('mainController listen -- $event'); + if (event['click'] != null && webSync) { + Map click = event['click']; + double x = (click['x'] as int).toDouble(); + double y = (click['y'] as int).toDouble(); + + clickSynchronization(x, y); + } + }); + + } + + List get childController{ + return _childControllers; + } /// 点击同步 clickSynchronization(double x,double y){ diff --git a/lib/windows/web_grid_view.dart b/lib/windows/web_grid_view.dart new file mode 100644 index 0000000..ae3fd82 --- /dev/null +++ b/lib/windows/web_grid_view.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; +import 'package:web_synchronization_tool/windows/show_animation_utils.dart'; +import 'package:web_synchronization_tool/windows/synchronization_web_tool.dart'; +import 'package:web_synchronization_tool/windows/windowsJs.dart'; +import 'package:webview_windows/webview_windows.dart'; + +class WebGridController { + + Function(WebviewController controller)? addWebControllerBlack; + + addWebController(WebviewController controller) { + if (addWebControllerBlack != null) { + addWebControllerBlack!(controller); + } + } +} + +class WebGridWidget extends StatefulWidget { + const WebGridWidget({super.key, required this.controller}); + + final WebGridController controller; + + @override + State createState() => _WebGridWidgetState(); +} + +class _WebGridWidgetState extends State { + + List controllers = []; + + bool initDone = false; + @override + void initState() { + super.initState(); + + controllerInit(); + } + + Future controllerInit() async { + + for (var i = 0; i< 10 ; i++) { + var controller = WebviewController(); + await controller.initialize(); + controller.loadUrl('http://www.df6831.com/'); + + // controller.executeScript(WindowsJs.zoom(35)); + // controller.addScriptToExecuteOnDocumentCreated(WindowsJs.onloadZoom(35)); + + controllers.add(controller); + } + + SynchronizationWebTool.getInstance().setChildController(controllers); + + setState(() { + initDone = true; + }); + } + + @override + Widget build(BuildContext context) { + return GridView.builder( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 5, // 两列 + crossAxisSpacing: 8.0, // 水平间距 + mainAxisSpacing: 8.0, // 垂直间距 + childAspectRatio: 0.9), + itemBuilder: (BuildContext context, int index) { + return Stack( + children: [ + Webview(controllers[index]), + TextButton( + style: ButtonStyle( + overlayColor: MaterialStateProperty.resolveWith( + (states) => Colors.transparent)), + onPressed: () { + + var controller = controllers[index]; + // controller.executeScript(WindowsJs.zoom(100)); + + showAnimationDialog( + context: context, + // barrierDismissible: false, + child: ShowWebWidget(controller: controller,)); + }, + child: Container(), + ) + ], + ); + }, + itemCount: controllers.length, // 生成20个瀑布流瓦片 + ); + } +} + + +class ShowWebWidget extends StatelessWidget { + const ShowWebWidget({super.key, required this.controller}); + + final WebviewController controller; + + @override + Widget build(BuildContext context) { + return Center( + child: SizedBox( + width: 1400, + height: 900, + child: Webview(controller), + ), + ); + } + + + +} + diff --git a/lib/windows/windowsJs.dart b/lib/windows/windowsJs.dart index c9e6cee..f632938 100644 --- a/lib/windows/windowsJs.dart +++ b/lib/windows/windowsJs.dart @@ -5,31 +5,37 @@ document.addEventListener("click", function (event) { var x = event.clientX; var y = event.clientY; - var click = { 'x': x, 'y': y }; - // var value = { click: click }; + var click = { "x": x, "y": y }; + var value = { click: click }; // 发送消息 - window.chrome.webview.postMessage(click); + window.chrome.webview.postMessage(value); + + window.chrome.webview.postMessage({"text":event.target.textContent,"end":event.target.textContent === "进入游戏"}); // 检查点击的元素是否有类名为 'btn' - if (event.target.classList.contains("btn")) { + if (event.target.textContent === "进入游戏") { // 获取按钮上显示的文本内容 - var buttonText = event.target.innerText; + window.chrome.webview.postMessage({ "成功获取到btn": 1 }); + // window.chrome.webview.postMessage({ "btn": event.target.textContent }); - if (buttonText == "进入游戏") { - var btn = { x: "成功获取到btn", y: buttonText }; - window.chrome.webview.postMessage(btn); + // 阻止默认的链接跳转行为 + event.preventDefault(); - // 阻止默认的链接跳转行为 - event.preventDefault(); - - var newUrl = this.href; // 获取点击链接的跳转地址 - - // 在当前窗口打开目标地址 - // window.location.href = "http://www.df6831.com/game/"; - window.location.href = newUrl; - window.chrome.webview.postMessage({url:newUrl}}); - } + var oldUrl = window.location.href; + var classUrl = event.target.href; + + var str = oldUrl; + var startIndex = str.indexOf('www.'); + var endIndex = str.indexOf('/', startIndex); + var url = str.substring(startIndex, endIndex); + var newUrl = "https://" + url + "/game/"; + + window.chrome.webview.postMessage({"元素地址": classUrl ,"旧地址":window.location.href ,"截取":url,"新地址": newUrl}); + // 在当前窗口打开目标地址 + // window.location.href = "http://www.df6831.com/game/"; + window.location.href = newUrl; + } }); '''; @@ -54,28 +60,27 @@ document.addEventListener("click", function (event) { /// 监听加载,在加载完成后缩放 - static String onloadScale(int scale){ - assert(scale >= 1 && scale <= 100, 'zoom 1 到 100'); + static String onloadZoom(int zoom){ + assert(zoom >= 1 && zoom <= 100, 'zoom 1 到 100'); return ''' window.onload = function () { - // 修改页面缩放比例为0.5(50%) - document.body.style.transformOrigin = 'top left'; - document.body.style.transform = 'scale(${scale / 100})'; + var currentUrl = window.location.href; + if (currentUrl.endsWith('game/')) { + ${WindowsJs.zoom(zoom)} + } }; '''; } /// 修改缩放 - static String scale(int scale){ - assert(scale >= 1 && scale <= 100, 'zoom 1 到 100'); + static String zoom(int zoom){ + assert(zoom >= 1 && zoom <= 100, 'zoom 1 到 100'); return ''' - // document.body.style.zoom = "$scale%"; - document.body.style.transformOrigin = 'top left'; - document.body.style.transform = 'scale(${scale / 100})'; + document.body.style.zoom = "$zoom%"; '''; } - static String message = 'window.chrome.webview.postMessage({x:3333}});'; + static String message = 'window.chrome.webview.postMessage({x:3333});'; } diff --git a/lib/windows/windows_main_page.dart b/lib/windows/windows_main_page.dart index 2c7398b..b026dfd 100644 --- a/lib/windows/windows_main_page.dart +++ b/lib/windows/windows_main_page.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:web_synchronization_tool/windows/synchronization_web_tool.dart'; +import 'package:web_synchronization_tool/windows/web_grid_view.dart'; import 'package:web_synchronization_tool/windows/windowsJs.dart'; import 'windows_web_page.dart'; import 'package:webview_windows/webview_windows.dart'; @@ -11,11 +13,15 @@ class WindowsPage extends StatefulWidget { } class _WindowsPageState extends State { - final mainController = WebviewController(); - final controller = WebviewController(); + Widget? windowsWebWidget; + WebviewController mainController = WebviewController(); + final gridController = WebGridController(); bool initDone = false; + String clickId = ''; + String zoomId = ''; + @override void initState() { super.initState(); @@ -24,42 +30,31 @@ class _WindowsPageState extends State { } Future controllerInit() async { - await mainController.initialize(); - await controller.initialize(); - mainController.loadUrl('http://www.df6831.com/'); - controller.loadUrl('http://www.df6831.com/'); - addClickEventJS(); + gridController.addWebController(mainController); setState(() { initDone = true; }); - - // controller.setUserAgent('Mobile'); - - /// 通道消息 - mainController.webMessage.listen((event) { - print('mainController listen -- $event'); - // controller.executeScript(WindowsJs.clickJs(event['x'], event['y'])); - }); - - /// 通道消息 - controller.webMessage.listen((event) { - // print('controller listen -- $event'); - }); - - } - /// 注入点击监听 - addClickEventJS() async { - ScriptID? scriptId = await mainController.addScriptToExecuteOnDocumentCreated(WindowsJs.clickEventJs); - // mainController.addScriptToExecuteOnDocumentCreated(WindowsJs.onloadScale(70)); - // mainController.removeScriptToExecuteOnDocumentCreated(scriptId?? ''); - controller.addScriptToExecuteOnDocumentCreated(WindowsJs.clickEventJs); + /// 开启通道消息 + eventMessage() { + // 通道消息 + // mainController.webMessage.listen((event) { + // print('mainController listen -- $event'); + // if (event['click'] != null && webSync) { + // Map click = event['click']; + // double x = (click['x'] as int).toDouble(); + // double y = (click['y'] as int).toDouble(); + // x = x * (0.4 / 0.7); + // y = y * (0.4 / 0.7); + // // controller.executeScript(WindowsJs.clickJs(x, y)); + // } + // }); } @override @@ -75,45 +70,61 @@ class _WindowsPageState extends State { padding: const EdgeInsets.symmetric(horizontal: 50), child: Row( children: [ - TextButton( - onPressed: () { - mainController.executeScript(WindowsJs.clickJs(200, 900)); - // controller.executeScript(WindowsJs.clickJs(600, 100)); - }, - child: const Text('模拟点击测试')), + // TextButton( + // onPressed: () { + // mainController.executeScript(WindowsJs.clickJs(200, 900)); + // }, + // child: const Text('模拟点击测试')), TextButton( onPressed: () { mainController.executeScript(WindowsJs.inputJs(45)); - controller.executeScript(WindowsJs.inputJs(45)); + // controller.executeScript(WindowsJs.inputJs(45)); }, child: const Text('模拟输入测试')), TextButton( onPressed: () { - mainController.loadUrl('http://www.df6831.com/'); + mainController.loadUrl('https://www.baidu.com/'); }, child: const Text('跳转首页')), TextButton( onPressed: () { - mainController.executeScript(WindowsJs.scale(70)); - controller.executeScript(WindowsJs.scale(40)); + SynchronizationWebTool.getInstance().childController.forEach((controller) { + controller.executeScript(WindowsJs.zoom(35)); + }); + // 468, 72 + // controller.executeScript(WindowsJs.zoom(40));// 239,39 }, child: const Text('缩放')), + // TextButton( onPressed: () { - mainController.openDevTools(); + mainController + .executeScript('window.resizeBy(-100, -100);'); }, - child: const Text('开发者')), - TextButton( - onPressed: () { - mainController.clearCookies(); - mainController.clearCache(); - }, - child: const Text('清除缓存')), - TextButton( - onPressed: () { - mainController.executeScript(WindowsJs.message); - }, - child: const Text('发送消息')), + child: const Text('减少尺寸')), + + // TextButton( + // onPressed: () { + // mainController.openDevTools(); + // }, + // child: const Text('开发者')), + // TextButton( + // onPressed: () { + // mainController.executeScript(WindowsJs.message); + // }, + // child: const Text('发送消息')), + Row( + children: [ + const Text('同步'), + Switch( + value: SynchronizationWebTool.getInstance().webSync, + onChanged: (value) { + setState(() { + SynchronizationWebTool.getInstance().webSync = value; + }); + }) + ], + ) ], ), ), @@ -127,42 +138,20 @@ class _WindowsPageState extends State { Widget pageViewWidget() { return Row( children: [ - SizedBox( - width: 1350, - height: 1000, - child: WindowsWebWidget( - controller: mainController, - ), - ), - SizedBox( - width: 550, - height:400, - child: WindowsWebWidget( - controller: controller, - ), - ) + // SizedBox( + // width: 1000, + // height: 1000, + // child: inWindowsWebView(), + // ), + Expanded( + child: WebGridWidget( + controller: gridController, + )) ], ); } -} -class KeepAlivePage extends StatefulWidget { - final Widget child; - - KeepAlivePage({super.key, required this.child}); - - @override - _KeepAlivePageState createState() => _KeepAlivePageState(); -} - -class _KeepAlivePageState extends State - with AutomaticKeepAliveClientMixin { - @override - bool get wantKeepAlive => true; - - @override - Widget build(BuildContext context) { - super.build(context); - return widget.child; + Widget inWindowsWebView() { + return Webview(mainController); } } diff --git a/lib/windows/windows_web_page.dart b/lib/windows/windows_web_page.dart index 5d2c963..48d8e4c 100644 --- a/lib/windows/windows_web_page.dart +++ b/lib/windows/windows_web_page.dart @@ -10,6 +10,8 @@ class WindowsWebWidget extends StatefulWidget { class _WindowsWebWidgetState extends State { + Webview? webview; + @override void initState() { super.initState(); @@ -21,7 +23,8 @@ class _WindowsWebWidgetState extends State { } Widget inWindowsWebView(){ - return Webview(widget.controller); + webview ??= Webview(widget.controller); + return webview!; } }