今回はFlex Message についてお伝えします。
かなり細かく設定できる一方、使いこなすのはとてつもなく困難です。
現実的な話、いくつかあるテンプレートを元にカスタマイズしていくのがいいと思います。
Flex Message Simulator を使うと確認しながらカスタマイズできて便利です。
ここではいくつかサンプルを組み込んでみましょう。
Apparelをベースにカスタマイズ
<!DOCTYPE html> <html lang="jp" dir="ltr"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>XP LIFF</title> <script src="https://static.line-scdn.net/liff/edge/2.1/sdk.js"></script> <script type="text/javascript"> document.addEventListener("DOMContentLoaded", () => { liff .init({ liffId: '<LIFF_ID>' }) .then(() => { document.getElementById('go').addEventListener('click', () => { if (!liff.isInClient()) { document.getElementById('log').value += 'ngn'; } else { liff.sendMessages([{ "type": "flex", "altText": "This is a Flex Message", "contents": { "type": "carousel", "contents": [ { "type": "bubble", "body": { "type": "box", "layout": "vertical", "contents": [ { "type": "image", "url": "https://www.x-power.co.jp/images/top/logo_20200116.png", "size": "full", "aspectMode": "fit", "aspectRatio": "2:3", "gravity": "top" }, { "type": "box", "layout": "vertical", "contents": [ { "type": "box", "layout": "vertical", "contents": [ { "type": "text", "text": "CrossPower", "size": "xl", "color": "#ffffff", "weight": "bold" } ] } ], "position": "absolute", "offsetBottom": "0px", "offsetStart": "0px", "offsetEnd": "0px", "backgroundColor": "#03303Acc", "paddingAll": "20px", "paddingTop": "18px" } ], "paddingAll": "0px" } }, { "type": "bubble", "body": { "type": "box", "layout": "vertical", "contents": [ { "type": "image", "url": "https://www.x-power.co.jp/images/top/osc.jpg", "size": "full", "aspectMode": "cover", "aspectRatio": "16:11", "gravity": "top" }, { "type": "box", "layout": "vertical", "contents": [ { "type": "box", "layout": "vertical", "contents": [ { "type": "text", "text": "『LinuC試験", "size": "xl", "color": "#ffffff", "weight": "bold" }, { "type": "text", "text": "から学ぶ", "size": "xl", "color": "#ffffff", "weight": "bold" }, { "type": "text", "text": "セキュリティ入門』", "size": "xl", "color": "#ffffff", "weight": "bold" } ] }, { "type": "box", "layout": "vertical", "contents": [ { "type": "text", "text": "弊社が運営する寺子屋ITライセ", "color": "#ebebeb", "size": "sm", "flex": 0 }, { "type": "text", "text": "ンスの講師が、", "color": "#ebebeb", "size": "sm", "flex": 0 }, { "type": "text", "text": "「オープンソースカンファレン", "color": "#ebebeb", "size": "sm", "flex": 0 }, { "type": "text", "text": "ス2019 Enterprise」にて", "color": "#ebebeb", "size": "sm", "flex": 0 }, { "type": "text", "text": "登壇致しました。", "color": "#ebebeb", "size": "sm", "flex": 0 } ], "spacing": "none" } ], "position": "absolute", "offsetBottom": "0px", "offsetStart": "0px", "offsetEnd": "0px", "backgroundColor": "#9C8E7Ecc", "paddingAll": "20px", "paddingTop": "18px" }, { "type": "box", "layout": "vertical", "contents": [ { "type": "text", "text": "NEW", "color": "#ffffff", "align": "center", "size": "xs", "offsetTop": "3px" } ], "position": "absolute", "cornerRadius": "20px", "offsetTop": "18px", "backgroundColor": "#ff334b", "offsetStart": "18px", "height": "25px", "width": "53px" } ], "paddingAll": "0px" } } ] } }]).then(function() { document.getElementById('log').value += 'completedn'; }).catch(function(error) { document.getElementById('log').value += error + 'n'; }); } }); }) .catch((err) => { document.getElementById('log').value = 'init ngn' + err; }); }); </script> </head> <body> <div> <h3>Flex Message - Apparel</h3> <input type="button" id="go" value="実行"/> <textarea id="log" style="width:96%;height:100px;"></textarea> </div> </body> </html>
Webサイトのトピックスのようなメッセージが出来上がりました。
画像を並べる
<!DOCTYPE html> <html lang="jp" dir="ltr"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>XP LIFF</title> <script src="https://static.line-scdn.net/liff/edge/2.1/sdk.js"></script> <script type="text/javascript"> document.addEventListener("DOMContentLoaded", () => { liff .init({ liffId: '<LIFF_ID>' }) .then(() => { document.getElementById('go').addEventListener('click', () => { if (!liff.isInClient()) { document.getElementById('log').value += 'ngn'; } else { liff.sendMessages([{ "type": "flex", "altText": "This is a Flex Message", "contents": { "type": "bubble", "body": { "type": "box", "layout": "vertical", "contents": [ { "type": "image", "url": "https://www.x-power.co.jp/images/top/top_business1.jpg", "position": "relative", "size": "full", "aspectMode": "cover" }, { "type": "image", "url": "https://www.x-power.co.jp/images/top/top_business2.jpg", "position": "relative", "size": "full", "aspectMode": "cover" }, { "type": "image", "url": "https://www.x-power.co.jp/images/top/top_business3.jpg", "position": "relative", "size": "full", "aspectMode": "cover" } ] }, "styles": { "body": { "backgroundColor": "#000000" } } } }]).then(function() { document.getElementById('log').value += 'completedn'; }).catch(function(error) { document.getElementById('log').value += error + 'n'; }); } }); }) .catch((err) => { document.getElementById('log').value = 'init ngn' + err; }); }); </script> </head> <body> <div> <h3>Flex Message - Apparel</h3> <input type="button" id="go" value="実行"/> <textarea id="log" style="width:96%;height:100px;"></textarea> </div> </body> </html>
画像を縦に並べてみました。
枠線を黒でしていしていますが、paddingを無くせば枠なしも可能です。
Transit(乗り換え案内)
<!DOCTYPE html> <html lang="jp" dir="ltr"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>XP LIFF</title> <script src="https://static.line-scdn.net/liff/edge/2.1/sdk.js"></script> <script type="text/javascript"> document.addEventListener("DOMContentLoaded", () => { liff .init({ liffId: '<LIFF_ID>' }) .then(() => { document.getElementById('go').addEventListener('click', () => { if (!liff.isInClient()) { document.getElementById('log').value += 'ngn'; } else { liff.sendMessages([{ "type": "flex", "altText": "This is a Flex Message", "contents": { "type": "bubble", "size": "mega", "header": { "type": "box", "layout": "vertical", "contents": [ { "type": "box", "layout": "vertical", "contents": [ { "type": "text", "text": "出発", "color": "#ffffff66", "size": "sm" }, { "type": "text", "text": "秋葉原", "color": "#ffffff", "size": "xl", "flex": 4, "weight": "bold" } ] }, { "type": "box", "layout": "vertical", "contents": [ { "type": "text", "text": "到着", "color": "#ffffff66", "size": "sm" }, { "type": "text", "text": "新宿", "color": "#ffffff", "size": "xl", "flex": 4, "weight": "bold" } ] } ], "paddingAll": "20px", "backgroundColor": "#0367D3", "spacing": "md", "height": "154px", "paddingTop": "22px" }, "body": { "type": "box", "layout": "vertical", "contents": [ { "type": "text", "text": "計: 1 時間", "color": "#b7b7b7", "size": "xs" }, { "type": "box", "layout": "horizontal", "contents": [ { "type": "text", "text": "20:30", "size": "sm", "gravity": "center" }, { "type": "box", "layout": "vertical", "contents": [ { "type": "filler" }, { "type": "box", "layout": "vertical", "contents": [ { "type": "filler" } ], "cornerRadius": "30px", "height": "12px", "width": "12px", "borderColor": "#EF454D", "borderWidth": "2px" }, { "type": "filler" } ], "flex": 0 }, { "type": "text", "text": "秋葉原", "gravity": "center", "flex": 4, "size": "sm" } ], "spacing": "lg", "cornerRadius": "30px", "margin": "xl" }, { "type": "box", "layout": "horizontal", "contents": [ { "type": "box", "layout": "baseline", "contents": [ { "type": "filler" } ], "flex": 1 }, { "type": "box", "layout": "vertical", "contents": [ { "type": "box", "layout": "horizontal", "contents": [ { "type": "filler" }, { "type": "box", "layout": "vertical", "contents": [ { "type": "filler" } ], "width": "2px", "backgroundColor": "#B7B7B7" }, { "type": "filler" } ], "flex": 1 } ], "width": "12px" }, { "type": "text", "text": "徒歩 4分", "gravity": "center", "flex": 4, "size": "xs", "color": "#8c8c8c" } ], "spacing": "lg", "height": "64px" }, { "type": "box", "layout": "horizontal", "contents": [ { "type": "box", "layout": "horizontal", "contents": [ { "type": "text", "text": "20:34", "gravity": "center", "size": "sm" } ], "flex": 1 }, { "type": "box", "layout": "vertical", "contents": [ { "type": "filler" }, { "type": "box", "layout": "vertical", "contents": [ { "type": "filler" } ], "cornerRadius": "30px", "width": "12px", "height": "12px", "borderWidth": "2px", "borderColor": "#6486E3" }, { "type": "filler" } ], "flex": 0 }, { "type": "text", "text": "御茶ノ水", "gravity": "center", "flex": 4, "size": "sm" } ], "spacing": "lg", "cornerRadius": "30px" }, { "type": "box", "layout": "horizontal", "contents": [ { "type": "box", "layout": "baseline", "contents": [ { "type": "filler" } ], "flex": 1 }, { "type": "box", "layout": "vertical", "contents": [ { "type": "box", "layout": "horizontal", "contents": [ { "type": "filler" }, { "type": "box", "layout": "vertical", "contents": [ { "type": "filler" } ], "width": "2px", "backgroundColor": "#6486E3" }, { "type": "filler" } ], "flex": 1 } ], "width": "12px" }, { "type": "text", "text": "東京メトロ 1時間", "gravity": "center", "flex": 4, "size": "xs", "color": "#8c8c8c" } ], "spacing": "lg", "height": "64px" }, { "type": "box", "layout": "horizontal", "contents": [ { "type": "text", "text": "20:40", "gravity": "center", "size": "sm" }, { "type": "box", "layout": "vertical", "contents": [ { "type": "filler" }, { "type": "box", "layout": "vertical", "contents": [ { "type": "filler" } ], "cornerRadius": "30px", "width": "12px", "height": "12px", "borderColor": "#6486E3", "borderWidth": "2px" }, { "type": "filler" } ], "flex": 0 }, { "type": "text", "text": "新宿", "gravity": "center", "flex": 4, "size": "sm" } ], "spacing": "lg", "cornerRadius": "30px" } ] } } }]).then(function() { document.getElementById('log').value += 'completedn'; }).catch(function(error) { document.getElementById('log').value += error + 'n'; }); } }); }) .catch((err) => { document.getElementById('log').value = 'init ngn' + err; }); }); </script> </head> <body> <div> <h3>Flex Message - Transit</h3> <input type="button" id="go" value="実行"/> <textarea id="log" style="width:96%;height:100px;"></textarea> </div> </body> </html>
ソースの量が多いのであまり多くは紹介できませんでしたが、
かなりバリエーション豊富なのが分かったと思います。