Flutter Desktopでウィンドウサイズを変更したり制限したりする

4 min read読了の目安(約4400字

Flutter Desktopを使ってデスクトップ環境向けのアプリを書いていると、ウィンドウのサイズを変えたり制限したりしたくなる。特に、ウィンドウが小さくなりすぎると描画が崩れて困るので何とかしたい。

そんなときは、Google公式のwindow_sizeを使って、色々と設定できる。

https://github.com/google/flutter-desktop-embedding/tree/master/plugins/window_size

window_sizeの概要

Googleがデスクトップ環境向けに提供しているプラグインの1つ。

リポジトリのREADMEを超訳すると、こんな感じ。

このプラグインは、Flutterのコンテンツを含むウィンドウのサイズや位置を変更したり、画面情報を取得したりできるよ。
まだプロトタイプで、長期的にはFlutterのフレームワーク自体の機能に取って代わられるかも。あとAPIが大きく変わることもあるよ。
将来的にはウィンドウの最大化や最小化みたいなこともできるようになるかも。そんなプルリクエストを募集中!
macOS、Windows、Linuxをサポートしているけど、全部のプラットフォームに全部の機能が実装されているわけじゃないよ。ただ、サイズ変更や位置変更みたいな基本的な機能は3つのプラットフォームのどれでも使えるよ。

コードを書きながら試してみる

Flutterデフォルトのカウントアプリのコードを一部書き換えながら試してみる。

試した実行環境

自分が実行した環境は以下の通り。

  • Flutter 2.2.0
  • Windows 10

だけど多分、macOSなんかでも同じように動くと思われる。

設定

適当なFlutterのプロジェクトを作り、pubspec.yamlを開いて、dependenciesに以下の記述を追加する。

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  # 以下の記述を追加する。
  window_size:
    git:
      url: git://github.com/google/flutter-desktop-embedding
      path: plugins/window_size
      ref: e48abe7

このプラグインはGithubのリポジトリにしか置かれておらず、pub.devでは公開されていないため、こう書く。

リポジトリ内にプラグインの書き方について書かれているページがあって、超訳するとこんな感じ。

ここで公開されているプラグインは、そのうちFlutter自体の一部になるか、公式にサポートされる可能性のある試作品だよ。
このリポジトリのプラグインは、長期的な使用を目的としていないから、普通のFlutterプラグインみたいにpub.devでは公開されてないよ。なので代わりにこのリポジトリから直接使ってね。

refのところには、バージョンを固定したいコミットのハッシュ値を書いてね。普通はプラグインを追加した時点でのリポジトリの最新のコミット値かな。
refを省略することもできるけど、本気でお勧めしない。これがないと、プラグインに破壊的変更があった場合、いきなりプロジェクトが壊れちゃうからね。

ということで上記のコードでは現時点での最新のハッシュ値を書いてある。

簡単に動かしてみる。

まずはimportする。

lib/main.dart
import 'package:window_size/window_size.dart';

そしてmain()関数を以下のように書き換えてみる。

lib/main.dart
void main() async { // 情報を取得する関数が非同期なのでasyncを加える。
  WidgetsFlutterBinding.ensureInitialized(); // runApp()の前に色々するための呪文。

  // 一応プラットフォームをチェックしている。
  if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
    setWindowTitle('Size Limit Window Test'); // ウィンドウのタイトルを設定する。
    setWindowFrame(Rect.fromLTWH(200, 100, 1280, 720)); // ウィンドウの位置と大きさを指定する。
    setWindowMinSize(const Size(300, 200)); // ウィンドウの最小サイズを指定する。
    setWindowMaxSize(Size.infinite); // ウィンドウの最大サイズを指定する。

    // スクリーンの情報を取得して表示する。
    final info = await getCurrentScreen();
    print(info?.frame);
  }

  runApp(MyApp());
}

Windowsでの初回実行時にエラーが出たら

自分の環境では、初回の実行時にこんなエラーが出た。

Building with plugins requires symlink support.

Please enable Developer Mode in your system settings. Run
  start ms-settings:developers
to open settings.
exit code 1

開発者モードを有効にする必要があるらしい、ということで、コマンドラインからメッセージ中のコマンドを実行してみる。

start ms-settings:developers

すると設定画面が開くので、開発者モードのトグルスイッチをオンにする。警告か出るものの、そのままOK。

その後でビルドを行うと無事に完了し、実行される。

コードの解説

コード中にコメントで書いている通りだけど、簡単に解説。

情報取得系の関数(この場合はgetCurrentScreen())が非同期なので、main()関数をasyncにする。

まずはrunApp()の前に色々するための呪文を唱える。これがないとエラーになる。

一応プラットフォームをチェックしてから、各関数を使ってウィンドウへ色々とセットしている。

  • タイトル
  • 初期サイズ(X座標200、Y座標100、幅1280、高さ720)
  • 最小サイズ(幅300、高さ200)
  • 最大サイズ(制限なし)
    サイズの単位はピクセルっぽい。多分物理ピクセルなのかなとも思うけど、検証していない。

最後にスクリーンの情報を取得してprintしている。自分の環境だと以下のように表示された。

flutter: Rect.fromLTRB(0.0, 0.0, 2560.0, 1440.0)

関数の一覧

呼び出せる関数はこのソースに書いてあるもの。

https://github.com/google/flutter-desktop-embedding/blob/master/plugins/window_size/lib/src/window_size_utils.dart

普通に使うのは、上記のコード例で使ったものくらいだと思う。

他のものとして、例えば、setWindowVisibility()falseを渡すとウィンドウが消える。
Windowsだと画面上からガチで消える。最小化とかではなく、消える。閉じるわけではなく、消える。タスクマネージャーにはいるので、そこから終了させたりはできるけど。
なお、関数にtrueを渡すと消えたウィンドウが表示される。

あとマルチスクリーン環境で実行しているとき、getScreenList()を使えばそれぞれの画面の情報を得られるっぽい。試していないけど。

おまけと留意点

ウィンドウのサイズの固定方法

当然と言えば当然だけど、setWindowMinSize()setWindowMaxSize()で同じ値を指定すると、サイズ変更できないウィンドウとなる。

指定するサイズは何のサイズ?

関数で指定するサイズは、ウィンドウ自体の大きさとなっている。

つまりタイトルバーなんかの部分も含んだサイズで、アプリの中身のサイズではない。

じゃあきっちりとアプリのサイズを指定したいときにどうすれば良いかということなんだけど、調べた範囲だとFlutterではタイトルバーのサイズを得る方法がなさそうなので、今のところ難しいのではないかという認識。違っていたら教えて欲しい。

フルスクリーンにはできるの?

今のところは関数一発でフルスクリーンにするようなものはない。ウィンドウのタイトルバーを隠したりとか、そういうこともできない。

ウィンドウのサイズをディスプレイに合わせるだけなら、getCurrentScreen()で画面の情報を得てからそれに合わせれば一応は可能。だけどWindowsのタスクバーやMacのドックを考慮する必要があったりするので微妙な気もする。

フルスクリーンは誰もがやりたいと思うことで、Issueが立っているけど、何ヶ月も放置されていたりするので、まだしばらくは無理かも。

最後に

モバイルアプリと違ってウィンドウのサイズを自在に変えられるデスクトップアプリでは、特にウィンドウサイズを小さくしすぎないような制限は必須なので、かなり有用だと思う。


なお、ウィンドウのサイズを変える類似のパッケージとして、desktop_windowもある。

https://pub.dev/packages/desktop_window

今回取り上げたwindow_sizeとはそれぞれ機能が違っていて一長一短なので、試してみても良いと思う。個人で合う合わないもあるし。