FlutterでメッセージアプリのトークっぽいUIを作る【リスト編】


メッセージアプリって意外と作る機会なかったので、Flutterの勉強がてら作ってみました。
※今回は、メッセージを表示するリストUIのみです。

###扱うメッセージのモデル
メッセージで扱う情報は以下のモデルを定義しておきます。
このモデルのリストを表示します。この定義がベストとは限りませんのでご了承ください。

```dart
class ChatMessageModel {
  final String avatarUrl; //ユーザのアイコンURL
  final String name;      //名前
  final String datetime;  //メッセージの日時
  final String message;   //メッセージ本文
  final bool isMine;      //メッセージの自身のものか?

  ChatMessageModel({this.avatarUrl, this.name, this.datetime, this.message, this.isMine});
}
```

#メッセージUIの大枠を作る
今回作るUIのイメージはLINEのトークといった**メッセージをやりとりするUI**です。
FlutterのWidgetである**ListView**と**ListTile**を使ってみます。

##ListViewでListTileを並べる
###[ListView](https://api.flutter.dev/flutter/widgets/ListView-class.html)とは
よく使われるスクロールウィジェットです。
子要素をスクロールする縦方向に表示することができます。
表示する子要素の量や動的か固定かによって、使うべきコンストラクタが変わります。今回は表示するリストの数が少ないのでデフォルトのままでいきます。
for文を使って子要素を並べる実装にします。

###[ListTile](https://api.flutter.dev/flutter/material/ListTile-class.html)とは
アイコンや１行から３行までのテキストなどを、マテリアルデザインのリスト仕様で配置できるウィジェットです。
基本的にデザインが出来上がってるので、プロパティに表示するものを設定するという親切設計です。
プロパティの`title`にメッセージ本文、`subtitle`にユーザのアイコン・名前、メッセージの時刻を表示してみます。
ListViewの子要素にこのListTileを並べます。

コーディングしたものがこちら

```dart
ListView(
  children: [
    for (int index = 0; index < widget.chatMessageList.length; index++)
      Card(
        child:ListTile(
          title:Text(widget.chatMessageList[index].message),
          subtitle: Row(
            children: <Widget>[
               CircleAvatar(
                 backgroundImage:  NetworkImage(widget.chatMessageList[index].avatarUrl),
                 radius: 10.0,
               ),
               Text(widget.messageList[index].name + widget.chatMessageList[index].datetime),
           ]
),),),],)
```
コード中に`Card`とありますが、これもウィジェットです。今はListTileの外枠のデザインのために使っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541992/7503a034-bf4a-b8f0-15b9-25c8b2b256a6.png)
ここまでのUIはこんな感じ。これだとまだスレっぽいですね。


##トークっぽいUIにスタイルを調整する
スタイルを調整してトークっぽいUIにします。
Cardのプロパティに`margin`を設定します。
`margin`は、CSSでもある様に要素の周りのマージンを設定するものです。
モデルで定義した`isMine`を使って、設定するマージンを切り替えます。

```dart
margin: widget.messageList[index].isMine 
  ? EdgeInsets.only(top: 5.0, left: 90.0, bottom: 5.0, right: 8.0) //自分のメッセージであれば右寄せる
  : EdgeInsets.only(top: 5.0, left: 8.0, bottom: 5.0, right: 90.0) //自分以外は左に寄せる
```
ListTileの`Row`に`mainAxisAlignment`を追加します。
`Row`は横並びに子要素を表示するウィジェットです。ユーザのアイコン・名前、メッセージの時刻
`mainAxisAlignment`はフレックスボックスの様なレイアウト設定ができます
こちらも`isMine`を使って設定を切り替えます。

`mainAxisAlignment`はついては[こちら](https://qiita.com/kaleidot725/items/35f6940e594bdf073eb8)がすごく参考になりました。

```dart
mainAxisAlignment: widget.messageList[index].isMine 
  ? MainAxisAlignment.end   //アイコン・名前、メッセージの時刻を右寄せにする
  : MainAxisAlignment.start //アイコン・名前、メッセージの時刻を左寄せにする
```
入れたものがこちら

```dart
ListView(
  children: [
    for (int index = 0; index < widget.chatMessageList.length; index++)
      Card(
        margin: widget.messageList[index].isMine 
          ? EdgeInsets.only(top: 5.0, left: 90.0, bottom: 5.0, right: 8.0)
          : EdgeInsets.only(top: 5.0, left: 8.0, bottom: 5.0, right: 90.0),
        child:ListTile(
          title:Text(widget.chatMessageList[index].message),
          subtitle: Row(
            mainAxisAlignment: widget.messageList[index].isMine 
              ? MainAxisAlignment.end
              : MainAxisAlignment.start,
            children: <Widget>[
               CircleAvatar(
                 backgroundImage:  NetworkImage(widget.chatMessageList[index].avatarUrl),
                 radius: 10.0,
               ),
               Text(widget.messageList[index].name + widget.chatMessageList[index].datetime),
           ]
),),),],)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541992/4a37dce7-4031-a0b6-343a-b1b1be6f6d7c.png)
LINEのトークっぽいUIになりました。全然遠いですけどね笑
まだまだ作成中ですがコードはこちらに置いてあります。
https://github.com/taka-guevara/FlutterMessangerApp

#次回予告
メッセージのフォームと送信ボタン周りを作ってみます。
https://qiita.com/guevara-net/items/b40f96c1329d239197fd

Firebaseかslackと連携してみたい（願望）