【Flutter】初めてのクロスプラットフォームアプリ開発! iOS・Androidアプリ開発入門

初めてのFlutterアプリ開発
この記事が向いてる人
  • 既にFlutterの環境構築が済んでいる
  • まだFlutterでアプリ開発をしたことがない
  • とりあえず簡単なアプリをFlutterで開発したい
  • Widgetの使い方が分からない

\ Flutterの環境構築がまだの方はこちら /

今回はFlutterを導入したばかりで「Widget」がそもそも分からないような方のために、1からFlutterでアプリ開発をする方法を紹介していきます。(開発環境MacOS, Android Studio)

↓のようなアプリをこの記事を通して開発します。

初めてのFlutterアプリ開発「ランダムさいころ」

また、当記事では各パートの解説を簡潔にし、代わりに解説の詳細リンクを各パートで紹介しています。(当記事の解説で分からなかった場合は詳細リンクをご覧ください。)

この記事を読み終える頃には、Widgetの基本的な使い方、簡単なアプリを開発する流れが理解できるようになるはずです。

スポンサーリンク

Flutterでアプリ開発を始める前に知っておくこと

widget
Widgetを理解する
  • Widgetとは、FlutterアプリのUIを構築しているパーツ
  • FlutterのUIはWidgetがツリー状(Widgetツリー)に組み合わさって構築されている
  • Widgetはクラスをインスタンス化したオブジェクト

Flutterでアプリ開発をする上で、まず初めに知っておきたいのが「Widget」です。Widgetとは、FlutterアプリのUIを構築するパーツのようなもので、FlutterアプリはこのWidgetがツリー状(Widgetツリー)に組み合わさって構築されています。また、Widgetツリーの根元となるWidgetを「root」と呼びます。

FlutterではDart言語が使用されていて、Widgetはクラスをインスタンス化したオブジェクトなのでクラス同様プロパティ、メソッド、コンストラクタを持ちます。よって、Dartでクラスの使い方をマスターすればWidgetを自由に扱えるようになります。

Flutterアプリを開発するなら、先にDartの基本を理解しておくことをお勧めします。

Flutterアプリ開発の下準備

手順
  • Flutterの新規プロジェクトの作成
  • iOS Simulator(MacOSだけ)、Android Emulatorを起動させる

この記事でのFlutterの開発環境はMacOS、IDEはAndroid Studioです。仮に使用しているパソコンがWindows、またはIDEがVisual Studioだったとしても重要なポイントは同じなので安心してください。

Flutterの新規プロジェクトの作成

Android StudioでのFlutterの新規プロジェクトの作成方法はこちらの詳細リンクの「Android StudioでFlutterの新規プロジェクトを作成」で確認できます。今回は「iOS」「Android」向けのアプリを作っていきます。

iOS Simulator/Android Emulatorを起動させる

Android-Emulator

Flutterのプロジェクトを作成したら、Flutterアプリのプログラムを開発中にテストできるよう「iOS Simulator」「Android Emulator」など、アプリ開発をするデバイスのSimulator、Emulatorを起動させます。(WindowsではAndroid StudioでiOS向けのFlutterアプリの開発が可能ですが、iOS Simulatorを使用できません)

また、Mac M1でFlutterのアプリ開発をしている方はAndroid StudioでAndroid Emulatorを使用できないので対処が必要です。こちらの詳細リンクから確認できます。

スポンサーリンク

Flutterアプリ「ランダムさいころ」を開発する

手順
  • material libraryをインポートする
  • main関数のrunApp関数でFlutterアプリのrootとなるWidgetを指定
  • Flutterアプリのメインプログラムを作る

今回開発するアプリは、ボタンを押すとランダムなさいころの目が表示される「ランダムさいころ」です。とてもシンプルなアプリですが、Stateful Widgetの使い方、Dart libraryのインポートの仕方などFlutter初心者の方にとって学びが多いアプリなはずです。

また、本当に1からFlutterアプリ開発の仕方を解説していくので、Flutterのプロジェクトを新規作成したら、デフォルトで書かれている全てのコードを消去してください。

