Write your first Flutter app #1

前提

公式のGet startedを翻訳しつつも段階的に解釈して進めて行きます。
初学者向けのチュートリアルではありますが、これが何かしらの手助けになれればと思っています。個人的な所感もありますが、色々な方からの知見も吸収出来たら幸いです。まずはFlutterというのは何だろうから初めていきます。

Flutterって何?

ja.wikipedia.org

Apache Cordova、ReactNative、Xamarinと同じようにクロスプラットフォーム開発を可能とするモバイルアプリケーションフレームワークです。言語についてはDartとなります。Dart2が発表されてからGoogleも本腰を入れて進めていると思います。一部では学ぶべき言語ではない、とも言われていますがaltJSの観点で言うと私は今後伸びて行くと思っています。紹介が終わった所で実際に動かして行きます。

目次

  • Get startedを流していく
  • Part1のテーマ
  • Step 1: Create the starter Flutter app
  • Step 2: Use an external package
  • Step 3: Add a Stateful widget
  • Step 4: Create an infinite scrolling ListView←こちらは次回

Part1はStep4までありますが、今回はStep3までを対象に実施していきます。

元ネタ

flutter.dev

Get startedを流していく

オブジェクト指向コードや、変数、ループ、条件付きなどの基本的なプログラミングの概念に慣れている場合は、このFlutterのチュートリアルを完了することが出来る。感覚的にはJavaなどがつがつとやって来た方はDartに対しての苦手意識はなくなるでしょう。

Part1のテーマ

公式では以下の内容が羅列されています。

  • iOSAndroidクロスプラットフォームにて不自然なく見えるアプリの書き方。
  • Flutterアプリの基本構造。
  • 機能拡張のためのパッケージ使用方法。
  • ホットリロードの使用方法。
  • stateful widgetを実装する方法。
  • Lazy Loadのリスト作成方法(ページの表示を速くするための遅延読み込み)。

Step 1: Create the starter Flutter app

ここではシンプルなテンプレートを使用してFlutterのアプリの作成を行っていきます。作成されたコードを一部抜粋し、何が起きているかフォーカスを絞ってみようと思います。
※プロジェクト作成部分は割愛します。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      )
    );
  }
}
StatelessWidget

ステートレス、という事から可変でなく状態を持たない固定のwidgetを指しています。StatefulWidgetというモノもあり、これは可変で状態を持つというwidgetを指します。(後ほど出てきます)FlutterではStatelessWidgetを拡張して、アプリ自体をwidgetとして扱います。
class [App名] extends StatelessWidgetとしているのが該当コード部分ですが、なぜStatelessWidgetの中にStatefulWidgetが存在したりしているのかというと、複数のclassを内包した画面は最終的には不変となるモノなのでStatelessという位置付けです。
BuildContextについてはアプリケーションが起動してから終了するまでのライフサイクル、つまり1つの画面を統括する役割です。 いずれ深掘りしますが、最初から全てを知ろうとすると進まない原因となるので、ここは先へ進みたいと思います。どの言語でもFWでもそうなのですが、使われているパッケージなどの参照は勉強になるので恐れず深淵に進んで行きましょう。
参考:StatelessWidget class - widgets library - Dart API

Widget

Flutterでは、アプリのパーツのほぼ全てがwidgetという概念。
widget = 画面を構成する部品(UI)という意味。
参考:Introduction to widgets - Flutter

build

下位レベルのwidgetに関して表示する方法を記述するbuild()メソッド(以下抜粋)を提供します。これはAndroidiPhoneでもcontextな考えがあるので普段からアプリ開発を行っている方はとっつきやすいですね。多くの場面で呼ばれているのでこちらも今後深堀りしていきます。
参考:build method - State class - widgets library - Dart API

MaterialApp

MaterialWidgetと呼ばれるwidgetはMaterialDesignの原則に従っているwidgetの実装を指します。基本的に用意されているwidgetを使用することも出来るし、混在させる事も出来る。もちろん独自のcustom widgetの作成も可能。私はデザインセンスが絶望的に無いのでここに乗っかって行きたいと思います。
参考:MaterialApp class - material library - Dart API

Scaffold

Scaffoldは単純な和訳で土台です。ここではMaterialDesign原則widgetを基本的な部品として使います。Railsを使った事がある方は聞き覚えのある言葉でしょうが、Flutterはモバイルアプリケーションフレームワークなのでコンセプトは少し違います。widgetの足場としてwidgetを積み上げていきます。
参考:Scaffold class - material library - Dart API

