Flutter入門 - ç°¡å˜ãªã‚¢ãƒ—リを䜜っおUI宣蚀やホットリロヌドなど䟿利機胜の䜿い方を理解しよう

モバむル向けアプリケヌションのフレヌムワヌク・Flutterを䜿っお簡単なアプリケヌションを䜜成する基本的な開発に぀いお、FlutterのGoogle Developers Expertである䞊田哲広さんに解説しおいただきたした。

Flutter入門 - ç°¡å˜ãªã‚¢ãƒ—リを䜜っおUI宣蚀やホットリロヌドなど䟿利機胜の䜿い方を理解しよう

こんにちは。䞊田哲広@najeiraです。FlutterのGoogle Developers Expertずしお掻動しおいたす。

Flutterは、Googleが䞭心ずなっおGitHub䞊でオヌプン゜ヌスなプロゞェクトずしお開発されおいる、モバむル向けアプリケヌションのフレヌムワヌクです。AndroidずiOSのアプリを単䞀のコヌドベヌスで開発できたす。

1 GitHub - flutter/flutter: Flutter makes it easy and fast to build beautiful mobile apps.
※Webやデスクトップぞのサポヌトも今埌のロヌドマップに含たれおいたす。

FlutterのアプリはDart蚀語を䜿っお蚘述したす。モダンでReactiveなUIフレヌムワヌクで、矎しいUI矀が豊富に含たれおいたす。FlutterではUIの各郚品のこずをWidgetず呌びたす。

特長ずしお、宣蚀的なUI定矩やホットリロヌドファむルの倉曎・保存をするずリロヌドするこずなくリアルタむムでファむルを読み蟌み盎す機胜による高い開発効率、リリヌス時のネむティブコヌドぞの事前コンパむル・GPUを掻甚したレンダリング゚ンゞンによる高い実行パフォヌマンスなどがありたす。

本蚘事ではFlutterを䜿った簡単なアプリケヌションを䜜成し、Flutterの基本的な開発を䜓隓・孊習するこずを目的ずしたす。

むンストヌル
Macに必芁なツヌルFlutterのむンストヌルflutter doctorAndroid StudioAVDのセットアップ
サンプル・アプリ
サンプル・アプリの起動サンプル・アプリの゜ヌスコヌド
ホットリロヌド
自動ホットリロヌドの蚭定ロゞックのホットリロヌド解説: setStateに぀いお
新たなアプリを䜜る
アプリを䜜る準備HTTP通信AndroidManifest.xmlJSONのパヌス画像を衚瀺する
リリヌスビルド
むンストヌルリリヌス

むンストヌル

たずはFlutterをむンストヌルしたしょう。Windows、Mac、Linux、ChromeOSで䜿甚できたす。

Flutterの公匏サむト右䞊にある「Get started」のボタンから、公匏ガむドでのむンストヌルの手順を参照できたす。公匏ガむドが詳现か぀最新情報ではありたすが、本蚘事でもMac環境でAndroid Studioを䜿う堎合のむンストヌル・セットアップの手順に぀いお解説したす。他のOSやIDE/゚ディタに぀いおは公匏ガむドを参照しおください。

2

Macに必芁なツヌル

Flutterは以䞋のコマンドラむンツヌルを利甚したす。

  • bash
  • curl
  • git 2.x
  • mkdir
  • rm
  • unzip
  • which
    ※これらはMacの環境に暙準で入っおいたす。足りないものがあれば別途むンストヌルしおください。

Flutterのむンストヌル

macOS甚ダりンロヌドペヌゞ の「flutter_macos_v1.7.8+hotfix.3-stable.zip」のボタンから、zipファむルをダりンロヌドしおくださいバヌゞョンの衚蚘は本蚘事の執筆時点のものです。

3 MacOS install - Flutter

ダりンロヌドしたzipファむルを、むンストヌルしたい堎所に展開したす。以降、操䜜はタヌミナルで行うものずしお、コマンド䟋を瀺したす。 ~/development にむンストヌルしたい堎合は以䞋のようになりたす。

mkdir ~/development
cd ~/development
unzip ~/Downloads/flutter_macos_v1.7.8+hotfix.3-stable.zip

~/development/flutter ずいうディレクトリが䜜成され、その䞋にFlutterのファむルが展開されたす。

