关于flutter:介绍-Flutter-桌面应用-NativeShell

12次阅读

共计 6683 个字符,预计需要花费 17 分钟才能阅读完成。

猫哥说

看到这张图片,我就感觉脖子酸。。。我这样摆过,尽管看起来很 cool,而后你的脖子要上下调整,这比左右调整麻烦。

明天举荐浏览的是对于 Flutter 桌面开发,上面有原文、代码 Git 链接。

开始前我想起 React Native 说过的一句话《用同样的办法在多端开发》,这句话很玄妙又很正确,就是说不是让你同一套代码同时能编译成 ios android web windows linux …,只是代码的高度复用,所以有的同学在做多端架构时就要留神拆包了。

比方 你的业务代码、API、Entity、性能函数 很多状况下是复用的。然而各个平台的底层、交互体验是个性化。

不要被在 ios android 两端平滑兼容所坑骗。

明天介绍 NativeShell 这个桌面程序,这个程序演示了 多窗口、模式对话框、拖拽、菜单、工具栏、文件操作、零碎 API 调用的例子,如果你正在做钻研,这是一个很好参考。

老铁记得 转发,猫哥会出现更多 Flutter 好文~~~~

微信群 ducafecat

原文

https://matejknopp.com/post/i…

视频

代码

https://github.com/nativeshel…

参考

  • http://airflow.app/
  • https://airflow.app/remote-app/
  • https://github.com/nativeshel…
  • https://github.com/nativeshel…
  • https://github.com/nativeshel…

注释

自从我第一次看到 Turbo Vision,我就对桌面应用程序感兴趣。DOS 中那些文本模式可调整大小的窗口对我来说就像魔术一样。它激发了人们对用户界面框架的趣味,这种框架在 20 多年后仍然很弱小。

在过来十年左右的工夫里,人们的注意力次要转移到了网络和挪动设施上,这并没有让我感到特地快乐。所以我感觉是时候从暗影中爬出来,来到我的舒服区,试着把一些聚光灯带回它应该在的中央。到桌面下来!:)

Flutter 之路

我最初一个解决的桌面应用程序是(当初依然是) Airflow。它是 Qt 和大量平台特定代码的混合体。如果我本人这么说的话,我对最终的后果十分称心,然而开发人员的教训和整体生产力还有很多须要改良的中央。

http://airflow.app/

大概两年前,我须要一个实用于 iOS 和安卓零碎的气流应用程序。通过几个原型后,决定做出,我去 Flutter。我的确喜爱认为我有本人的 UI 开发教训,毕竟,我在不同的平台上应用过十几个 GUI 框架,所以当初没有什么能让我感到诧异的了,对吧?错了。他们所有人中最大的惊喜就是和 Flutter 一起工作的感觉是如许的好。在我的毕生中,素来没有,一次也没有,建设用户界面这么有意义。

https://airflow.app/remote-app/

如果我能用这种形式构建桌面应用程序,岂不是很神奇?当然,这是可能的,但事实是一个残酷的情妇,在那个时候桌面嵌入依然处于婴儿期。那就回到 Qt 吧。但这个念头始终在我脑海中挥之不去。

一两年过来了,很多事件产生了变动。还有很多工作要做,然而桌面嵌入曾经成熟了很多,而且 Flutter on desktop 曾经开始成为一个可行的抉择。

Flutter desktop 嵌入

当初你可能会问: Matt,Flutter 不是曾经嵌入了桌面吗? 那么这一切都是为了什么呢?

是的,的确如此。NativeShell 就建设在他们之上。您能够将 Flutter 桌面嵌入程序设想为一个平台视图组件(想想 GtkWidget、NSView 或者,恕我直言,HWND)。它解决鼠标和键盘输入,绘画,但它不尝试治理窗口,或 Flutter 引擎 / 隔离。或者做一些像平台菜单和拖放的事件。为了使事件更加简单,Flutter 嵌入在每个平台上都有齐全不同的 API。因而,如果您心愿为一些低级代码创立引擎或注册平台通道处理程序,则须要为每个平台别离执行此操作。

https://nativeshell.dev/

这就是 NativeShell 染指的中央

