Help us understand the problem. What is going on with this article?

Flutterで有名なアプリのUIを再現する(Twitter編①)

この記事を見るとここまでできます

Screenshot_1579017962.png

今回は初回なので、まだまだ形になっていません。

今回の記事のポイント(要点だけ知りたい方はここだけ読んでください)

画像を円形にして表示する

Twitterでは、左上に表示されている自身の画像や、投稿に表示される投稿者の画像が円形に加工されて表示されています。
この部分の実装は下記のようにしています。

Container(
 margin: EdgeInsets.all(8.0),
 decoration: BoxDecoration(
  shape: BoxShape.circle,
  image: DecorationImage(
   fit: BoxFit.fill,
   image: NetworkImage(iconImgUrl),
  ),
 ),
)

ContainerのdecorationプロパティにBoxDecorationを指定しています。
BoxDecorationのshapeプロパティでBoxShape.circleを指定することで円形に加工されます。
また、画像もDecorationImageのfitプロパティでBoxFit.fillを指定することで円形全体に画像が表示されます。

BottomNavigationBarに4つ以上のボタンを配置する

表示環境にもよるかもしれませんが、私の環境の場合だとBottomNavigationBarに4つ以上のボタンを配置すると表示位置が均等にならず、背景色の指定が無効化されてしまいましたが、最終的に下記のようにすることで解決しました。

BottomNavigationBar(
  type: BottomNavigationBarType.fixed,
  backgroundColor: Color.fromRGBO(30, 40, 54, 1.0),
  showSelectedLabels: false,
  showUnselectedLabels: false,
  items: <BottomNavigationBarItem>[
    _menuButton(Icons.home),
    _menuButton(Icons.search),
    _menuButton(Icons.notifications_none),
    _menuButton(Icons.mail_outline),
  ],
)

上記のようにtypeプロパティにBottomNavigationBarType.fixedを指定する事で解決しました。
typeはデフォルトではBottomNavigationBarType.shiftingが指定されており、固定化されていないようでした。

ここから本題です

このシリーズのゴール

UI周りの実装方法を学習するには有名なアプリを真似て作ればゴールも明確だし、完成した時の満足感も高いだろう、という事で今回はFlutterでTwitterアプリを再現しようと思います。

あくまでUI周りの実装を学習する過程を纏めた記事なので、Twitterクライアントを作るとか、機能を作りこむといったところまではせず、見た目と動作がそっくりになるところまで進めようと思います。

今のところ、5,6回くらいに分けて投稿する予定ですが、実装を進めながらの投稿になりますので、ハマったポイントがあった場合は番外記事も投稿するかもしれません。

続きが気になる方はフォローをお願いします。

今回のゴール

今回は初回なので、上下のメニュー部分を実装します。

コードと解説

アプリのメインは下記のようにしました。

main.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Twitter',
      home: MainPage(),
    );
  }
}

ルートページとしてMainPageをインスタンス化していますので、次はMainPageのコードです。

少し長いのでメソッドごとに4つに分けて解説します。
実際のコードはMainPageクラス内に全て実装しています。

main.dart
class MainPage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: _twitterAppBar(
          'https://d1f5hsy4d47upe.cloudfront.net/79/791ba2a1c3245ae92712c393fe2b6408_w.jpg'),
      body: Container(
        color: Color.fromRGBO(30, 40, 54, 1.0),
      ),
      bottomNavigationBar: _twitterBottomBar(),
    );
  }
}

Twitterアプリのメイン画面は大きく分けると3つのセクションで構成されています。

  • アプリケーションバー:画面上部のアカウントアイコン、Twitterのアイコン、星アイコンが表示されている部分
  • 本文:画面中央のTwitterの投稿が表示される部分
  • メニュー:画面下部の各画面への遷移するためのメニュー部分