Flutterのコマンドを簡単に利甚できるようにするために、環境倉数 PATH にFlutterむンストヌル先を蚭定しおおきたしょう。

~/.bash_profile に以䞋の行を远加したす。 [YOUR_NAME] はご自身のナヌザヌ名に眮き換えおください。たた、むンストヌル先を別の堎所にした堎合も、適宜パスを眮き換えおください。

export PATH="$PATH:/Users/[YOUR_NAME]/development/flutter/bin"

sourceコマンドで、珟圚のセッションにも反映させたす。

source ~/.bash_profile

flutter doctor

Flutterには環境をチェックする doctor ずいうコマンドがありたす。このコマンドを実行するこずで、Flutterが必芁ずするDart SDKなどがダりンロヌド・セットアップされたす。以䞋のように実行しおください。

flutter doctor

※flutterコマンドが芋぀からない堎合は、前章での flutter/bin にパスを通す蚭定を芋盎しおください。

以䞋のように関連するツヌルの状況が衚瀺され、環境が敎っおいる項目は「 ✓ 」で衚瀺されたす。ない箇所に぀いおは「 ! 」ず衚瀺されたす。ここでは少なくずも先頭のFlutterの欄が「 ✓ 」ずなっおいればOKです。

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.7.8+hotfix.3, on Mac OS X 10.14.4 18E226, locale ja-JP)

[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 10.2)
[✓] iOS tools - develop for iOS devices
[✓] Android Studio (version 3.3)
[✓] IntelliJ IDEA Ultimate Edition (version 2018.1)
[✓] VS Code (version 1.35.1)
[✓] Connected device (2 available)

この埌のAndroid Studioをセットアップ埌には、䞊蚘の欄のうちAndroid toolchain、Android Studioの欄が「 ✓」ずなり、開発が進められるようになりたす。なお、iOSでFlutterアプリを開発したい堎合は、別途Xcodeのむンストヌルが必芁です。

Android Studio

FlutterにはAndroid Studio、IntelliJ IDEA、Visual Studio Code向けの公匏な開発プラグむンがありたす。たた、プラグむンを利甚せずずも、Flutterのコマンドラむンツヌルも䜿えるため、お奜きな゚ディタでFlutterでアプリ開発ができたす。

本蚘事ではAndroid Studioを䜿う堎合の手順を玹介したす。

Android Studioのむンストヌル

たず、Android Studioの公匏サむトから、Android Studioをダりンロヌドしたす。

4 Download Android Studio and SDK tools

Android Studioを起動し、Android Studio Setup Wizardを進めたす。これによりAndroid SDK、Android SDK Platform-Tools、Android SDK Build-Toolsずいった、Flutterに必芁な各ツヌルがむンストヌルされたす。

本蚘事でぱミュレヌタを䜿っお開発しおいきたすが、実機デバむスを䜿った開発においおも基本的な手順に違いはありたせん。

※Android Studioをすでにむンストヌル枈みの堎合は、バヌゞョンが3.1以䞊であるこずを確認しおください。
※本蚘事の執筆時点でのAndroid Studioの最新バヌゞョンは3.4.2ですが、画面のスクリヌンショットなどは3.3で撮圱しおいたす。

Flutterプラグむンのむンストヌル

Android Studio向けのFlutterプラグむンをむンストヌルしお䜿いたす。Android StudioのPreferencesからPluginsを遞択し、画面䞋郚のBrowse repositoriesを遞んでください。

「flutter」で画面内を怜玢しお衚瀺される「Flutter」を遞び、Installボタンでむンストヌルしたす。

5

むンストヌル埌、Android Studioを再起動しおください。再起動埌、Android Studioの開始画面に「Start a new Flutter project」のメニュヌが衚瀺されるようになるので、それを遞択したす。

6

New Flutter Projectの画面では「Flutter Application」を遞び「Next」ぞ進みたす。

7

Project nameにはお奜きな名前を入れおください。Flutter SDK pathには、むンストヌルしたFlutterのパスが入っおいたす。Project locationには、このアプリを䜜成する堎所を入力したす。

8

Company domainは、アプリのリリヌス時にAndroidアプリのパッケヌゞ名iOSの堎合はバンドルIDずしお䜿われたす。本蚘事はチュヌトリアルのため、 example.com のたた進めおいきたす。

9

さお、アプリの雛圢が䜜成されるず、Android Studioの゚ディタが起動しお以䞋のような状態ずなりたす。

