35
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

UnityでFlutterっぽい開発ができるので試してみた

Last updated at Posted at 2022-10-27

はじめに

UnityでFlutterっぽいコードを書いて、アプリを作れるパッケージがあるという記事を見て、気になったので試してみました。

C#は5年、Dartは1~2年くらい経験があるので、本記事で紹介するパッケージを使ってみて、どこまでFlutterっぽいのか? どういう違いがあるか?などを最後にまとめています。

※本記事で紹介しているパッケージのバージョンですが、GitHubでアーカイブ化された古いバージョンのリポジトリのため、使うのは非推奨です。最新のリポジトリは以下になります。(私の環境だと使用できなかったため古いバージョンを使用しています。ご注意ください)
https://github.com/UIWidgets/com.unity.uiwidgets

作成環境

  • Unity エディタバージョン 2021.3.8.f1

目次

  1. UIWidgetsの導入
  2. ToDoアプリっぽくする
  3. さわってみた所感

UIWidgetsの導入

UIWidgetsとは、UnityでFlutterっぽくアプリ開発ができるパッケージの名前です。
導入はリポジトリからコードをダウンロードし、パッケージを使用したいプロジェクトのPackagesフォルダ配下に入れるだけです。
本章では、パッケージを導入 ~ 起動の確認まで説明したいと思います。
※なお、冒頭で説明した通り、導入説明は古いバージョンのパッケージの説明になりますのでご注意ください

プロジェクト作成

まずUnityでプロジェクトを作成します。
テンプレートは2D、プロジェクト名をUIWidgetsSampleとしました。

パッケージのダウンロード

Gitを使用する場合

  • ターミナルを開いて、cdコマンドで作成した「プロジェクトフォルダ/Packages」に移動してください
  • 以下のコマンドを実行してください
git clone https://github.com/UnityTech/UIWidgets.git com.unity.uiwidgets

Gitを使用しない場合

  • リポジトリDownload ZIPからコードをダウンロードしてください。
    image.png

  • ダウンロードが終わったら解凍後、作成したプロジェクトフォルダのPackagesフォルダにコピーか移動してください。

起動の確認

シーンの設定

  • Unityで作成したプロジェクトを開く
  • UIWidgetsを使いたいシーンを開き、UI‐Canvasを追加
  • 追加したCanvasUI‐Panelを追加
  • 追加したPanelImageコンポーネントを削除

スクリプトの記述

  • スクリプトを作成し、名前をUIWidgetsExampleに変更します
  • リポジトリのREADMEにあるサンプルコードをコピペします。
UIWidgetsExample.cs
 using System.Collections.Generic;
 using Unity.UIWidgets.animation;
 using Unity.UIWidgets.engine;
 using Unity.UIWidgets.foundation;
 using Unity.UIWidgets.material;
 using Unity.UIWidgets.painting;
 using Unity.UIWidgets.ui;
 using Unity.UIWidgets.widgets;
 using UnityEngine;
 using FontStyle = Unity.UIWidgets.ui.FontStyle;

 namespace UIWidgetsSample {
     public class UIWidgetsExample : UIWidgetsPanel {
         protected override void OnEnable() {
             // if you want to use your own font or font icons.
             // FontManager.instance.addFont(Resources.Load<Font>(path: "path to your font"), "font family name");

             // load custom font with weight & style. The font weight & style corresponds to fontWeight, fontStyle of
             // a TextStyle object
             // FontManager.instance.addFont(Resources.Load<Font>(path: "path to your font"), "Roboto", FontWeight.w500,
             //    FontStyle.italic);

             // add material icons, familyName must be "Material Icons"
             // FontManager.instance.addFont(Resources.Load<Font>(path: "path to material icons"), "Material Icons");

             base.OnEnable();
         }

         protected override Widget createWidget() {
             return new WidgetsApp(
                 home: new ExampleApp(),
                 pageRouteBuilder: (RouteSettings settings, WidgetBuilder builder) =>
                     new PageRouteBuilder(
                         settings: settings,
                         pageBuilder: (BuildContext context, Animation<float> animation,
                             Animation<float> secondaryAnimation) => builder(context)
                     )
             );
         }

         class ExampleApp : StatefulWidget {
             public ExampleApp(Key key = null) : base(key) {
             }

             public override State createState() {
                 return new ExampleState();
             }
         }

         class ExampleState : State<ExampleApp> {
             int counter = 0;

             public override Widget build(BuildContext context) {
                 return new Column(
                     children: new List<Widget> {
                         new Text("Counter: " + this.counter),
                         new GestureDetector(
                             onTap: () => {
                                 this.setState(()
                                     => {
                                     this.counter++;
                                 });
                             },
                             child: new Container(
                                 padding: EdgeInsets.symmetric(20, 20),
                                 color: Colors.blue,
                                 child: new Text("Click Me")
                             )
                         )
                     }
                 );
             }
         }
     }
 }