それでは、Flutterアプリを実際に開発していきましょう!

material libraryをインポートする

FlutterアプリのUIはWidgetで構築されており、Widgetを使用するにパッケージをインストールする必要があります。

FlutterのコアとなるWidgetのパッケージには、Googleのデザインが使用できる「material library」とAppleの「cupertino library」があります。また、他にも様々なパッケージがありインポートすることで使用できます。

Flutterアプリ開発には「material library」のWidgetが必須なので、Flutterでは新規プロジェクトが作成される際、「material library」がデフォルトでインポートされています。一度消去してしまいましたが、改めて「material library」をインポートします。

//material libraryのインポートコード
import 'package:flutter/material.dart';

main関数とrunApp関数

初めてのFlutterアプリ開発2

material libraryをインポートしたことで、WidgetをFlutterで使用できるようになりました。ただ、このままではプログラムが実行できないので、main関数で実行したいプログラム(Widget)をrunApp関数で指定する必要があります。

import 'package:flutter/material.dart';

void main(){
  runApp(Widgetツリーの「root」となるWidgetを指定);
}

main関数とは、Dartのプログラムを実行した際、最初に呼び出される関数で、全てのプログラムはこのmain関数を通して実行されます。また、runApp関数の引数にWidgetツリーの「root」となるWidgetを代入することで指定したWidgetを実行できます。

Widgetは「StatelessWidget」または「StatefulWidget」を用いて自分で作れるので、FlutterアプリのメインとなるWidgetを自分で作り、runApp関数の引数に自分で作ったWidgetを代入してFlutterアプリを開発していきます。

今回は「MyApp」という名の「StatefulWidget」を作り、runApp関数に代入します。(動画を参照)

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp()); //runApp関数に自分で作った「MyApp」を代入
}

//Widgetを自分で作る
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

それでは、StatefulWidgetの「MyApp」でFlutterアプリのメインとなるプログラムを作っていきましょう。

スポンサーリンク

Flutterアプリのメインプログラムを作る

今回使用するWidget
  • Scaffold
  • AppBar
  • Column
  • TextButton
  • Text
  • Expanded
  • Container
  • Image
今回使用するDart library
  • dart:math library

今回のアプリ開発で使用するWidgetとDart libraryをまとめたのでチェックしておいてください。また、先に完成したコードを知りたい方はこの記事の最後から確認できます。

MaterialAppで「material library」のWidgetを使用可能にする

material libraryのWidgetを使うためには、パッケージのインポート以外にも、MaterialAppをインスタンス化しておく必要があります。

MaterialApp(
  home: MyWidget(),
)

このコードのようにMaterialAppをインスタンス化し、homeプロパティの引数にWidgetツリーのrootとなるWidgetを代入します。

Scaffold:appBarとbodyを作る

Scaffoldを使って上のようなFlutterアプリの基盤となるレイアウトを作ることができます。今回、Scaffoldで使うプロパティは「appBar」と「body」でそれぞれ「トップバー」と「アプリのメインコンテンツ」を作るために使用します。

また、appBarの引数には「AppBar」、bodyの引数に今回は「Column」を使用します。Columnを使うことでアプリのy軸方向に複数のWidgetを配列できます。

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp( 
      home: Scaffold(
        appBar: AppBar(
          title: Text('ランダムさいころ'),
        ),
        body: Column(
          children: [],
        ),
      ),
    );
  }
}

これで「トップバー」と「メインコンテンツ」となる「Column」を指定できました。

Column & Expanded:bodyのレイアウト設定

Columnのy軸における「ダイスの画面」と「ボタン」のサイズの比率を上の画面のように2対1にするためにExpanded Widgetを使用します。ExpandedはCoulmnやRowのように複数のWidgetをレイアウトするWidgetと共に使われます。

//完成したコードからbodyのコードを抽出
body: Column(
  children: [
    Expanded(
      flex: 2,
      child: Container(),
    ),
    Expanded(
      flex: 1,
      child: Container(),
    ),
  ],
),