10

AVDのセットアップ

アプリをAndroid゚ミュレヌタで実行するためには、AVDAndroid Virtual Deviceの蚭定が必芁です。

11 Create and manage virtual devices  |  Android Developers

Android StudioのToolsから「AVD Manager」を遞択し、AVDの䞀芧画面が衚瀺されたら、巊䞋の「Create Virtual Device」を遞びたす。次の画面では任意のHardwareを遞んで「Next」ぞ進みたす。

12

次に、System imageを遞びたす。Recommendedのタブに衚瀺されおいる䞭から遞べばOKです。珟行のMacのCPUはIntelを採甚しおおり、ABIApplication Binary Interfaceがx86かx86_64のものでも問題なく高速に動䜜するでしょう。本皿でも、x86かx86_64を掚奚したす。ダりンロヌドが必芁なものには「Download」のリンクが衚瀺されおいるので、必芁に応じおダりンロヌドしおください。

13

Emulated Performanceの項目で「Hardware - GLES 2.0」を遞択しおください。

14

䜜成が完了したら、画面右の再生ボタンで゚ミュレヌタを起動したす。

15

ここたで来たら、FlutterアプリをAndroid゚ミュレヌタで実行する準備は完了です。

サンプル・アプリ

サンプル・アプリの起動

Android Studioの「Start a new Flutter project」によっおFlutterのサンプル・アプリが雛圢ずしお䜜成されおいるため、たずはそのアプリを起動しおみたしょう。

Android Studioの䞊郚にFlutterプラグむンのツヌルバヌがありたす。「Android SDK build for x86」ず衚瀺されおいるのが、Android゚ミュレヌタです。他に実機デバむスの接続があれば、プルダりンから遞択できたす。アプリを実行したい環境を遞んでください。

「main.dart」ずあるのがアプリの゚ントリポむントです。この時点では他にファむルがないため、そのたたでOKです。その右にある再生ボタンを抌しおアプリを起動したしょう。

16

※Androidの実機デバむスで開発したい堎合は、端末の開発者オプションの「USBデバッグ」を有効にしおください。たた、WindowsでAndroidデバむスを䜿う堎合は、USBドラむバが必芁です。詳しくはナヌザヌガむドの「Google USB ドラむバを入手する」を参照しおください。

起動するず以䞋のようになりたす。なお、サンプル・アプリの初回起動時はAndroidアプリの通垞のコンパむルが行われるため、数十秒から数分、時間がかかるこずがありたす。

17

画面巊に配眮されおいるサンプル・アプリ画面の右䞋の「」ボタンを抌すず、アプリ画面䞭倮に衚瀺されおいる数字がカりントアップしたす。

サンプル・アプリの゜ヌスコヌド

サンプルずしお䜜成されたこのアプリは、以䞋のコヌドになっおいたすコメント郚分を陀く。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

わずか60行ほどのコヌドで、アプリケヌションずしお動䜜するものが出来䞊がっおいたす。

本蚘事ではFlutterフレヌムワヌクの詳现に぀いおは觊れたせんが、このコヌドに登堎する芁玠に぀いお、簡単に述べおおきたす:

  • main 関数から凊理が開始され、 runApp にWidgetを枡すこずでアプリが衚瀺される
  • MyApp は StatelessWidget を継承しおおり、 Widget である
  • MyHomePage は StatefulWidget を継承しおおり、状態があるこずを意味する _MyHomePageState がその状態
  • Widget や State の build メ゜ッドの戻り倀が、画面に衚瀺されるUIずなる
  • MaterialApp はマテリアルデザむンのアプリを䜜るために䟿利なWidget
  • Scaffold は兞型的な画面レむアりトを構築する䟿利なWidget

ホットリロヌド

では、Flutterの特長のひず぀である、ホットリロヌドを詊しおみたしょう。

アプリは起動したたた、コヌド内の文字列

'You have pushed the button this many times:'

の䞭身を、

'ボタンをこの回数も抌したした'

に倉曎しおください。

ファむルの倉曎を保存するず、アプリ内の文字列も即座に倉曎されたす。

18

これは、Flutterプラグむンでファむル保存する際の自動ホットリロヌドが、デフォルトで有効になっおいるためです。

自動ホットリロヌドの蚭定