Step1はこれ終了です。ここまで消化出来ました。

  • iOSAndroidクロスプラットフォームにて不自然なく見えるアプリの書き方。
  • Flutterアプリの基本構造。
  • 機能拡張のためのパッケージ使用方法。
  • ホットリロードの使用方法。
  • stateful widgetを実装する方法。
  • Lazy Loadのリスト作成方法(ページの表示を速くするための遅延読み込み)。

ガンガン進んで行きましょう。

Step 2: Use an external package

ここではOSSパッケージのenglish_wordsを使用する方法の説明です。pubspec.yamldependencies部にenglish_words: ^3.1.0を追加します。

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.2
  english_words: ^3.1.0 # こちらを追加

追加後にAndroidStudioだとPackage getなどサジェストが出てくるのでこちらを実行しても良いです。これを実行した場合はflutter pub getを内部で行ってくれています。手動で行う場合は以下のコマンドを実行します。

$ flutter pub get

english_wordsはpubspec.lockにも自動生成されます。試しにpubspec.yamlから外して再度Package getなどするとここからpubspec.lockから除外されていることも確認出来ます。 パッケージの追加が終わったのでmain.dartに追加したパッケージを参照して使用していきます。

import 'package:flutter/material.dart';
// 以下を追加します
import 'package:english_words/english_words.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // importしたpackageを使う
    final wordPair = WordPair.random();
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          // ここではキャメルケースで試して見ます
          title: Text(wordPair.asCamelCase),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      )
    );
  }
}

アプリを実行します。アプリが実行中の場合は、実行中のアプリを更新するためにホットリロードが走ります。プロジェクトを保存してもホットリロードが行われます。

f:id:tanabebe:20190726131915g:plain

基本的なパッケージの使い方

ここは正直あまり掘り下げる必要がないと思っています。どの言語でもFWでも様々な外部パッケージやらライブラリは必要不可欠ですのであくまでランダムな単語構成を作るためにenglish_wordsを使用しているくらいの感覚です。
Step2はこれで終了です。ここまで消化出来ました。

  • iOSAndroidクロスプラットフォームにて不自然なく見えるアプリの書き方。
  • Flutterアプリの基本構造。
  • 機能拡張のためのパッケージ使用方法。
  • ホットリロードの使用方法。
  • stateful widgetを実装する方法。
  • Lazy Loadのリスト作成方法(ページの表示を速くするための遅延読み込み)。

Step3へ進みましょう。

Step 3: Add a Stateful widget

Stateful widgetは、widgetが変更される可能性がある状態を維持します。 実装するには、少なくとも2つのクラスが必要です。

  1. StatefulWidgetクラス
  2. Stateクラス

まず、StatefulWidgetクラス(RandomWordsState)を作成していきます。main.dartに追加します。

// StatefulWidgetクラス(RandomWordsState)
class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

// Stateクラス(RandomWordsState)
class RandomWordsState extends State<RandomWords> {
  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random();
    return Text(wordPair.asPascalCase);
  }
}
State

widgetを構築するbuild()を実行しているのでStateがwidgetの状態管理や構成を担ってくれています。ここはReactの良い部分をインスパイアしている感じが見受けられます。

StatefulWidget

Step3の冒頭で言っていた通り、StateクラスとStatefulWidgetクラスの2つで構成されています。StatefulWidgetはbuildメソッドを持たず、createStateメソッドを持ち、これがStateクラスを返します。

Stateful widgetの完成

MyAppクラスでwordPairを削除しRandomWordsを呼ぶように変更します。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
          child: RandomWords(),
        ),
      ),
    );
  }
}

これでアプリを実行するとStep2と同様の動作となりますね。

f:id:tanabebe:20190726142455g:plain

Step3はこれで終了です。 ここまで消化出来ましたね。

  • iOSAndroidクロスプラットフォームにて不自然なく見えるアプリの書き方。
  • Flutterアプリの基本構造。
  • 機能拡張のためのパッケージ使用方法。
  • ホットリロードの使用方法。
  • stateful widgetを実装する方法。

次でPart1ラストのStep4です、が!これは次回に持越したいと思います。

所感

元々DroidKaigi 2018で発表された際に気になってはいたのですが、実際にチュートリアルを少しやっているとツリー構造もイケてるし、野良パッケージも少なさそうです。最初のハードルとしては少し高いように感じますが、理解が追いついた時にかなりの生産性を発揮してくれるでしょう。実際、Native側の開発者からも「良さげ」という評価が高いです。少し懸念的な部分を持つとすればiOSでのUI部分はネックそうだなと…と言うのも冒頭で iOSAndroidクロスプラットフォームにて不自然なく見えるアプリの書き方とあるのですが正直な所、ここは言及されているようには思えなかったのが私の所感です。

次回

Part1のStep4を解説していきます。