Expandedのflexプロパティを使うことで、Expandedのchildプロパティで指定したWidgetをColumnのy軸に対してサイズの比率を指定できます。また、ExpandedのchildにContainerを指定しておきます。

これでColumnにおけるchildrenのレイアウトができました。

Image:画像を保存・表示させる

初めてのFlutterアプリ開発3

ランダムさいころアプリで使う、1から6のダイスの目の画像を保存するフォルダを上の動画のように作り、画像をフォルダに保存します。今回はフォルダ名を「images」とします。

画像の名前はこの記事と同じように「dice1」~「dice6」にしておいて下さい。また、画像は「Canva」を使うと簡単に作れます。無料版でも機能が充実しているのでぜひ使ってみて下さい。

imagesフォルダの画像を使用するには、pubspec.yamlファイルを更新する必要があります。詳細はこちらで動画を使って紹介しています。

pubspec.yamlファイルを更新したら、下のコードのようにImageのimageプロパティでAssetImageクラスを使用して保存した画像を指定し表示できます。

//例
Image(
  image: AssetImage('images/画像名'),
),

また、今回はランダムにサイコロの目が出るようにしたいので、画像名に使用する「数字」を指定するための変数を宣言(変数名:number、初期値:1)しておき、AssetImageの引数に「’images/dice$number.png’」を代入します。(この記事最後の完成したコードで確認)

これでサイコロの目が1の画像が表示されました。次にボタンを押すとサイコロの目がランダムに表示されるようプログラムを作っていきます。

TextButton:サイコロの目がランダムに表示されるボタンを作る

FlutterのWidgetのボタンには基本的な3つのボタン「TextButton」「ElevatedButton」「OutlinedButton」があります。今回はその中の「TextButton」を使ってランダムなサイコロの目を表示させるボタンを作っていきます。

TextButton(
  child: Text('転がす'),
  style: TextButton.styleFrom(
    textStyle: TextStyle(fontSize: 30),
  ),
  onPressed: () {}, //(){}:コールバック関数
),

このTextButtonのコードを書くことでボタンの外見が表示されますが、onPressedプロパティのコールバック関数にプログラムを定義していないので、ボタンが押されても何もプログラムが実行されません。よって、コールバック関数にボタンが押された際、ランダムにサイコロの目が表示されるプログラムを定義する必要があります。

ランダムなサイコロの目を表示させるために「dart:math library」をインポートし、StatefulWidgetのSetStateメソッドでボタンが押されるたびに「MyApp」の変数numberの値が1から6の間でランダムに選ばれ、値に応じたサイコロの画像が表示されるようにします。

//dart:math libraryをインポート
import 'dart:math';

.....

//完成したコードのTextButtonの部分を抽出
TextButton(
  child: Text('転がす'),
  style: TextButton.styleFrom(
    textStyle: TextStyle(fontSize: 30),
  ),
  onPressed: () {
    setState(() { //ボタンが押された際に「MyApp」をbuildし直す
      number = Random().nextInt(6) + 1;
    });
  },
),

これでTextButtonが押されるたびに、ランダムなサイコロの画像が表示されるようになりました。

完成したコード

import 'package:flutter/material.dart';
import 'dart:math';

void main() {
  runApp(
    MyApp(),
  );
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int number = 1;  //画像名に使用する「数字」を指定するための変数を宣言

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('ランダムさいころ'),
        ),
        body: Column(
          children: [
            Expanded(
              flex: 2,
              child: Container(
                padding: EdgeInsets.all(20),
                child: Image(
                  image: AssetImage('images/dice$number.png'), //画像名で使われる「数字」の代わりに「変数」を使う
                ),
              ),
            ),
            Expanded(
              flex: 1,
              child: Container(
                child: TextButton(
                  child: Text('転がす'),
                  style: TextButton.styleFrom(
                    textStyle: TextStyle(fontSize: 30),
                  ),
                  onPressed: () {
                    setState(() {
                      number = Random().nextInt(6) + 1;
                    });
                  },
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
タイトルとURLをコピーしました