14
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Flutter入門】シンプルなメッセージアプリのUIを作る

Last updated at Posted at 2020-02-12

#【はじめに】
Qiita初投稿です。学生エンジニアのKCPと申します。よろしくお願いします:smirk_cat:

2月からFlutterの学習を開始し、その一環としてこちらの記事Build a simple message app UI in Flutterを模写していたのですが、初心者にとっては解説が少なくわかりづらかったのでもう少し噛み砕いて説明していきます。

シンプルなメッセージアプリのUIのみを作っていきます。メッセージはできません。

#【対象読者】

  • Flutterの環境構築が終わっている
  • なんとなくだがチュートリアルを一通り終わらせた
  • 初心者だけどいい感じのUIを作ってみたい

#【今回作るもの】
スクリーンショット 2020-02-12 16.14.29.png

#【実装】
###1. 雛形を作る

まずは新しいプロジェクトを作ります。

$ flutter create message_app

カウンターアプリができると思いますが、一旦まっさらな状態にします。

main.dart

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold();
  }
}

###2. データの作成
まずはデータを入れるための新しいファイルを作成します。

場所はmain.dartと同じ階層のlibディレクトリの下です。

$ touch chat_model.dart

そしてこちらのサイトのAPIを利用してユーザーデータを作成します。

RANDOM USER GENERATOR
A free, open-source API for generating random user data. Like Lorem Ipsum, but for people.
https://randomuser.me/

ChatModelクラスを作成し、この中にデータを入れていきます。

chat_model.dart
class ChatModel {
  final String avatarUrl; 
  final String name;
  final String datetime;
  final String message;

  ChatModel({this.avatarUrl, this.name, this.datetime, this.message});
}

上から画像、名前、日時、メッセージを定義しました。

次に使用する6人のダミーデータを作成します。

chat_model.dart
class ChatModel {
  final String avatarUrl;
  final String name;
  final String datetime;
  final String message;

  ChatModel({this.avatarUrl, this.name, this.datetime, this.message});

<!-- 追加 -->
  static final List<ChatModel> dummyData = [
    ChatModel(
      avatarUrl: "https://randomuser.me/api/portraits/women/34.jpg",
      name: "Laurent",
      datetime: "20:18",
      message: "How about meeting tomorrow?",
    ),
    ChatModel(
      avatarUrl: "https://randomuser.me/api/portraits/women/49.jpg",
      name: "Tracy",
      datetime: "19:22",
      message: "I love that idea, it's great!",
    ),
    ChatModel(
      avatarUrl: "https://randomuser.me/api/portraits/women/77.jpg",
      name: "Claire",
      datetime: "14:34",
      message: "I wasn't aware of that. Let me check",
    ),
    ChatModel(
      avatarUrl: "https://randomuser.me/api/portraits/men/81.jpg",
      name: "Joe",
      datetime: "11:05",
      message: "Flutter just release 1.0 officially. Should I go for it?",
    ),
    ChatModel(
      avatarUrl: "https://randomuser.me/api/portraits/men/83.jpg",
      name: "Mark",
      datetime: "09:46",
      message: "It totally makes sense to get some extra day-off.",
    ),
    ChatModel(
      avatarUrl: "https://randomuser.me/api/portraits/men/85.jpg",
      name: "Williams",
      datetime: "08:15",
      message: "It has been re-scheduled to next Saturday 7.30pm",
    ),
  ];
}

###3. UI設計
やっとUIの実装に移ります:wink:

まずは先ほど作成したデータのファイルをインポートします。
main.dartの一番上に記述してある
import 'package:flutter/material.dart';の下に

import './chat_model.dart';を記述。

そうしたらとりあえずappBar部分を完成させます。

main.dart
@override
  Widget build(BuildContext context) {
    return Scaffold(
<!-- 追加 -->
      appBar: AppBar(
        title: Text('fluttermaster.com - Message Chat'),
      ),
    );
  }
スクリーンショット 2020-02-12 17.14.54.png

body部分の作成に移ります。

メッセージしているユーザーのリストを作成するためにListViewウィジェットを作成します。

main.dart
body: Container(
        child: ListView.builder(
           itemCount: ChatModel.dummyData.length,
           itemBuilder: (context, index) {
             ChatModel _model = ChatModel.dummyData[index];
            }
          ),
        ),

ListView.builder 関数に要素数を itemCount として、 一個一個の要素に対しての表示は itemBuilder を適応させます。

今回、 itemCount には ChatModel.dummyData.length が入っています。

