Dart で iOS/Android アプリをつくる

  • 25
    Like
  • 0
    Comment

この記事は WACUL Advent Calendar 2016 の13日目の記事です。

少し前に「GoogleのDartプログラミング言語に再びスポットライトが…その高い生産性にまず社内で人気が盛り上がる」という記事を読みまして Dart 生きとったんかワレとなったのですが、Advent Calendar のネタにするかということで触ってみました。
Dart は全く触ったこと無かったのですが、達人プログラマーにも

毎年少なくとも1つの言語を習得する

とありますし、ちょうどいいですねという感じです。(習得じゃなくてちょっと触ってみる程度だけど)

Dart でネイティブアプリを作るためのフレームワークとして、Flutter が上の記事では紹介されています。Flutter は単一の Dart コードで iOS/Android のクロスプラットフォーム開発を実現するために Google が開発しているオープンソースのフレームワークです。今回は Flutter を使ってごく簡単なアプリを作ってみたので、使った機能等をメモのような感じで紹介します。

環境構築

Flutter Setup にまとまってます。今回エディタは IntelliJ IDEA を使いました。

dartfmt

Dart には Go の gofmt のような dartfmt というコード整形ツールがあります。GitHub の dart-lang オーガナイザー以下にあるので一応公式っぽい?普段 Go を書いているのでこの類のツールは必須な身体になってます。

hot reload

Flutter にはクイックにコードの変更をアプリに反映させる hot reload が用意されています。大変便利。CLI でも使えるし、IntelliJ IDEA などではエディタから使えます。
下の gif 画像をみると、色を青から緑に変更したのがすぐに反映されていることが分かるかと思います。

hot-reload.gif

詳細はこちら

StatelessWidget と StatefulWidget

Flutter で用意されている Widget には StatelessWidget と StatefulWidget があります。その名の通り StatelessWidget は状態を持たないもの、StatefulWidget は状態を持ちその状態によって View を変更することができるものです。StatefulWidget は State というものをもつことができ、その State が ViewModel のような役割を果たします。State から状態の変更を View に伝えて再描画する場合は、setState() を使います。

以下は公式ドキュメントにのっているカウンタの例です。

class CounterDisplay extends StatelessWidget {
  CounterDisplay({this.count});
  final int count;
  @override
  Widget build(BuildContext context) {
    return new Text('Count: $count');
  }
}

class CounterIncrementor extends StatelessWidget {
  CounterIncrementor({this.onPressed});
  final VoidCallback onPressed;
  @override
  Widget build(BuildContext context) {
    return new RaisedButton(
      onPressed: onPressed,
      child: new Text('Increment'),
    );
  }
}

class Counter extends StatefulWidget {
  @override
  _CounterState createState() => new _CounterState();
}

class _CounterState extends State<Counter> {
  int _count = 0;

  void _increment() {
    // setState() を呼ぶことで view が再描画される
    setState(() {
      ++_count;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Row(children: <Widget>[
      new CounterIncrementor(onPressed: _increment),
      new CounterDisplay(count: _count),
    ]);
  }
}

setState.gif

Gesture

flutter ではタップやドラッグなどのユーザのアクションを、Gesture という名前でまとめて扱っています。これらのユーザのアクションを入力として受け取ってレスポンスを返したいような場合には GestureDegector を使います。

さきほどのカウンタにリセット機能をつけるには以下のようにします。

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  void _resetCounter() {
    setState(() {
      _counter = 0;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(config.title),
      ),
      body: new Center(
        // GestureDetector でラップする
        child: new GestureDetector(
          child: new Text(
            'Button tapped $_counter time${ _counter == 1 ? '' : 's' }.',
          ),
          // ダブルタップでカウンタをリセットする
          onDoubleTap: _resetCounter,
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: new Icon(Icons.add),
      ),
    );
  }
}

gesture.gif

Layout

Flutter には Row や Column, ScrollableList などよく使われるであろうレイアウトは用意されており、それらを利用することでプラットフォームの違いを意識せずレイアウトを組むことができます。Flexible などもあり単純なものならこれらを使うだけで済みそうです。
これらはドキュメントに簡単にまとまっています。

まとめ

今回ごく簡単な todo アプリを作ってみて(時間なくて最低限の機能も足りてないレベルだけど)、その時につかった機能などをメモのような形で紹介しました。
Flutter は "early-stage open-source project" とのことですが、導入も簡単で特につまずくことなく開発できたので趣味で触る分にはよさそう。Dart 自体はなんか Java っぽくて好みはわかれるかもなぁと思いました。Swift や Kotlin を使ってる人からすると Cool じゃないって思うかも(ネイティブアプリ事情はあまりわからないですが)
まだめちゃくちゃ単純なアプリを少しだけ書いてみただけなので、普段サーバーサイドのコードしか書いてないのもあり、もう少し触ってみようかなと思います :)

todos.gif