ハンズオンで学ぶFlutter(UI構築編)

#Flutterとは??
Google製の1つのコードで、androidアプリ、iosアプリを作成できるマルチプラットフォームです。
以下のURLはFlutterの公式ホームページです。
https://flutter.dev/?gclid=CjwKCAiA_Kz-BRAJEiwAhJNY783VvB3S3Nk5DjqVD2Rs4uQavLOakmvbjAKYd0IRpvVvTiWCQEDzexoCgJEQAvD_BwE&gclsrc=aw.ds

FlutterはGoogleが本腰を入れているため、ドキュメントがしっかりしています。

また、FlutterはDartという言語で書かれています。
DartもGoogle製の言語で、JavascriptやJavaに影響を受けて作られた言語なので、経験のある方は飲み込みやすいと思われます。

#Flutterのハンズオン
それでは早速本題に入りましょう。
この記事では、FlutterでのUIの構築方法、状態管理の方法を簡単なアプリを作りながら学んでいきます。
今回は、UI構築編なので見た目の部分を作っていきましょう。

##最終的な成果物
![123.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669831/14227756-fea9-dec5-d477-f506a340e37d.jpeg)

今回作成するアプリは、見ての通りニュースの一覧を表示するアプリです。
ニュースの内容はnewapiからとってきたものを表示しています。
以下のurlから確認してみてください。
https://newsapi.org/

本来は、apiを取ってくるところまでコードを書かないといけないのですが、今回は「FlutterでのUI構築」と「状態管理」にフォーカスするので、いったん飛ばします(必要なコードはこちらで提供)。
それでは、「FlutterでのUI構築」から行っていきましょう。

##UI構築(見た目の作成)
早速コードを見ていきましょう!
最初にFlutterのプロジェクトを作成すると、以下のようなカウントアプリがmain.dartの中にデフォルトで作られると思います。
![default_app.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669831/bfdd0999-11bc-d3c5-f207-fe209a14d2e8.jpeg)

とりあえず、必要のない部分は消して、以下の画面を作成して準備オッケーです!
![125.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669831/56d59fe7-3f50-68a4-06a4-a9b36f95835c.jpeg)

今の段階のコードは、以下です。

```dart:lib/main.dart

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,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MainPage(),
    );
  }
}
class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Demo"),
        centerTitle: true,
      ),
      body: Center(
        child: Text("I am ready to go"),
      ),
    );
  }
}

```
このMainPageクラスは、statelesswidgetを継承しているwidgetです。
Flutterでは、このようにクラスを作成し、基本的にはstatefulwidgetか、statelesswidgetのwidgetを継承します。それらのwidgetを組み合わせ、階層構造を作ることによって、UIを作成します。

###詳細

```dart:lib/main.dart
class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Demo"),
        centerTitle: true,
      ),
      body: Center(
        child: Text("I am ready to go"),
      ),
    );
  }
}

```

statelesswidgetの中にあるbuildメソッドはUIを構築していくメソッドになります。ここでは、Scaffoldというwidgetを返しています。Scaffoldはシンプルなデザインを提供してくれるwidgetになり、appbar、bodyなどの部分に新たなwidgetを与えることで画面を生成していきます。

###StatelessWidgetとStatefulwidgetの違いは?
先ほどの、MainPageクラスはstatelesswidgetを継承していますが、statefulwidgetというものもあります。この違いを見ていきます。
####StatelessWidget
stateがlessなので、名前の通り状態を持たないwidgetです。　厳密的に言うと、状態をもってもいいが、widgetが作成された後は値の状態を変更できないwidgetになります。もし、値の状態を変更したい場合は一度widgetを破棄して、新しいwidgetを作成する必要があります。

###StatefulWidget
逆にstatefulwidgetは、状態を持つことが出来、状態の変更も可能です。
詳しくは、[statefulwidgetの説明](https://tech-rise.net/why-stateful-widget-separates-two-classes/) から調べてみてください。

##Scaffold内のbodyを変更する

長くなりましたが、Scaffoldのbodyを変更してニュースリストページを作っていきましょう。
最初は、ニュースのデータを持ってこずに見た目の部分だけ作成します。
完成図は以下になります。
![122.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669831/b7163030-7b37-9641-228a-ed548accd5df.jpeg)

ニュースの画像(newsimage)とニュースのタイトル(newsexample)を表示するwidget(ArticleTile)を一つ作り、それをリスト表示できるwidget(ListView)で複数個並べています。(背景色はわかりやすいようにするためのものです)

コードは以下の通りです。

```dart:lib/main.dart

class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Demo"),
          centerTitle: true,
        ),
        body: Padding(
          padding: const EdgeInsets.only(top: 10),
          child: Container(
            margin: EdgeInsets.symmetric(horizontal: 10),
            //ListView.builderはリストを作成するwidget
            child: ListView.builder(
              //リストで表示する数を記入
              itemCount: 10,
              //リストで表示するwidgetを記入(ここではArticleTileというwidgetをリストで表示)
              itemBuilder: (context, index) {
                //下にあるArticleTileをreturnしている。
                return ArticleTile();
              },
            ),
          ),
        ));
  }
}

//ニュースの内容を表示するwidget
class ArticleTile extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //子要素にpaddingをつけることのできるwidget
    return Padding(
      padding: const EdgeInsets.only(bottom: 6),
      //Containerは背景色や子のサイズ、またwidgetの形を変えたりすることがが出来るwidget
      child: Container(
        //形を変更できる
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(8.0),
        ),
        //Rowは子要素を横に並べることが出来るwidget
        child: Row(
          children: [
            //ニュース画像を表示するエリア
            //RowやColumnの子Widget間の隙間を目一杯埋めたいときに使うwidget
            Expanded(
                //比を操作できる
                flex: 2,
                child: Container(
                  height: 150,
                  child: Center(child: Text("newsimage")),
                  color: Colors.grey,
                )),
            //ニュースタイトルを表示するエリア
            Expanded(
                //比を操作できる
                flex: 5,
                child: Container(
                  height: 150,
                  child: Center(child: Text("newsexample")),
                  color: Colors.amber,
                )),
          ],
        ),
      ),
    );
  }
}
```
ここで出てきたwidget一覧は、
>・Container
・Row
・Center
・Padding
・Expanded
>・ListView

です。
このようにFlutterで用意されているWidgetを使いながら見た目の部分を作成していきます。
これらのWidgetはすべてStatelessWidgetもしくはStatefulWidgetを継承しています。ここからも、flutterはすべてWidgetであることがわかると思います。

また、ここでは出てきてませんがColumnやCard、Stackなど多くのwidgetがFlutterでは用意されています。
詳しくは以下の記事をご覧ください。
[Flutter開発のために知っておくべきwidget](https://qiita.com/coka__01/items/dedb569f6357f1b503fd)


今回は、見た目の部分の大枠だけ作成しましたが、次から実際にニュースのデータを取ってきて表示するところまでやっていきます。