从 Flutter 桌面嵌入完结的中央开始。它为现有的 Flutter 嵌入提供了一个统一的、与平台无关的 API。它治理引擎和窗户。它提供了拖放反对,对平台菜单的拜访,以及其余超出 Flutter 嵌入范畴的性能。并且它通过简略易用的 Dart API 公开了所有这些。

NativeShell 是用铁锈写的。锈是平凡的,因为它能够让你编写高效的低级平台特定的代码,如果你须要,但它也让你应用 NativeShell,而不用晓得任何锈。简略地执行货物运输是所有须要让事件进行。Cargo 是 Rust 软件包管理器(就像 pub 是用于 Dart 的),它负责下载和构建所有依赖项。

开始

  • Install Rust
    https://www.rust-lang.org/too…
  • Install Flutter
    https://flutter.dev/docs/get-…
  • 在 Flutter 中启用桌面反对(为您的平台抉择一个)
$ flutter config --enable-windows-desktop
$ flutter config --enable-macos-desktop
$ flutter config --enable-linux-desktop
  • Switch to Flutter Master
$ flutter channel master
$ flutter upgrade

在这之后,你应该能够开始了:

$ git clone https://github.com/nativeshell/examples.git
$ cd examples
$ cargo run

NativeShell 通明地集成了 Flutter 建设过程和货物。如果铁锈和飞镖之神在对你微笑,这就是你当初应该看到的:

Platform Channels

如果您须要从 Flutter 应用程序调用本机代码,这两个选项是平台通道或 FFI。对于个别应用的平台通道是事后设计好的,因为它们更容易应用,并且可能在平台和 UI 线程之间适当地传递音讯。

这就是应用 NativeShell 注册平台通道处理程序的成果(我保障,这里也是惟一的 Rust 代码)

fn register_example_channel(context: Rc<Context>) {
    context
        .message_manager
        .borrow_mut()
        .register_method_handler("example_channel", |call, reply, engine| {match call.method.as_str() {
                "echo" => {reply.send_ok(call.args);
                }
                _ => {}}
        });
}

为了间接应用现有的平台嵌入 API 来实现这项工作,您须要应用平台特定的 API 为每个平台别离编写这些代码。而后确保每次创立新引擎时都注册处理程序(敞开引擎时可能登记)。

应用 NativeShell,您只需注册处理程序一次,它能够从任何引擎调用。音讯能够通过 Serde 被通明地序列化和反序列化为 Rust 构造(应用 Flutter 的规范办法编解码格局)。

https://github.com/nativeshel…

Window Management

想必你心愿你的桌面应用程序有多个窗口?NativeShell 曾经掩护你了。调整窗口大小到内容或设置最小的窗口大小,使 Flutter 布局不底流?它也能做到这一点。它还确保只在内容筹备好后才显示窗口,从而打消了俊俏的闪动。

目前,每个窗口作为独自的独立窗体运行。NativeShell 为创立窗口、设置和调整几何形态、更新款式和窗口题目提供了 API。它还提供了便于在窗口之间进行通信的 API。

视频能够依据内容调整大小,也能够依据内容大小调整大小。

  • 多窗口

  • 模式对话框

这将是 Dart 中如何创立和治理多个窗口的最小演示:

void main() async {runApp(MinimalApp());
}

class MinimalApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Widgets above WindowWidget will be same in all windows. The actual
    // window content will be determined by WindowState
    return MaterialApp(
      home: WindowWidget(onCreateState: (initData) {
          WindowState? context;
          context ??= OtherWindowState.fromInitData(initData);
          // possibly no init data, this is main window
          context ??= MainWindowState();
          return context;
        },
      ),
    );
  }
}

class MainWindowState extends WindowState {
  @override
  Widget build(BuildContext context) {
    return TextButton(onPressed: () async {
        // This will create new isolate for a window. Whatever is given to
        // Window.create will be provided by WindowWidget in new isolate
        final window = await Window.create(OtherWindowState.toInitData());
        // you can use the window object to communicate with newly created
        // window or register handlers for window events
        window.closeEvent.addListener(() {print('Window closed');
        });
      },
      child: Text('Open Another Window'),
    );
  }
}

class OtherWindowState extends WindowState {
  @override
  Widget build(BuildContext context) {return Text('This is Another Window!');
  }