Android StudioのPreferenceから「Languages & Frameworks」 > 「Flutter」を遞ぶず、Flutterに関するオプションを倉曎できたす。自動ホットリロヌドをオフにしたい堎合は「Perform hot reload on save」のチェックを倖したす。

19

自動ホットリロヌドがオフの状態でホットリロヌドする堎合は、ツヌルバヌにある皲劻の圢のボタンを抌したす。

ロゞックのホットリロヌド

ホットリロヌドできるのは文字列ずいった定数だけではありたせん。ボタンを抌したずきの凊理を行っおいる _incrementCounter メ゜ッドの䞭身を「2ず぀足しおいく」ように曞き換えおみたしょう。コヌドは以䞋の通りです。

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

ホットリロヌドしお、「」ボタンを抌しおみおください。数字が2ず぀増えるようになりたした。

解説: setStateに぀いお

_counter の曎新は、setState ずいうメ゜ッドに枡した無名関数内で代入状態の倉曎を行っおいたす。

この setState メ゜ッドの呌び出しによっお、Flutterフレヌムワヌクに察しお「状態が倉わった」こずが䌝わりたす。Flutterフレヌムワヌクは、このあずで build メ゜ッドを呌び出すこずで画面を最新の状態に曎新したす。

新たなアプリを䜜る

サンプル・アプリはここたでにしお、より実践的なアプリを䜜りたしょう。

䞖の䞭の倚くのアプリにある「HTTP通信を行う」「リストビュヌによっお倚数の項目を衚瀺する」ずいった機胜を実装したす。本蚘事ではGitHubのFlutterリポゞトリにあるIssuesを䞀芧衚瀺するアプリを䜜っおいきたす。

アプリを䜜る準備

たずは MyApp クラスの title の文字列を Flutter Issues に倉曎し、 _MyHomePageState クラスの build メ゜ッド内を以䞋のように空っぜに近い状態にしお、新たなアプリに備えたす。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Issues',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Issues'),
    );
  }
}
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Text('空っぜの画面です'),
    );
  }
}
スクリヌンショット
20
pubspec.yaml

Flutterでは、倖郚パッケヌゞなどの䟝存関係やアプリの蚭定はpubspec.yamlずいうファむルに蚘述したす。ファむルは雛圢ずずもに䜜成されおいたす。

21

アプリの雛圢を䜜成した時点では、pubspec.yamlは以䞋のようになっおいたすコメント郚分は陀く。

name: flutter_app
description: A new Flutter application.

version: 1.0.0+1

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.2

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true
dependencies

このファむルの dependencies の項目に、 http を远加したす。

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.2
  http: any
packages get

httpパッケヌゞの蚘述を远加した埌は、゚ディタ画面䞊郚に衚瀺されるFlutter commandsの「Packages get」を遞んで実行しおください。これにより、pubspec.yamlに蚘茉された倖郚パッケヌゞなどが取埗され、䜿えるようになりたす。

22

゚ディタ䞋郚のコン゜ヌルに以䞋のように衚瀺されれば凊理は成功です。

23

Tips: pub

FlutterやDartの各皮パッケヌゞは、「Dart packages」で探せたす。

Dart packages

import

コヌドでhttpパッケヌゞを利甚するためには import が必芁です。以䞋のようにimport文を远加しおください。

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

as http ずあるのは、 import したパッケヌゞ内の名前にプレフィックスを぀けお利甚するためです。httpパッケヌゞにはgetやpostずいった単玔な名前があり、他の識別子ずの衝突を避けたい堎合などにこの機胜を䜿いたす。

HTTP通信

HTTP通信によっお、倖郚からデヌタを読み蟌んでみたす。

FlutterリポゞトリのIssuesの䞀芧を取埗するAPIの゚ンドポむントにアクセスしお、デヌタを取埗したす。このURLをブラりザで衚瀺するずAPIの䞭身を確認できたす。

゜ヌスコヌド

_MyHomePageState を以䞋のようにしたす。倉曎埌、Flutterツヌルバヌの再生ボタンを抌しおホットリスタヌトを行っおください。ホットリロヌドでは衚瀺が曎新されたせん。

class _MyHomePageState extends State<MyHomePage> {
  String _data = '';

  @override
  void initState() {
    super.initState();
    _load();
  }

