「エモい(きれいな)」Flex Messageを作りませんか？ #2 boxコンポーネントの底力

この記事は[前回記事](https://qiita.com/e_chan1007/items/e63992422551cd75b9b3)の続きです。

# はじめに
いーちゃんです。6時間授業ががっつり再開しました。つい4ヶ月前まで普通にやっていたはずなのにちょっときついです。~~ちょっと運動しただけで軽く筋肉痛、怠けすぎました。~~

さて、エモいFlex Message、通称"えもフレ"(個人的に呼んでいるだけです)を作る記事、第2弾です。
今回は、boxコンポーネントを応用して、アイコンやデザインを工夫したボタンの配置をしてみたいと思います。
[Flex Message Simulator](https://developers.line.biz/flex-simulator/)を触りながら読んでみてください。

> (注) 以下の説明では省いていますが、画像等は誰でもHTTP(S)経由でアクセスできるよう、公開されたサーバーに設置しておき、そのURLをプロパティに適切に設定する必要があります。
> また、画像の直リンクは相手サーバーに負荷がかかりますので控えましょう。
> (Flex Messageの画像はクライアントがそれぞれ直接ダウンロードするようです)

# こんなモノが作れるようになります
前回記事で天気予報を紹介しておいて触れずに終わってしまったので先にお伝えしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/3e82be3d-9b83-9097-aa7c-6d8d2c6e0aaf.png)
今回は電車の出発案内をテーマに作っていきます。データとして

- 高輪ゲートウェイ駅
- 京浜東北線 大船行
- 平日8:00に発車
- 各駅停車

を使います。一応今回は[実際のデータ](https://www.jreast-timetable.jp/2007/train/160/160801.html)です。

> 例によってこの記事に出てくる場所は近所でもよく出没するスポットでもなんでもありません。

# 1. 背景を置く
![320px-Takanawa_Gateway_Station_200316e1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/ef09a422-4ea7-283b-3f77-4e4f3a3313e2.jpeg)
[Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Takanawa_Gateway_Station_200316e1.jpg?uselang=ja)よりこの画像をお借りします。
背景の設定方法は、前回記事よりも簡単な方法に切り替えます。

- 画像の`size`プロパティを`full`に設定
- 画像の`aspectMode`プロパティを`cover`に設定`
- __body > boxの`paddingAll`プロパティを`0px`に設定__

これだけです。boxの内側の余白を0にしてやるだけで画像を全面に配置でき、高さもいい感じに決まります。
> 一定のアスペクト比の画像だけを用いるときには、画像の`aspectRatio`に`4:3`のように指定するとboxの大きさも4:3になり、画像が(角を除き)トリミングされないので便利です。

今回は電車の出発案内がテーマなのですが、__背景画像を駅によって変える__と仮定します。すると、ある画像は背景が明るく、ある画像は背景が暗い、つまり背景色によって文字が見づらくなってしまう可能性があります。そのため、今回は画像の上にさらにグラデーションを重ねます。
ですが、Flex Messageでは現在グラデーションを指定できないため、これも画像を載せて対応します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/9c636185-130c-a0a7-ad83-77f4f7d38898.png)

(実際には512x512px、透過の画像を利用します。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/851e1a0c-5818-25c6-152b-700682cac6cd.png)

グラデーション画像を背景と同じ設定で乗せました。しかし、画像の下に配置されてしまいます。そこで`position: absolute`を利用します。
今回はグラデーション画像を移動するので、グラデーション画像の`position`プロパティを`absolute`に設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/55fa42d5-100a-0722-b861-0db2e2caefa6.png)
左上がぴったり合うので、position系の設定は必要ありません。
ちなみに、特に違和感を覚えない方もいらっしゃるかもしれませんが、Flex Messageでは__画像の透過__が半透明を含めちゃんと反映されています。

> 今回は背景画像の`aspectRatio`を設定していないので画像が正方形に切り取られ、512px四方のグラデーションがぴったり重なります。しかし、背景画像に`aspectRatio`を設定するとそううまくはいかず、
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/71fefb7f-a436-dc65-2c0d-514a3f833a63.png)
> (グレー部分は見えないがグラデーション画像が存在する部分)
> このようになり、結果としてグラデーションが適用されない可能性があります。対策方法は背景とグラデーションのアスペクト比を合わせる、すなわち
>
 - グラデーションに背景画像と同じ`aspectRatio`を指定する(=引き伸ばし)
 - グラデーション画像を背景画像と同じアスペクト比で作っておく

> のどちらかをする必要があります。

# 2. 文字を置く
もう一度情報を整理すると

- 高輪ゲートウェイ駅
- 京浜東北線 大船行
- 平日8:00に発車
- 各駅停車

です。おそらくこの情報を見る人が重要だと思う順番は、

1. 平日8:00に発車
2. 京浜東北線 大船行
3. 各駅停車
4. 高輪ゲートウェイ駅

くらいではないでしょうか。それを踏まえて文字は、

1. 高輪ゲートウェイ駅 (sm)
2. 京浜東北線 大船行 (lg)
3. 8:00発 (3xl)
4. 各駅停車 (sm)

を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/9988ec76-8142-a535-7220-380ef2560a48.png)
大きさだけ指定するとこうなります。ということで、次は位置を調整しようと思うのですが、今回は4つの文字をまとめて下側に配置したいと思いますので、まず「グループ化」しましょう。といってもboxコンポーネントを作成してその中に入れるだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/ad412f50-1a7b-86f8-8088-dd1118ec7d26.png)
このような構造になればOKです。

続いて、boxコンポーネントごと位置をずらしましょう。

- `position`を`absolute`に
- `offsetBottom`を`0px`に
- `paddingAll`を`16px`に

このように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/af745ad8-d170-6a07-b373-a5256c604405.png)
グレー系のグラデーションを指定しているので、このままでは何一つ文字が読めません。そこで、文字色を変更します。`#FFFFFF`を基本として、時刻と路線以外は不透明度を`DD`まで下げましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/e16ed2a3-4b83-5c59-7c70-7f7d2a0a4bb2.png)
> ※思ったより見づらかったのでこの画像からグラデーションを少し濃くしました

…一応完成、と言えるような言えないような感じです。

# 3. 微調整
### 1. 路線名と種別は横並びでいけそう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/3fae1327-0e08-d61c-3fd6-fbb9212e6348.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/f32b8122-42ad-d3d6-7b21-4859075475e4.png)
路線名と種別を同じboxに入れ、そのboxの`layout`プロパティを`baseline`に設定します。
boxコンポーネントの`layout`には3つの種類があり、

- `vertical`: 縦向きにコンポーネントを配置(既定)
- `horizontal`: 横向きにコンポーネントを配置
- `baseline`: 横向きにコンポーネントをベースラインが揃うよう配置

`baseline`レイアウトではベースライン、英語の4線ノートでいう上から3本目の位置に文字が揃います。そのまま配置すると間が詰まってしまうので、`各駅停車`側の`margin`を`lg`にしました。

### 2. 路線のマークをつけたい
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/b745c931-6ee0-e3e5-0bd5-dbacf2ef0abd.png)
([ニュースリリース](https://www.jreast.co.jp/press/2016/20160402.pdf)参照) これを指してるつもりです。

今回は`京浜東北線`の左側に置きたいのですが、先程のboxの戦闘にいつも通りimageコンポーネントを入れればいいような気もします。ですが、その方法では__高さの調節__が難しいのです。そこで マーク、すなわちアイコンをいい感じに配置するコンポーネント、`icon`コンポーネントを使いましょう。
ちなみに、`icon`コンポーネントは**`baseline`レイアウトのbox内にしか配置できない**性質がありますから、先程追加したboxを選択した状態で`icon`コンポーネントを追加しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/57dfd212-9d1c-5361-fcae-191c3f39e413.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/291cd1be-98be-f947-680a-90e8e9f74db1.png)
ちなみにこのアイコン、角丸の四角の中にJKって書いてあるわけですが、これくらいシンプルなものは画像を用意しなくてもboxコンポーネントとtextコンポーネントで再現可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/bb724947-c9a3-1282-5b04-ca75b63969b2.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/034b1640-1c63-5d4f-b683-a2b131407d44.png)
水色の枠線をつけ、角を丸め、白で塗ったboxの中にJKと書く、それだけです。注意する点は

- `baseline`boxの中にboxコンポーネントを入れることができない →  外側をさらに`horizontal`boxで囲う(その場合`baseline`boxの中身も出せますね)
- そのままだと路線名とアイコンが上揃え・余白なしになってしまうので`baseline`boxに
    - `margin`: `md`を指定する
    - `offsetTop`: `2px`くらいで上下を合わせる

ことです。
ちなみにアイコンのboxの装飾は

- `backgroundColor`: `#FFFFFF`
- `borderColor`: `#00B2E5`
- `borderWidth`: `4px`
- `cornerRadius`: `4px`

を、文字自体には

- `size`: `xs`
- `weight`: `bold`

それぞれ指定しています。

### 3. 詳細ボタンをつけたい
buttonコンポーネントも[あります](https://developers.line.biz/ja/reference/messaging-api/#button)が、デザインをカスタマイズできる範囲が狭いので、これまたboxコンポーネントで作成しましょう。
「クリックしたときにちゃんと動くの?」と思うかもしれませんが、ボタンがタップされたときのアクションを表す`action`オブジェクトは他のコンポーネントにも設定できるため問題はありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/bf5feea6-f560-5970-9225-57fc1c7c115d.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/7cf572ac-b7eb-5f69-03ed-050517f24e01.png)
boxコンポーネントだと、このように丸みを帯びたボタンも作成できます。
boxコンポーネントに

- `borderColor`: `2px`
- `borderColor`: `#FFFFFF`
- `cornerRadius`: `32px`
- `paddingAll`: `4px`

その中のtextコンポーネントに

- `align`: `center`
- `color`: `#FFFFFF`

をそれぞれ指定しました。
この中で注目すべき点は、`cornerRadius`プロパティかと思います。
先程は角を少し丸めるために使いましたが、ここに大きめな値を設定すると角と角がつながって丸くなります。この性質を利用して、boxコンポーネントの`width`と`height`プロパティに同じ値を設定すると、円が描けるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/7a7d46fb-2098-b825-da9c-8767a6d04657.png)
こんな感じのアイコンも作れるようになる、というわけです。
ちなみに、四角でも丸でも、__boxコンポーネント内には最低1つの子コンポーネントが必要__なので、ただの丸や四角だけを描きたいときには`filler`コンポーネントなんかを入れておきましょう。

