#【はじめに】
Qiita初投稿です。学生エンジニアのKCPと申します。よろしくお願いします
2月からFlutterの学習を開始し、その一環としてこちらの記事Build a simple message app UI in Flutterを模写していたのですが、初心者にとっては解説が少なくわかりづらかったのでもう少し噛み砕いて説明していきます。
シンプルなメッセージアプリのUIのみを作っていきます。メッセージはできません。
#【対象読者】
- Flutterの環境構築が終わっている
- なんとなくだがチュートリアルを一通り終わらせた
- 初心者だけどいい感じのUIを作ってみたい
#【実装】
###1. 雛形を作る
まずは新しいプロジェクトを作ります。
$ flutter create message_app
カウンターアプリができると思いますが、一旦まっさらな状態にします。
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クラスを作成し、この中にデータを入れていきます。
class ChatModel {
final String avatarUrl;
final String name;
final String datetime;
final String message;
ChatModel({this.avatarUrl, this.name, this.datetime, this.message});
}
上から画像、名前、日時、メッセージを定義しました。
次に使用する6人のダミーデータを作成します。
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の実装に移ります
まずは先ほど作成したデータのファイルをインポートします。
main.dartの一番上に記述してある
import 'package:flutter/material.dart';
の下に
import './chat_model.dart';
を記述。
そうしたらとりあえずappBar部分を完成させます。
@override
Widget build(BuildContext context) {
return Scaffold(
<!-- 追加 -->
appBar: AppBar(
title: Text('fluttermaster.com - Message Chat'),
),
);
}
body部分の作成に移ります。
メッセージしているユーザーのリストを作成するためにListViewウィジェットを作成します。
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を適応させていることになります。
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の要素をタップした時などのイベントを容易に実装できるウィジェットです。
leading
左端にウィジェットを追加。Iconが表示されることが多い。
title
真ん中にウィジェットを追加
subtitle
タイトルの下に表示されるサブタイトル
trailing
右端にウィジェットを追加
CircleAvatarはアバターなどを表示するときに円形にクリップしてくれるウィジェットです。
今回の場合はユーザーのアイコンに使われていますね。
ここまで書いたらほとんど終わったも同然です
###4. 細かい修正
少しユーザー同士が寄りすぎているため、Dividerウィジェットを使って間隔を空けます。
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
最後にメッセージとチャットしたいユーザーに飛べる矢印マーク(実際は飛べない)を追加します。
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,
),
),
],
);
},
),
),
完成!よっしゃ!
#【参照】
さはらのブログ: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/
#【最後に】
マークダウン記法とかあんま知らんくてめっちゃ時間かかってしまった。
自分も始めたばかりなので何か間違いや知っておくべきことががあればご教授お願いします