  Future<void> _load() async {
    final res = await http.get('https://api.github.com/repositories/31792824/issues');
    setState(() {
      _data = res.body;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Text(_data),
    );
  }
}
スクリヌンショット

ホットリスタヌト埌、以䞋のように、GitHubのAPIから取埗したFlutterリポゞトリのIssues APIの䞭身が、そのたた文字列ずしお衚瀺されたす。

25
ホットリスタヌト

Flutterのホットリロヌドを行うず、 build メ゜ッドが呌び出されお画面が曎新されたす。今回のコヌドの倉曎では新たにhttpパッケヌゞを远加し、さらに initState メ゜ッドで初期化凊理を行うようにしたしたが、衚瀺されおいるWidgetStateの initState はホットリロヌドでは再呌び出しされたせん。そのため、ホットリスタヌトでアプリを最初から実行させるこずで initState ずそこから呌び出される _load メ゜ッドを実行させ、HTTP通信の結果を画面に衚瀺するようにしたした。

Flutterアプリを開発䞭に、意図した通りに曎新が行われなかった堎合は、この initState が再呌び出しされなかったこずが原因の可胜性がありたす。その際はホットリスタヌトを詊しおみおください。

解説

ここでの倉曎のポむントは以䞋の通りです。

class _MyHomePageState extends State<MyHomePage> {
  String _data = '';
  • 取埗したデヌタを保持するむンスタンス倉数 _data を远加したす。
  @override
  void initState() {
    super.initState();
    _load();
  }
  • initState メ゜ッドを override したす 。initState は、このオブゞェクトが画面Widget treeに远加された時に呌び出され、初期化凊理などを蚘述できたす。ここでは別途実装した _load メ゜ッドを呌び出しお、HTTP通信を開始させおいたす。
  Future<void> _load() async {
    final res = await http.get('https://api.github.com/repositories/31792824/issues');
    setState(() {
      _data = res.body;
    });
  }
  • _load メ゜ッドは async キヌワヌドにより、非同期メ゜ッドになっおいたす。 http.get httpパッケヌゞのget関数は非同期でHTTP通信を行い Future を返したす。その結果を await で埅ち受けおいたす。
  • 戻り倀を受け取る倉数 res は final で宣蚀しおおり、これ以降は再代入できたせん。たた型名の宣蚀は省略しおいたすDartが掚論で型を解決しおいたす。
  • HTTP通信のレスポンスの䞭身 res.body をむンスタンス倉数 _data に代入しおいたす。 setState によっお状態が倉わったこずをFlutterに䌝えたす。
  • bodyのText widgetはむンスタンス倉数 _data の䞭身を衚瀺したす。

なお、async/awaitを䜿わずに _load メ゜ッドを蚘述するず以䞋のようになりたす。 http.get が返すFutureオブゞェクトに察しお then メ゜ッドでコヌルバック関数を枡したす。凊理が完了するずそのコヌルバック関数が呌び出されたす。この方法はasync/awaitがサポヌトされる以前の方法であり、珟時点ではasync/awaitを䜿う方法が掚奚されおいたす。

  void _load() {
    http.get('https://api.github.com/repositories/31792824/issues').then((http.Response res) {
      setState(() {
        _data = res.body;
      });
    });
  }
Tips: _で始たる名前

Dartでは、 _ で始たる識別子は、他のファむルからアクセスするこずができたせん。このため、倖郚に公開する必芁のない倉数やメ゜ッドを _ から始たる名前にしおいたす。

AndroidManifest.xml

ここで、Androidのパヌミッションの蚭定をしおおきたしょう。

26

デバッグビルドではパヌミッションによる゚ラヌは発生したせんが、リリヌスビルドした時に暩限がないずHTTP通信が倱敗したす。 android/app/src/main/AndroidManifest.xml に、以䞋のように uses-permission を远蚘しおください。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.flutter_app">

    <uses-permission android:name="android.permission.INTERNET" />

JSONのパヌス

GitHubのAPIはJSON圢匏です。Dartには暙準パッケヌゞでJSONの凊理を行う関数が甚意されおおり、これを利甚しおパヌスを行いたす。

import

Dartの convert パッケヌゞを import しおください。

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

これで、以䞋のように䜿うこずができたす。

final data = json.decode(res.body);
゜ヌスコヌド

GitHub Issuesのタむトルを List で扱い、リスト圢匏で衚瀺するよう _MyHomePageState を曎新したす。今回も initState で呌び出される凊理が倉わっおいるので、ホットリスタヌトで曎新しおください。

class _MyHomePageState extends State<MyHomePage> {
  List<String> _titles = <String>[];

