AI LINE Bot練功坊-L9 Message Type (3) Flex Message === ## 匯入函式 ```python from linebot.v3.messaging import ( FlexMessage, FlexBubble, FlexImage, FlexMessage, FlexBox, FlexText, FlexIcon, FlexButton, FlexSeparator, ) ``` # Flex Message 彈性訊息 LINE BOT 可以使用 Flex Message ( 彈性樣板訊息 ) 發送客製化的選單訊息,Flex Message 使用網頁 CSS3 的 Flex 語法,可以設計較豐富且多樣性的按鈕版型 而且不像 Template 在電腦版就無法運作,Flex Message 支援 「電腦版」 ## Flex Message 結構 Flex Message 是由三層結構組成 **Container 容器 -> Block 區塊 -> Component 組件** 內容及圖片參考 [官方網站](https://developers.line.biz/en/docs/messaging-api/flex-message-elements/)。 ![image](https://hackmd.io/_uploads/Byy3CHpyA.png) >Reference:https://developers.line.biz/en/docs/messaging-api/using-flex-messages/ ### **Container 容器** 容器是 Flex Message 的最外層結構,有兩種類型可選 | 1.Bubble | 2.Carousel | |:--------------------------------------------------:|:--------------------------------------------------:| | 是包含一個訊息框的容器。 | 是包含多個 Bubble 的容器,可以橫向滑動 | | ![image](https://hackmd.io/_uploads/BkpIvayg0.png) | ![image](https://hackmd.io/_uploads/rkPQwTyeA.png) | ### **Block 區塊** Block區塊是組成 Bubble 的結構,分為四個部分 ![image](https://hackmd.io/_uploads/rJNI3C1g0.png) Header: 顯示標題的區塊 Hero: 顯示主要圖片的區塊 Body: 顯示主要內容的區塊 Footer: 顯示按鈕或補充訊息的區塊 ### **Component 組件** 組件是 Flex Message 的最基本結構,類型很多如下 1. Box: 定義介面的佈局,裡面可以包含其它組件 2. Button: 按鈕 ![image](https://hackmd.io/_uploads/SJIv2RklA.png) 3. Image: 圖片 ![image](https://hackmd.io/_uploads/rkPu3AkeR.png) 4. Icon: 文字前的圖標 ![image](https://hackmd.io/_uploads/ryYFhRkgC.png) 5. Text: 文字 ![image](https://hackmd.io/_uploads/rJkqnC1gR.png) 6. Span: 單行文字,可以指定不同的顏色、大小、粗細 ![image](https://hackmd.io/_uploads/HJ5a301e0.png) 7. Separator: 分隔線,可製作水平或垂直的分隔線 ![image](https://hackmd.io/_uploads/S1yNa0JlR.png) 8. Filler: 可以在組件間插入空白區塊 ![image](https://hackmd.io/_uploads/HJAkpRJgC.png) >Reference:https://developers.line.biz/en/docs/messaging-api/flex-message-elements/ ### **Component 屬性** **Bubble** * direction 內容排列方向 * ltr 從左至右 * rtl 從右至左 * size 調整 bubble 大小 * giga * mega * kilo * hecto * deca * micro * nano * Action Type * postback * uri * message * datetimepicker --- **Header、Hero、Body、Footer** * backgroundColor 背景顏色 * seperator 分隔線 * True * False * seperatorColor 分隔線顏色 --- **Box** * layout * vertical 垂直排列 box, button, image, text, separator, and filler * horizontal 水平排列 box, button, image, text, separator, and filler * baseline 水平排列 icon, text, and filler --- #### baseline 與 horizontal 不同之處 baseline 中的元件按同一基線垂直對齊,這意味著所有子元件都使用相同的基線,無論字型大小。 圖示元件的基線是圖示影象的底部。 ![baseline.7a7956f9](https://hackmd.io/_uploads/BJ-dsUHWA.png) baseline 中的元件不能套用 *gravity* 和 *offsetBottom* 屬性 * position * relative 相對配置 可以設定父層元素為基準元素作絕對位移。 * absolute 絕對配置 以「自己原本顯示的位置為基準位置」來指定上下左右的偏移,且區塊原本的空間仍會保留不會消失。 * flex 如果元件的位置屬性設定為相對(relative),則元件的寬度和高度由元件的 flex 屬性決定。 #### horizontal box 中的寬度分配 假設一個 horizontal box 有兩個元件,一個將 flex 屬性設定為 2,另一個設定為 3。 然後將可用寬度(horizontal box 的寬度)以二比三的比例劃分,並分配給每個元件。 ![flexSample1.aa211fd0](https://hackmd.io/_uploads/B1tQ3kIWA.png) --- #### Vertical box 中的高度分配 假設一個 horizontal box 有兩個 vertical boxes,第一個 box 佔用五行的文字,第二個 box 根據其 flex 屬性的值,以 2 : 3 的比例分配給兩個文字元件。 ![line](https://hackmd.io/_uploads/ryzVklI-C.png) * spacing 元件之間的間距 本示例 Flex Message 有一個 horizontal box,其中三個 vertical boxes 作為子元件,間隔均為(md)。 ![1](https://hackmd.io/_uploads/ByJ0cOIbA.png) * margin 元件之間的邊距 (邊距屬性優先於間距屬性) 本示例 Flex Message 有一個 horizontal box,其中三個 vertical boxes 作為子元件,間隔均為(md),第三個 vertical box 邊距屬性為 xxl。 ![Unknown](https://hackmd.io/_uploads/HJkvkKIZR.png) * width * height * maxWidth * maxHeight * backgroundColor * borderWidth * borderColor * cornerRadius * justifyContent 在父階層中設置幫助安排內容 * flex-start 這將從起點開始對所有項目進行排列。如果是水平,則將基於 bubble 給出的方向: ltr (從左至右)或 rtl (從右至左);反之若是垂直,則所有項目將從上至下進行排列。 * center 將所有項目排列在中心點。 * flex-end 這將從末端開始對所有項目進行排列。如果是水平,則將基於 bubble 給出的方向: ltr 從左至右)或 rtl (從右至左);反之若是垂直,則所有項目將從下至上進行排列。 * space-between 第一個與最後一個項目貼齊左右側的佈局,其餘項目平均分配到顯示畫面的中心。 * space-around 將每個項目之間的距離均勻地分配。 * space-evenly 平均劃分每個項目與訊息佈局的距離來進行排列。 #### **layout: vertical** ![截圖 2024-04-24 00.47.36](https://hackmd.io/_uploads/H1tSIwHWR.png) --- #### **layout: horizontal & direction: ltr** ![截圖 2024-04-24 00.47.21](https://hackmd.io/_uploads/Hk4U8wrZ0.png) * alignItems 指定父階層中的項目更換排序方向 * flex-start 如果父階層水平排列,則所有項目將自上而下;如果父母垂直排列,則所有項目將從一開始(取決於 Bubble 的方向)。 * center 將所有項目排列在水平和垂直方向的中心點。 * flex-end 如果將父階層水平排列,則所有項目將從下至上;並且如果將父接成垂直排列,則所有項目將從末端排列(取決於 Bubble 的方向)。 #### **layout: vertical** ![截圖 2024-04-24 00.50.18](https://hackmd.io/_uploads/SJglvvHbR.png) --- #### **layout: horizontal & direction: ltr** ![截圖 2024-04-24 00.50.08](https://hackmd.io/_uploads/rycewwHWR.png) * Offset 偏移量 * offsetTop 將元件從元件原始位置的頂部邊緣向下移動。 * offsetBottom 將元件從元件原始位置的底部邊緣向上移動。 * offsetStart 將元件從文字開始的地方移開。 如果 bubble 的方向是 LTR,則向右移動。 如果是 RTL,則向左移動。 * offsetEnd 遠離文字結束的地方。 如果 bubble 的方向是 LTR,則向左移動。 如果是 RTL,則向右移動。 ![offset1](https://hackmd.io/_uploads/Bk4OPK8bR.png) #### Offset when position is relative ![offset2](https://hackmd.io/_uploads/r1ScwYUZC.png) | Property | Value | | -------- | ------ | | position | relative| | offsetTop| 10px | | offStart | 40px | --- #### Offset when position is absolute ![offset3](https://hackmd.io/_uploads/HkFZ5Yvb0.png) | Property | Value | | --------- | -------- | | position | absolute | | offsetTop | 10px | | offBottom | 20px | | offStart | 40px | | offEnd | 80px | * Padding 元件內所有內容與元件自身的邊界 * paddingAll * paddingTop * paddingBottom * paddingStart * paddingEnd ![padding](https://hackmd.io/_uploads/Bk-MWq8-0.png) | Property | Value | | --------- | -------- | | paddingTop | 20px | | paddingAll | 80px | | paddingStart| 40px | * Background Type * linearGradient 線性漸變背景 * angle * startColor * endColor * centerColor * centerPosition ``` { "type": "bubble", "body": { "type": "box", "layout": "vertical", "contents": [], "background": { "type": "linearGradient", "angle": "0deg", "startColor": "#ff0000", "endColor": "#0000ff" }, "height": "200px" } } ``` #### Linear gradient at 45 degrees (Bottom-left to top-right) ![45d](https://hackmd.io/_uploads/BJLto9IWR.png) #### Linear gradient at 90 degrees (Left to right) ![90d](https://hackmd.io/_uploads/BJ_pi9Ib0.png) #### Linear gradient at 180 degrees (Top to bottom) ![180d](https://hackmd.io/_uploads/r1rCo98ZA.png) * Action Type --- **Button** * flex * position * margin * height * style * link * primary * secondary * color * gravity #### 使用 gravity 屬性,垂直對齊 text, image, 或 button ![gravity](https://hackmd.io/_uploads/rJ970c8WC.png) * scaling 如果縮放屬性設定為 true,您可以根據 LINE 應用程式的字型大小設定自動縮放字型大小和圖示大小。 * adjustMode 如果您為按鈕和文字元件的 adjustMode 屬性 shrink-to-fit,文字的字型大小將自動縮小以適應。 ![stf](https://hackmd.io/_uploads/rJ_E5KDW0.png) * Offset * Action --- **Image** * flex * position * url * margin * align #### 使用 align 屬性,水平對齊 text, 或 image ![ho](https://hackmd.io/_uploads/rJGLctPZA.png) * gravity * size * aspectRatio 圖片長寬比 * aspectMode * cover * fit * backgroundColor * animated * True * False * Offset * Action --- **Icon** * position * url * margin * size * scaling * aspectRatio * Offset --- **Text** * text * flex * margin * size * lineSpacing 行距 * color * weight * regular * bold * style * normal * italic * decoration * none * underline 底線 * line-through 刪除線 * position * align * gravity * wrap 過長的文字自動換至下一行 * True * False * scaling * maxLines * adjustMode * Offset * Action Type --- **Span** * text * size * color * weight * style * decoration --- **Separator** * margin * color --- **Filter** * flex >Reference:https://developers.line.biz/en/docs/messaging-api/flex-message-layout/ ## Flex Message 設計(flex-simulator) 官方有推出輔助工具 [Flex-Simulator](https://developers.line.biz/flex-simulator/) ,可以直接在網頁上製作 Flex Message 需登入LINE Developers 帳戶 ![image](https://hackmd.io/_uploads/Bk7bMtTJA.png) 設計工具主要分成三個區塊: * 左邊的區塊:預覽畫面 ( 傳送到 LINE 的訊息長相 ) * 中間的區塊:Flex Message 的樹狀清單結構 * 右邊的區塊:點擊中間區塊清單裡的元件,出現對應可以修改的屬性或參數 ![image](https://hackmd.io/_uploads/rJ5eFTylC.png =50%x) LINE官方也有提供的一些免費模板,可以根據需求改寫裡面的參數,設計成理想中的訊息 ### 製作 Flex 的步驟: 你可以點右上角的「Showcase」從官方提供的模板修改寫裡面的參數,改成想要得樣式,再匯出 如果想要從零開始做的話: 1. 點擊網頁右上角的「NEW」,選擇Container建立一個包含訊息框的 Bubble or Carousel類型 2. 點選想要修改的Block 區塊 3. 點擊中間清單的元件後,就能從上方的「+」號,加入額外的元件 ![image](https://hackmd.io/_uploads/S1X-nT1lC.png) 如:設定標題文字及背景顏色、新增圖片(設定圖片連結與大小)、新增文字(設定字體大小、粗細和對齊方式)、新增平行線(新增分隔線,並設定邊距)、新增按鈕(設定連結及按鈕樣式、添加連結到網站、或撥打電話 ### 測試 Flex Message 點擊右上方的 Send 按鈕後,會出現 Register destination 的按鈕,繼續點擊後會出現 QRCode,掃描 QRCode 加入好友就能測試 ![image](https://hackmd.io/_uploads/ByGMuPtxR.png) ![image](https://hackmd.io/_uploads/rk39g0ygC.png =30%x) ### 用Python 傳 Flex Message 首先先將官方模擬器的資料複製,點選右上角的複製JSON內容,編寫完基本指令後在「contents」之處將複製的JSON內容貼上 ## Flex Message 範例 ![image](https://hackmd.io/_uploads/Bydu001e0.png =80%x) 首先,程式碼建立一個 URL,這個 URL 是用來指向一個圖片資源的 FlexBubble()是一個物件,其屬性包括 direction(排列方向)、hero(主要圖像)、body(內容區域)、footer(底部區域) * contents 是用來容納各種 Flex 元件的容器 * hero:主圖像是一張圖片,其中包含 URL、尺寸、比例、顯示模式等屬性 * body:內容區域包含了標題、評分、詳細資訊等內容,使用了不同的 Flex 元件來組合顯示 * footer:底部區域包含了一個連結到電話的按鈕和一個連結到網站的按鈕,使用了 FlexButton 元件 最後,使用 line_bot_api.reply_message 函式回覆訊息,設定了回覆的內容為一個 FlexMessage,其中的內容就是前面建立的 FlexBubble 物件 **Python程式碼** ```python url = request.url_root + '/static/Logo.jpg' url = url.replace("http", "https") app.logger.info("url=" + url) bubble = FlexBubble( direction='ltr', hero=FlexImage( url=url, size='full', aspect_ratio='20:13', aspect_mode='cover', action=URIAction(uri='https://www.facebook.com/NTUEBIGDATAEDU', label='label') ), body=FlexBox( layout='vertical', contents=[ # title FlexText(text='教育大數據', weight='bold', size='xl'), # review FlexBox( layout='baseline', margin='md', contents=[ FlexIcon(size='sm', url="https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"), FlexIcon(size='sm', url="https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"), FlexIcon(size='sm', url="https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"), FlexIcon(size='sm', url="https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"), FlexIcon(size='sm', url="https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"), FlexText(text='5.0', size='sm', color='#999999', margin='md', flex=0) ] ), # info FlexBox( layout='vertical', margin='lg', spacing='sm', contents=[ FlexBox( layout='baseline', spacing='sm', contents=[ FlexText( text='Place', color='#aaaaaa', size='sm', flex=1 ), FlexText( text='Da\'an District, Taipei ', wrap=True, color='#666666', size='sm', flex=5 ) ], ), FlexBox( layout='baseline', spacing='sm', contents=[ FlexText( text='Time', color='#aaaaaa', size='sm', flex=1 ), FlexText( text="10:00 - 23:00", wrap=True, color='#666666', size='sm', flex=5, ), ], ), ], ) ], ), footer=FlexBox( layout='vertical', spacing='sm', contents=[ # callAction FlexButton( style='link', height='sm', action=URIAction(label='CALL', uri='tel:000000'), ), # separator FlexSeparator(), # websiteAction FlexButton( style='link', height='sm', action=URIAction(label='WEBSITE', uri='https://www.facebook.com/NTUEBIGDATAEDU') ) ] ), ) line_bot_api.reply_message( ReplyMessageRequest( reply_token=event.reply_token, messages=[FlexMessage(alt_text="hello", contents=bubble)] ) ) ``` >Reference:https://developers.line.biz/en/reference/messaging-api/#flex-message Youtube 課程影片 --- <iframe width="560" height="315" src="https://www.youtube.com/embed/8p-uWpy-Uh4?si=AmQ7pvG7yvvs7dTq" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> {%hackmd @ntuebigdata/about %} ## 相關教材連結 <div style="display: flex; justify-content:space-between;"> <div> <a class="btn btn-warning" href="https://hackmd.io/@ntuebigdata/message-type-2-template-message" style="color:white;width:300px;text-overflow:ellipsis;overflow:hidden">◀◀◀ L08 Message Type(2) Template Message ◀◀◀</a> </div> <div> <a class="btn btn-info" href="https://hackmd.io/@ntuebigdata/message-type-4-imagemap-message" style="color:white;width:300px;text-overflow:ellipsis;overflow:hidden">▶▶▶ L10 Message Type(4) Imagemap Message ▶▶▶</a> </div> </div>