在本篇中我们来简单聊聊 Dioxus 对于桌面平台的开发设计。
桌面应用原理 Dioxus-Desktop 主要使用 wry 生成窗口,WRY 是一款跨平台的 Webview 渲染库,它支持所有主流平台(Windows Linux MacOS)。其本质上就是在一个原生的窗口中嵌入 Webview 渲染器,从而使得我们可以将一些 HTML 内容嵌入到桌面程序之中,而 Dioxus 则是运用了这一点。
在这里贴一下 wry 的仓库地址:Tauri-Apps/wry
在 Dioxus 中,它会根据你传递的配置生成相应的文件,并加入事件的循环监听:
1 2 3 4 5 dioxus::desktop::launch_cfg(app, |config| { config.with_window(|win| { win.with_title("mrxzx.info" ) }) });
在启动一个 Desktop 应用时,我们可以通过闭包函数对窗口进行相关配置,这部分配置取自于 tao
包,目前 Dioxus 还没有进行这方面的封装。关于 WindowBuilder
的开发文档:WindowBuilder in tao::window - Rust (docs.rs)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 event_loop.run(move |window_event, event_loop, control_flow| { *control_flow = ControlFlow::Wait; match window_event { Event::NewEvents(StartCause::Init) => { Event::WindowEvent { event, window_id, .. } => match event { WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::Destroyed { .. } => desktop.close_window(window_id, control_flow), WindowEvent::Resized(_) | WindowEvent::Moved(_) => { if let Some (view) = desktop.webviews.get_mut(&window_id) { let _ = view.resize(); } } _ => {} }, Event::UserEvent(user_event) => { desktop_context::handler(user_event, &mut desktop, control_flow) } Event::MainEventsCleared => {} Event::Resumed => {} Event::Suspended => {} Event::LoopDestroyed => {} Event::RedrawRequested(_id) => {} _ => {} } })
当窗口被创建后,程序会进入一个 loop 循环,并一直等待事件的进入,并根据不同的事件进行不同的处理。
窗口交互 这一部分的原型主要是我提交的,因为在尝试制作无边框应用时遇到了 Window Drag
的问题,当隐藏窗口本身的头部栏后,无法对窗口进行托动,以及自定义关闭、最小化、最大化按钮。所以说一直在和 JK 讨论这方面的实现方案,最终决定制作一个 use_window
并封装一些函数在程序运行时可以被调用。(在此之前我们无法在运行时对窗口进行原生的交互,如 更新 Title 内容、隐藏窗口、关闭窗口等。)目前只需要在相应的 Element & Function 中使用 use_window
即可完成窗口的交互。
1 2 3 4 5 6 7 8 9 10 11 12 fn app (cx: Scope) -> Element { let win = use_window(&cx); cx.render(rsx! { div { "hello world" } button { onclick: move |_| { win.set_title("Dioxus YYDS!" ) }, "更换窗口标题" } }) }
目前支持的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 pub fn drag (&self ) {}pub fn set_minimized (&self , minimized: bool ) {}pub fn set_maximized (&self , maximized: bool ) {}pub fn toggle_maximized (&self ) {}pub fn set_visible (&self , visible: bool ) {}pub fn close (&self ) {}pub fn focus (&self ) {}pub fn set_fullscreen (&self , fullscreen: bool ) {}pub fn set_resizable (&self , resizable: bool ) {}pub fn set_always_on_top (&self , top: bool ) {}pub fn set_cursor_visible (&self , visible: bool ) {}pub fn set_cursor_grab (&self , grab: bool ) {}pub fn set_title (&self , title: &str ) {}pub fn set_decorations (&self , decoration: bool ) {}pub fn devtool (&self ) {}
这使得我们可以在 Dioxus 组件中与窗口进行交互。
实现方案 这里简单聊一聊这部分的实现方法;我们定义了一种 Custom 事件,并在 Desktop Context 被调用时,将对应的事件类型 Send 到 Tao 的事件循环之中,使得它触发相应的事件并进行响应。
1 2 3 Event::UserEvent(user_event) => { desktop_context::handler(user_event, &mut desktop, control_flow) }
这里的 UserEvent
便是在 Desktop Context 时触发的,它交给 desktop_contex::handler
进行处理。
更多交互 虽然目前我们实现大部分常用的 Window 交互接口,但它并不完整,所以说目前我们还在想办法完成更多交互功能。
多窗口 目前的 Dioxus-Desktop 仅支持单个窗口,不过我们正在尝试设计多窗口,这也是下一个大版本的主要任务。