> 説明を忘れていましたが、実際にボタンとして機能させるには`action`オブジェクトが必要です。
> `action`オブジェクトについては[リッチメニュー版の記事](https://qiita.com/e_chan1007/items/cd34ce0871943ee34396)を参考にしてみてください。このページで作成したJSONのうち、areas > action オブジェクトが転用可能です。

# 完成!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151384/3e82be3d-9b83-9097-aa7c-6d8d2c6e0aaf.png)
実際にBotとして配信するには若干機能不足、見た目が悪い気もしますがとりあえずは完成です。エモくなってます...よね?

# まとめ
__boxコンポーネント万能!!!__

- 背景画像は前回記事よりも簡単につけられるよ
- Flex Messageでは透過画像もちゃんと扱えるよ
- `vertical`レイアウトなら縦に、`horizontal`レイアウトなら横に並ぶよ
- `baseline`レイアウトだとベースラインが揃ったりアイコンがつけられたりするよ
- `borderColor`と`borderWidth`で枠線がつけられるよ
- `cornerRadius`で角を丸めたり、円を描くこともできるよ

# 最後に
- \#2にしてネタ切れなのでこの連載は一旦終了です。またネタが出来たら続編を書くかもしれません。
- 「エモい」をタイトルにしてるのに今回は全然使いませんでしたねw
- __「エモけりゃいい」ってもんじゃないです__(大切)
    - どんなにデザインがよくても使ってもらえないことがあります(体験談)
    - 相手のニーズにあった開発をしていくことが大切ですね
- 感想、要望、コメント等ありましたらお願いします!