この場合itemCountには先ほど6人分のデータを作成したので6を適応させていることになります。

main.dart
body: Container(
        child: ListView.builder(
           itemCount: ChatModel.dummyData.length,
           itemBuilder: (context, index) {
             ChatModel _model = ChatModel.dummyData[index];
        //追加
             return Column(
              children: <Widget>[
                ListTile(
                  leading: CircleAvatar(
                    radius: 24.0,
                    backgroundImage: NetworkImage(_model.avatarUrl),
                  ),
                  title: Row(
                    children: <Widget>[
                      Text(_model.name),
                      SizedBox(
                        width: 16.0,
                      ),
                      Text(
                        _model.datetime,
                        style: TextStyle(fontSize: 12.0),
                      ),
                    ],
                  ),
                ),
               ],
             );
            },
          ),
        ),

Coliumnをbodyとして表示する値としてListTileウィジェットを入れていきます。

ListTileは、ListViewの子ウィジェットとして使用でき、非常に整ったレイアウトのListViewを簡単に作れることとListViewの要素をタップした時などのイベントを容易に実装できるウィジェットです。

参照: https://saharablog.com/mobile-app/flutter-app/listtile/

leading
左端にウィジェットを追加。Iconが表示されることが多い。

title
真ん中にウィジェットを追加

subtitle
タイトルの下に表示されるサブタイトル

trailing
右端にウィジェットを追加

CircleAvatarはアバターなどを表示するときに円形にクリップしてくれるウィジェットです。
今回の場合はユーザーのアイコンに使われていますね。

ここまで書いたらほとんど終わったも同然です:kissing:

スクリーンショット 2020-02-12 18.05.07.png

###4. 細かい修正
少しユーザー同士が寄りすぎているため、Dividerウィジェットを使って間隔を空けます。

main.dart
body: Container(
        child: ListView.builder(
           itemCount: ChatModel.dummyData.length,
           itemBuilder: (context, index) {
             ChatModel _model = ChatModel.dummyData[index];
             return Column(
              children: <Widget>[

              //追加
                Divider(
                  height: 12.0,
                ),
              //ここまで

                ListTile(
                  leading: CircleAvatar(
                    radius: 24.0,
                    backgroundImage: NetworkImage(_model.avatarUrl),
                  ),
                  title: Row(
                    children: <Widget>[
                      Text(_model.name),
                      SizedBox(
                        width: 16.0,
                      ),
                      Text(
                        _model.datetime,
                        style: TextStyle(fontSize: 12.0),
                      ),
                    ],
                  ),
                ),
               ],
             );
            },
          ),
        ),

ボックスの全体の高さはheightによって指定され、色や線の厚さを変更することもできます。

Dividerについてはこちらに詳しく記載されています。Flutter公式ドキュメント: Divider

最後にメッセージとチャットしたいユーザーに飛べる矢印マーク(実際は飛べない)を追加します。

main.dart
body: Container(
        child: ListView.builder(
           itemCount: ChatModel.dummyData.length,
           itemBuilder: (context, index) {
             ChatModel _model = ChatModel.dummyData[index];
             return Column(
              children: <Widget>[
                Divider(
                  height: 12.0,
                ),
                ListTile(
                  leading: CircleAvatar(
                    radius: 24.0,
                    backgroundImage: NetworkImage(_model.avatarUrl),
                  ),
                  title: Row(
                    children: <Widget>[
                      Text(_model.name),
                      SizedBox(
                        width: 16.0,
                      ),
                      Text(
                        _model.datetime,
                        style: TextStyle(fontSize: 12.0),
                      ),
                    ],
                  ),

           //追加
                  subtitle: Text(_model.message),
                  trailing: Icon(
                    Icons.arrow_forward_ios,
                    size: 14.0,
                  ),
                ),
               ],
             );
            },
          ),
        ),

完成!よっしゃ!

スクリーンショット 2020-02-12 18.37.00.png

#【参照】
さはらのブログ:https://saharablog.com/mobile-app/flutter-app/listtile/
わかりやすいFlutterリファレンス:https://nzigen.com/flutter-reference/2018-04-17-list-view.html
Flutter Widget catalog:https://flutter.dev/docs/development/ui/widgets
Flutter Master:https://fluttermaster.com/build-a-simple-message-app-ui-in-flutter/

#【最後に】
マークダウン記法とかあんま知らんくてめっちゃ時間かかってしまった。

自分も始めたばかりなので何か間違いや知っておくべきことががあればご教授お願いします:pensive:

14
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?