メッセージ一覧画面(LINE 風トーク)|Android デザイン実践勉強会

サービスにおいて、今やチャット機能は不可欠なようです。最近は、依頼される殆どのアプリ開発で、「LINE のようなトークルーム」を実装しています。そのまま隠しもせずに「LINE 風のメッセージ画面」と仕様書に堂々と書いてある程です。

勿論、寸分違わず、ということではありませんが、ほぼ LINE 風のデザイン指示で、毎度、同じようなレイアウト実装を行っているので、ならば敢えて、LINE のデザインを勉強してみようじゃないか、と思います。


LINE トークを構成する各サイズを分析

余白やコンポーネントの各サイズを調査し、以下に書き込みました。単位は dp。

「W 360 dp x H 70 dp」がトーク一項目のサイズです。

画像2

複雑な構成ではありませんが、少し特徴的です。レイアウト実装時に、どうやって実現するのかな、と勉強になる箇所も少々ありますので、実装のポイントも後述します。


LINE トークの気になる特徴

「日時と未読数」を表示している領域が、固定幅(86dp)になっているようで、例えば「14:00」という短い日付テキスト表示時も、メッセージ領域が不変で右側に伸びていないのが特徴的でした。

画像3

画像4

メッセージ幅が可変であれば、もっとユーザにメッセージを多く見せられると思いますが、そこは好き嫌いで、LINE デザイナーの拘りなのでしょう。私なら、少しでもユーザに多くのメッセージを見せられるように、可変にします。Google 「メッセージ」アプリがまさにそうです。

また、「日時」の文字サイズですが、「12sp」を下回る小ささで、Android では、あまりに小さ過ぎる文字サイズは、以下の警告を出してしまいます。

Avoid using sizes smaller than 12sp
12sp 未満のサイズの使用は避けてください


LINE に酷似したメッセージ一覧画面を実現

Android の警告に則り、設定する最小の文字サイズを「12sp」として構成して、概ね、実現できました。配色に関しては、勉強の対象外としています。

画像2

この全実装(環境一式)は後述にて公開します。

さて、勉強になった実装を以下に解説します。


その前にコーヒーブレイク

次は実装レベルの細かい勉強になるので、神経を使うその前に、コーヒーブレイクしておきます。最近、ラブコメ漫画で注目しているのは「おとなりに銀河」です。

情熱が真っ直ぐでイイです。こういう感じ、どんどん失っていくなあ。


丸イメージ画像は ShapeableImageView を利用

画像5

ShapeableImageView はマテリアル・コンポーネントです。簡単に Shape を設定できます。

       <com.google.android.material.imageview.ShapeableImageView
           android:id="@+id/talk_image"
           android:layout_width="50dp"
           android:layout_height="50dp"
           android:layout_marginVertical="10dp"
           android:background="@color/teal_700"
           app:layout_constraintTop_toTopOf="parent"
           app:layout_constraintBottom_toBottomOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           tools:ignore="ContentDescription" />

イメージ画像を円にするだけなら、以下のように、とても簡単に実現できます。

binding.talkImage.shapeAppearanceModel =
        ShapeAppearanceModel
                .builder()
                .setAllCornerSizes(ShapeAppearanceModel.PILL)
                .build()

この丸い画像を実現する為だけに、外部ライブラリを導入しているケースも多いので、今後はこちらに乗り換えた方が楽になるでしょう。


layout_constraintVertical_chainStyle で「鎖」関係を意識

ひと目見て、「名前」と「メッセージ」は、上下にくっつけて、その状態で縦方向に中央配置したい、とパッと思いつくかもしれません。

画像6

しかし、意外と、その実現方法が思いつかないものです。

これは知っていれば、「layout_constraintVertical_chainStyle="packed"」で簡単に実現できます。縦(Vertical)に並んでいる View をくっつける(packed)という指示です。

       <TextView
           android:id="@+id/talk_name"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginStart="16dp"
           android:text="@{data.name}"
           android:textSize="16sp"
           android:lines="1"
           android:ellipsize="end"
           app:layout_constrainedWidth="true"
           app:layout_constraintVertical_chainStyle="packed"
           app:layout_constraintHorizontal_chainStyle="packed"
           app:layout_constraintHorizontal_bias="0.0"
           app:layout_constraintTop_toTopOf="parent"
           app:layout_constraintBottom_toTopOf="@id/talk_content"
           app:layout_constraintStart_toEndOf="@id/talk_image"
           app:layout_constraintEnd_toStartOf="@id/talk_mute" />
                   
       <TextView
           android:id="@+id/talk_content"
           android:layout_width="0dp"
           android:layout_height="wrap_content"
           android:text="@{data.content}"
           android:textSize="14sp"
           android:maxLines="2"
           android:ellipsize="end"
           app:layout_constraintTop_toBottomOf="@id/talk_name"
           app:layout_constraintBottom_toBottomOf="parent"
           app:layout_constraintStart_toStartOf="@id/talk_name"
           app:layout_constraintEnd_toStartOf="@id/talk_date" />

これは横(Horizontal)にも勿論、応用が可能です。

「名前」と「ミュート画像」をくっつけて、「名前」が長くなっても「日時」を超えないようにする横並びのレイアウトを考えつくでしょう。

画像7

このケースは「layout_constraintHorizontal_chainStyle="packed"」が活躍します。加えて、「layout_constrainedWidth="true"」で制約を超えてしまわないように指定します。指定しないと「日時」を重なってしまいます。

       <TextView
           android:id="@+id/talk_name"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginStart="16dp"
           android:text="@{data.name}"
           android:textSize="16sp"
           android:lines="1"
           android:ellipsize="end"
           app:layout_constrainedWidth="true"
           app:layout_constraintVertical_chainStyle="packed"
           app:layout_constraintHorizontal_chainStyle="packed"
           app:layout_constraintHorizontal_bias="0.0"
           app:layout_constraintTop_toTopOf="parent"
           app:layout_constraintBottom_toTopOf="@id/talk_content"
           app:layout_constraintStart_toEndOf="@id/talk_image"
           app:layout_constraintEnd_toStartOf="@id/talk_mute" />

       <ImageView
           android:id="@+id/talk_mute"
           android:layout_width="18dp"
           android:layout_height="18dp"
           android:layout_marginStart="4dp"
           android:src="@drawable/outline_volume_off_24"
           app:layout_constraintTop_toTopOf="@id/talk_name"
           app:layout_constraintBottom_toBottomOf="@id/talk_name"
           app:layout_constraintStart_toEndOf="@id/talk_name"
           app:layout_constraintEnd_toStartOf="@id/talk_date" />
                   
       <TextView
           android:id="@+id/talk_date"
           android:layout_width="70dp"
           android:layout_height="wrap_content"
           android:layout_marginTop="12dp"
           android:gravity="end|center_vertical"
           android:text="@{data.date}"
           android:textSize="12sp"
           app:layout_constraintTop_toTopOf="parent"
           app:layout_constraintEnd_toEndOf="parent" />

layout_constraintHorizontal_bias="0.0"」を設定して、「名前」と「メッセージ」が中央に配置されるのを抑止しています。「0.0」は、バイアスが無い状態で、左端にくっつきます。


レイアウト全容と環境一式

この全実装(環境一式)を以下に公開します。今後、トーク画面を開発する際、この実装をベースに改造すると、だいぶ楽になると思います。

ここから先は

4,116字 / 1ファイル

¥ 390

この記事が参加している募集

私のコーヒー時間

この記事が気に入ったらサポートをしてみませんか?