上記コードのbuildメソッドではScaffoldを返しています。
Scaffoldは、マテリアルデザイン用のウィジェットで、マテリアルデザインの各要素がプロパティとして定義されています。
その中で今回は、

  • appBarプロパティ:アプリケーションバーにあたる部分です。_twitterAppBarメソッドで中身を実装しています。
  • bodyプロパティ:本文にあたる部分です。今回は背景色を付けているだけですので、説明は割愛します。
  • bottomNavigationBarプロパティ:メニューにあたる部分です。_twitterBottomBarメソッドで中身を実装しています。

続いて、_twitterAppBarメソッドのコードです。

main.dart
  Widget _twitterAppBar(String iconImgUrl) {
    return AppBar(
      backgroundColor: Color.fromRGBO(30, 40, 54, 1.0),
      leading: Container(
        margin: EdgeInsets.all(8.0),
        decoration: BoxDecoration(
          shape: BoxShape.circle,
          image: DecorationImage(
            fit: BoxFit.fill,
            image: NetworkImage(iconImgUrl),
          ),
        ),
      ),
      centerTitle: true,
      title: Text('Trial'),
      actions: <Widget>[
        Container(
          margin: EdgeInsets.all(8.0),
          child: Icon(
            Icons.star_border,
            color: Color.fromRGBO(76, 158, 235, 1.0),
            size: 45,
          ),
        ),
      ],
    );
  }

このメソッドではAppBarを返しています。
ポイントは下記の3点です。

  • leadingプロパティ

アプリケーションバーの左側に表示されるウィジェットを指定する部分です。
Twitterでは、ログインユーザーのアイコン画像が円状に表示されているので、BoxDecorationを使って画像を円状に変形させています。

  • titleプロパティ

アプリケーションバーの中央に表示されるウィジェットを指定する部分です。
Twitterでは、Twitterのアイコンが表示されますが勝手に拝借するわけにもいかないので、この部分はテキストを表示してあります。
centerTitleプロパティをtrueにしておかないと、Androidでは左寄せで表示されます。

  • actionsプロパティ

アプリケーションバーの右側に表示されるウィジェットを指定する部分です。
Twitterでは、表示順ルール変更用の星マークが表示されているので、代替となるアイコンを表示しています。

次は、_twitterBottomBarメソッドです。

main.dart
  Widget _twitterBottomBar() {
    return Container(
      margin: EdgeInsets.only(top: 0.1),
      child: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        backgroundColor: Color.fromRGBO(30, 40, 54, 1.0),
        showSelectedLabels: false,
        showUnselectedLabels: false,
        items: <BottomNavigationBarItem>[
          _menuButton(Icons.home),
          _menuButton(Icons.search),
          _menuButton(Icons.notifications_none),
          _menuButton(Icons.mail_outline),
        ],
      ),
    );
  }

このメソッドでは、BottomNavigationBarでメニューを実装しています。
(Containerで囲われていますが、これはbody部分との境界をつけるためのマージンを指定するためです)

ポイントは、typeプロパティに指定したBottomNavigationBarType.fixedの部分で、これを指定することでボタンの位置が固定化されます。
また、showSelectedLabelsプロパティとshowUnselectedLabelsプロパティでボタンのラベルを非表示にしています。

ボタンの実装は_menuButtonメソッドに実装しました。

main.dart
  BottomNavigationBarItem _menuButton(IconData icon) {
    return BottomNavigationBarItem(
      icon: Icon(
        icon,
        color: Color.fromRGBO(139, 152, 164, 1.0),
      ),
      activeIcon: Icon(
        icon,
        color: Color.fromRGBO(76, 158, 235, 1.0),
      ),
      title: Text(''),
    );
  }

非選択状態のアイコンをiconプロパティに、選択状態にアイコンをactiveIconプロパティに指定したBottomNavigationBarItemを返しています。

次回

自身とフォロワーの投稿が表示される本文を実装予定です。

あとがき

文字色や背景色を各箇所で指定していますが、themeを使ってまとめた方がよさそうですね。
ただ、themeで各プロパティにColor.fromRGBOを使うとエラーになってしまう部分が解決できず・・・。
このあたりも解決次第投稿予定です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away