  @override
  void initState() {
    super.initState();
    _load();
  }

  Future<void> _load() async {
    final res = await http.get('https://api.github.com/repositories/31792824/issues');
    final data = json.decode(res.body);
    setState(() {
      final issues = data as List;
      issues.forEach((dynamic element) {
        final issue = element as Map;
        _titles.add(issue['title'] as String);
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView.builder(
        itemBuilder: (BuildContext context, int index) {
          if (index >= _titles.length) {
            return null;
          }

          return ListTile(
            title: Text(_titles[index]),
          );
        },
      ),
    );
  }
}
スクリヌンショット

衚瀺されたリストをスクロヌルしおみおください。スクロヌルや端に到達した際など、ネむティブアプリず倉わらない挙動になっおいるこずが分かるず思いたす。

27

なお、iOSで実行した堎合は端でバりンスし、Androidは終端の゚フェクトが衚瀺されたす。これはFlutterの内郚で、スクロヌルの挙動がOSに応じたものになるように実装しおいるためです。

解説
class _MyHomePageState extends State<MyHomePage> {
  List<String> _titles = <String>[];
  • むンスタンス倉数を List<String> に倉曎し、耇数のIssuesのタむトルを扱えるようにしおいたす。
  Future<void> _load() async {
    final res = await http.get('https://api.github.com/repositories/31792824/issues');
    final data = json.decode(res.body);
    setState(() {
      final issues = data as List;
      issues.forEach((dynamic element) {
        final issue = element as Map;
        _titles.add(issue['title'] as String);
      });
    });
  }
  • json.decode した結果からIssuesのタむトルを取り出しおいたす。API党䜓は List 、各芁玠は Map 、その䞭の title がタむトルです。json.decodeの戻り倀は型が dynamic ず定たっおいないJSONの圢匏は䞍定なためので、 as キヌワヌドによっお List や Map にキャストしおいたす。
  body: ListView.builder(
    itemBuilder: (BuildContext context, int index) {
      if (index >= _titles.length) {
        return null;
      }

      return ListTile(
        title: Text(_titles[index]),
      );
    },
  ),
  • リストの衚瀺には ListView ずいうWidgetを䜿いたす。 ListView.builder は、 ListView のクラスの名前付きコンストラクタです。
  • itemBuilder にリストの各芁玠をビルドするための関数を枡しおいたす。 ListView クラスが芁玠の䜍眮を index ずしお枡し、呌び出しおくるので、その䜍眮に応じたWidgetを返したす。 null を返すずリストは終端ずなるので、 _titles の件数を超えたずころで null を返しおいたす。
  • ListTile は、兞型的なリスト芁玠のレむアりトを実珟しおくれるWidgetです。その title にText widgetを蚭定しおいたす。 ListTile だけでなく、任意のWidgetを芁玠に䜿うこずもできたす。

画像を衚瀺する

タむトルだけでは寂しいので、Issueを登録した人のアバタヌ画像も䞀緒に衚瀺したしょう。

゜ヌスコヌド

GitHub Issuesのタむトルずナヌザヌのアバタヌ画像を List で扱えるよう、 _MyHomePageState を曎新したす。今回も initState で呌び出される凊理が倉わっおいるので、ホットリスタヌトで曎新しおください。

class Issue {
  Issue({
    this.title,
    this.avatarUrl,
  });

  final String title;
  final String avatarUrl;
}

class _MyHomePageState extends State<MyHomePage> {
  List<Issue> _issues = <Issue>[];

  @override
  void initState() {
    super.initState();
    _load();
  }

  Future<void> _load() async {
    final res = await http.get('https://api.github.com/repositories/31792824/issues');
    final data = json.decode(res.body);
    setState(() {
      final issues = data as List;
      issues.forEach((dynamic element) {
        final issue = element as Map;
        _issues.add(Issue(
          title: issue['title'] as String,
          avatarUrl: issue['user']['avatar_url'] as String,
        ));
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView.builder(
        itemBuilder: (BuildContext context, int index) {
          if (index >= _issues.length) {
            return null;
          }

          final issue = _issues[index];
          return ListTile(
            leading: ClipOval(
              child: Image.network(issue.avatarUrl),
            ),
            title: Text(issue.title),
          );
        },
      ),
    );
  }
}
スクリヌンショット
28
解説
class Issue {
  Issue({
    this.title,
    this.avatarUrl,
  });

  final String title;
  final String avatarUrl;
}
  • Issueごずのデヌタを衚す Issue クラスを定矩したした。
class _MyHomePageState extends State<MyHomePage> {
  List<Issue> _issues = <Issue>[];
  • むンスタンス倉数を List<Issue> に倉曎しお、Issue オブゞェクトのリストずしおいたす。
  Future<void> _load() async {
    final res = await http.get('https://api.github.com/repositories/31792824/issues');
    final data = json.decode(res.body);
    setState(() {
      final issues = data as List;
      issues.forEach((dynamic element) {
        final issue = element as Map;
        _issues.add(Issue(
          title: issue['title'] as String,
          avatarUrl: issue['user']['avatar_url'] as String,
        ));
      });
    });
  }
  • APIレスポンスをパヌスした結果リストの各芁玠を、 Issue クラスのオブゞェクトを生成しおから _issues に add しおいたす。
  body: ListView.builder(
    itemBuilder: (BuildContext context, int index) {
      if (index >= _issues.length) {
        return null;
      }

      final issue = _issues[index];
      return ListTile(
        leading: ClipOval(
          child: Image.network(issue.avatarUrl),
        ),
        title: Text(issue.title),
      );
    },
  ),
  • ListTile の leading にナヌザヌのアバタヌ画像を远加したした。
  • Image.network で、ネットワヌク䞊の画像を衚瀺するImage widgetのオブゞェクトを生成しおいたす。
  • ClipOval は child を円圢にクリップしお衚瀺するwidgetで、これにより画像を䞞く切り取っお衚瀺しおいたす。

リリヌスビルド

さお、本蚘事でのアプリはこれで完成です。

むンストヌル

実機のAndroidデバむスをお持ちの方は、リリヌスビルドした.apkファむルを、実機にむンストヌルしおみたしょう。 flutter install ずいうコマンドが甚意されおいたす。

たずは、実機デバむスをUSBケヌブルでマシンに接続し、 flutter devices コマンドを䜿っおみたす。

flutter devices

以䞋のように接続されたデバむスが衚瀺されたす。以䞋の䟋であれば実機のデバむスIDは「LPF0000000000000」です。

HW 01K                    • LPF0000000000000 • android-arm64  • Android 8.1.0 (API 27)
Android SDK built for x86 • emulator-5554    • android-x86    • Android 8.1.0 (API 27) (emulator)
macOS                     • macOS            • darwin-x64     • Mac OS X 10.14.4 18E226
web                       • web              • web-javascript • Google Chrome 75.0.3770.142

このデバむスIDを install コマンドで以䞋のように指定したす。デバむスIDは、ご自身のものに眮き換えおください。

flutter install -d LPF0000000000000
Initializing gradle...                                              5.7s
Resolving dependencies...                                           2.1s
Installing app.apk to HW 01K...
Installing build/app/outputs/apk/app.apk...                         2.6s

実機にflutter_appずいうアプリがむンストヌルされおいるはずです。

リリヌスビルドでは、開発䞭に衚瀺されおいた画面右䞊の「DEBUG」の垯がなくなっおいたす。たた、動䜜もより軜快になっおいるこずが確認できるず思いたす。

リリヌス

リリヌスビルドしたものをGoogle Play Storeに公開するのであれば、眲名などの準備が必芁です。詳现は以䞋を参照しおください。

たずめ

AndroidずiOSのアプリを単䞀のコヌドベヌスで開発できるFlutterに぀いお、実際のアプリを䟋にたずめたした。この蚘事がFlutterを理解するためのガむドになればず思いたす。

Flutter関連リンク

䞊田哲広うえだ・お぀ひろ 31 najeira 32 najeira

33
マむケル株匏䌚瀟CTO。携垯電話゜フトりェアの研究開発に携わったのち、2007幎頃からは䞻にWebサヌビスを開発しはじめる。2013幎に動画アプリ「MixChannel」を立ち䞊げ、開発党般を担圓。2017幎、マむケル株匏䌚瀟に参画しCTOに就任、車奜きのコミュニティ「CARTUNE」を開発。

2012幎からGoogle App EngineのGoogle Developer Expertずしお、2017幎からはFlutterも加えお掻動䞭。
若手ハむキャリアのスカりト転職