  // This can be anything that fromInitData recognizes
  static dynamic toInitData() => {'class': 'OtherWindow',};

  static OtherWindowState? fromInitData(dynamic initData) {if (initData is Map && initData['class'] == 'OtherWindow') {return OtherWindowState();
    }
    return null;
  }
}

Drag & Drop

很难设想还有哪个桌面用户界面框架不反对拖放操作。NativeShell 反对拖放文件门路、url、自定义 Dart 数据(由 StandardMethodCodec 实现序列化),甚至能够扩大以解决自定义平台特定格局。

它应该很容易应用,而且我对它的后果很称心,只管它的确波及到编写一些看起来十分吓人的代码。

https://github.com/nativeshel…

https://github.com/nativeshel…

Popup Menu

很多框架和应用程序都犯了这样的谬误,这经常让我感到诧异。直到最近 Firefox 才开始在 macOS 上应用本地弹出菜单。无论你的应用程序如许粗劣,如果你的菜单出错了,你就会感觉不对劲。

容许你轻松地创立和显示上下文菜单。思考到菜单零碎的弱小性能,这个菜单 API 看似简略。菜单是反馈性的。你能够要求重建菜单,而可见和 NativeShell 将计算三角洲和只更新菜单项实际上曾经扭转。

  int _counter = 0;

  void _showContextMenu(TapDownDetails e) async {final menu = Menu(_buildContextMenu);

    // Menu can be updated while visible
    final timer = Timer.periodic(Duration(milliseconds: 500), (timer) {
      ++_counter;
      // This will call the _buildContextMenu() function, diff the old
      // and new menu items and only update those platform menu items that
      // actually changed
      menu.update();});

    await Window.of(context).showPopupMenu(menu, e.globalPosition);

    timer.cancel();}

  List<MenuItem> _buildContextMenu() => [MenuItem(title: 'Context menu Item', action: () {}),
        MenuItem(title: 'Menu Update Counter $_counter', action: null),
        MenuItem.separator(),
        MenuItem.children(title: 'Submenu', children: [MenuItem(title: 'Submenu Item 1', action: () {}),
          MenuItem(title: 'Submenu Item 2', action: () {}),
        ]),
      ];

MenuBar

可能是 NativeShell 中我最喜爱的性能。在 macOS 上,它出现为空窗口小部件,而是将菜单放在零碎菜单栏(在屏幕顶部)。在 Windows 和 Linux 上,它应用 Flutter 小部件出现顶级菜单项,而后应用本机菜单解决其余部分。这意味着菜单栏能够位于小部件层次结构中的任何地位,它不局限于窗口的顶部,也不依赖于 GDI 或 Gtk 来绘制 iself。

它反对鼠标跟踪和键盘导航,就像一般零碎菜单栏一样,但没有任何限度。

当初状况如何

NativeShell 正在被惨重的开发。事件很可能会破裂。迫切需要更多的文档和示例。但我认为它的形态可能对某些人有用。

所有三个反对的平台 (macOS,Windows,Linux) 都具备齐全的等同性能。

https://github.com/nativeshel…

https://github.com/nativeshel…

https://github.com/nativeshel…

如果你一路走到了这里,你能够持续 nativeshell.dev。

https://nativeshell.dev/

感谢您的反馈!

https://github.com/nativeshel…


© 猫哥

https://ducafecat.tech/

https://github.com/ducafecat

往期

开源

GetX Quick Start

https://github.com/ducafecat/…

新闻客户端

https://github.com/ducafecat/…

strapi 手册译文

https://getstrapi.cn

微信探讨群 ducafecat

系列汇合

译文

https://ducafecat.tech/catego…

开源我的项目

https://ducafecat.tech/catego…

Dart 编程语言根底

https://space.bilibili.com/40…

Flutter 零根底入门

https://space.bilibili.com/40…

Flutter 实战从零开始 新闻客户端

https://space.bilibili.com/40…

Flutter 组件开发

https://space.bilibili.com/40…

Flutter Bloc

https://space.bilibili.com/40…

Flutter Getx4

https://space.bilibili.com/40…

Docker Yapi

https://space.bilibili.com/40…

正文完
 0