起動確認

  • Panelにスクリプトをアタッチ
  • Playボタンを押下する
    以下のような画面になると思います。
    image.png

ToDoアプリっぽくする

上記だと全然Flutterっぽさがないので、FlutterっぽくToDoアプリっぽいものを作ってみました。
以下の動作を実装しています。

  • タップすると項目がDoneになる
  • スワイプで削除する

BottomNavigationSampledfdf.gif

サンプルコード(ToDoのデータモデル)

public class ToDoData
{
    public int Id { get; private set; }
    public string Title { get; private set; }

    public ToDoData(int id, string title)
    {
        Id = id;
        Title = title;
    }
}

サンプルコード(ToDoリストのWidget)

class ExampleApp : StatefulWidget
 {


     public ExampleApp(Key key = null) : base(key)
     {
     }

     public override State createState()
     {
         return new ExampleState();
     }
 }

 class ExampleState : State<ExampleApp>
 {
     private List<ToDoData> _toDoDatas = new List<ToDoData>()
     {
         new ToDoData(1, "ToDo1"),
         new ToDoData(2, "ToDo2"),
         new ToDoData(3, "ToDo3"),
         new ToDoData(4, "ToDo4"),
         new ToDoData(5, "ToDo5"),
     };

     public override Widget build(BuildContext context)
     {
         return new Scaffold(
             appBar: new PreferredSize(
                 preferredSize: Size.fromHeight(120f),
                 child: new AppBar()
             ),
             body: ListView.builder(
                 itemBuilder: (BuildContext context, int index) => {
                     var toDoData = _toDoDatas[index];
                     return new Dismissible(
                         key: new ObjectKey(toDoData.Id.ToString()),
                         onDismissed: (direction) => {
                             if (direction == DismissDirection.endToStart)
                             {
                                 _toDoDatas.RemoveAt(index);
                             }
                         },
                         background: new Container(color: Colors.red),
                         child: new Card(
                             child: new ListTile(
                                 title: new Text(
                                     $"{_toDoDatas[index].Id:D4}:{_toDoDatas[index].Title}",
                                     style: new TextStyle(fontSize: 64)
                                 ),
                                 onTap: () => {
                                     setState(() => { _toDoDatas[index] = new ToDoData(toDoData.Id, "Done!"); });
                                 }
                             )
                         )
                     );
                 },
                 itemCount: _toDoDatas.Count
             )
         );
     }
 }

さわってみた所感

UIを記述する部分はほぼFlutterと同じで、Flutter経験者ならC#未経験でも書けそうだなと思いました。
そもそもDartC#の文法が結構似ているので、自分で書いていて、インスタンスの生成にnewをつけるかつけないかと、Listの書き方が若干違うくらいの差異しか感じなかったです。
Flutter経験者でUnityを触ってみたい人や、Unity経験者でFlutterの雰囲気を知りたい人の導入としては良さそうに思えました。
(ただがっつり勉強していくなら、このパッケージを使うよりはそれぞれの入門書などで勉強した方が良いと思います。)

あと気になった点として、動かしたときにデザインが崩れることがありました。
具体的には、FloatingActionButtonが小さく表示され、大きさを変えるとテキストのサイズが変わり、UIのバランスが変わってしまいました。
Flutterで書くのとまったく同じ書き方なのがまずかったのか、Unityでのシーンの設定がまずかったのかはわかりません。
ただFlutterの場合はプロジェクトを作成してすぐにコードを書いて開発していけますが、UIWidgetsでFlutterっぽいアプリを作る場合は、シーンの設定などしなければいけないので、その点はFlutterの知識だけではカバーできないようです。

35
16
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?