1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LINE FlexMessageでタップ不可ボタンを作ろう!

1
Posted at

概要

今回は、LINE BotでGoogle Calendarと連携した予約UIを作る中で、Flex Messageのボタンを「タップ不可」にするUIを作ってみました!

作ったのは、時間帯選択のFlex Messageです。Google Calendarの空き情報を取得して、空いているスロットは緑、予定が入っているスロットはグレーで表示します。空きスロットをタップすると予約フローに進み、グレーのスロットはタップしても何も起きない、という挙動です。

シンプルなんですが、Flex Messageの仕様上「グレーにしたボタンをタップしても何も起きない」を解決するために埋まりスロットには button ではなく box + text を使うことで解決しています。以下が実際の画像です。

IMG_6581.jpg
IMG_6582.jpg

なぜ Flex Message でタップ無効の UI が作れないのか

button の action は必須

原因は、Flex Message の button コンポーネントでは action が必須プロパティ になっていることでした。LINE の公式 OpenAPI スキーマ(line-openapi)を確認すると、FlexButton の定義は以下のようになっています。

FlexButton:
  type: object
  required:
    - action        # ← 必須
  allOf:
    - "$ref": "#/components/schemas/FlexComponent"
    - type: object
      properties:
        action:
          "$ref": "#/components/schemas/Action"
        color:
          type: string
        style:
          type: string
          enum:
            - primary
            - secondary
            - link

required: [action] と明記されています。action を省略するとバリデーションエラーになり、メッセージ自体が送信できません。button を使う限り、どんなに見た目をグレーにしても中身には必ず action が入っていて、タップすれば発火してしまいます。

disabled 属性は存在しない

HTMLなら <button disabled> の一言で終わる話ですが、Flex Messageにはそのような disabled に相当する属性は存在しません。スキーマの FlexButton のプロパティを見ても、actioncolorstyleheightgravity などがあるだけで、タップを無効化するようなフラグはどこにもないです。

つまり、button コンポーネントを使っている限り、「見た目だけグレーにして押せなくする」は仕様上不可能ということになります。

box なら action は省略できる

一方で、FlexBox のスキーマを見てみます。

FlexBox:
  type: object
  required:
    - layout
    - contents       # ← action は required に入っていない
  allOf:
    - properties:
        layout:
          type: string
        contents:
          type: array
        backgroundColor:
          type: string
        cornerRadius:
          type: string
        action:              # ← プロパティ自体は存在する
          "$ref": "#/components/schemas/Action"
        justifyContent:
          type: string

box にも action プロパティ自体は存在しますが、required に含まれていません。つまり省略可能で、省略すればタップしても何も起きません。

ここがポイントで、box の中に text を置いてボタンと同じ見た目にスタイリングすれば、見た目はボタン、タップしても無反応なコンポーネントが作れるわけです。

今回実装したこと

box + text でボタンの見た目を再現

空きスロットは従来どおり button + postback、埋まりスロットだけ box + text に差し替える形で実装しました。

if is_busy:
    # box + text: タップしても何も起きない
    element = {
        "type": "box",
        "layout": "vertical",
        "contents": [{
            "type": "text",
            "text": f"{start} - {end}",
            "align": "center",
            "color": "#FFFFFF",
            "size": "sm",
        }],
        "backgroundColor": "#CCCCCC",
        "cornerRadius": "md",
        "height": "40px",
        "justifyContent": "center",
        "margin": "sm",
    }
else:
    # button: タップで postback
    element = {
        "type": "button",
        "action": {
            "type": "postback",
            "label": f"{start} - {end}",
            "data": f"action=select_time&date={date}&start={start}&end={end}",
        },
        "style": "primary",
        "color": "#06C755",
        "height": "sm",
        "margin": "sm",
    }

buttonbox は同じ body 内に混在できるので、スロットごとに出し分けるだけでOKです。

見た目を揃えるために意識したこと

box をそのまま使うと button と見た目が微妙にずれるので、3つのポイントを意識しました。

背景色の指定方法が違う。 buttoncolor プロパティで背景色を指定しますが、boxbackgroundColor です。プロパティ名が違うだけなので、同じ色コードを入れれば見た目は揃います。

角丸はデフォルトでつかない。 button は最初から角丸が適用されていますが、box はデフォルトが直角です。cornerRadius: "md" を指定することで button と同じ丸みが再現できます。

テキストが上に寄る。 buttonlabel は自動で上下中央に配置されますが、box + text だとテキストが上に寄ります。justifyContent: "center"height: "40px" を明示的に指定して揃えました。

日付選択でも同じパターンを適用

この方法は時間帯選択だけでなく、日付選択カルーセルでも使っています。2週間分の日付を並べて、Google Calendarに予定がある日はグレーの box、空いている日は緑の button で表示しています。コンポーネントの構造は全く同じで、ラベルを日付に変えるだけなので汎用的に使えました。

バックエンド側のガード処理が不要に

副次的なメリットとして、Webhookハンドラ側のコードがシンプルになりました。もし button のまま実装していたら、ハンドラ側で「このスロットはbusyだから処理をスキップする」というガード処理を入れる必要がありました。Flex Message側で確実にブロックできていれば、ハンドラには余計な分岐を持ち込まなくて済みます。

まとめ

button では「押せないボタン」は作れない

Flex Messageの buttonaction が必須プロパティで、disabled 属性も存在しない。背景色をグレーにしても postback は発火する。

box + text で代替する

boxaction はオプショナルなので、省略すればタップしても無反応。backgroundColor / cornerRadius / justifyContent の3つを調整すれば button との見た目の差はほぼなくなる。

box に action を付けないこと

box にも action を付与できるが、付けてしまうと button と同じ問題が再発する。あくまで action省略することで無反応にする手法。

参考文献

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?