來吧!Flutter(14) — 訊息對話框

Andy Lu
Flutter Taipei
Published in
7 min readNov 30, 2020

--

即時通訊是大部分的人最常使用的 App 之一。在這些 App 當中,經常會使用對話框的圖示來表示一則訊息,那麼,我們該如何用 Flutter 來產生這訊息對話框呢?

第一部分:ListView

Message Entity

第一步,我們先設計Message Entity。

在這個 Message Entity 中,有兩個屬性,一個為 content 用來存放訊息的內容,另一個為 isMe 用來表示是否為自己發送的訊息,若為自己發送的訊息,則顯示於右方,否則顯示於左方。

第二步,填入假資料。

ListView

第三步,利用 ListView 來產生顯示的訊息列表。

為了呈現我的訊息顯示在右側,其他人的訊息顯示在左側,我先利用 ContainerText 包起來,並依照 isMe的值來決定 alignment 的值。

到目前為止,已經完成顯示訊息,並且依照訊息的所有者顯示於相對應的位置。

第二部分:Container + BoxDecoration

接者,我們希望能夠將每一個訊息都填上顏色,每個訊息框都有圓角。

如下圖:

先回顧一下訊息是怎麼繪製的:

  • 利用 Container 將 Text 包起來,並且依照 isMe 來決定 Text 的位置。
  • 因為沒有設定外圍的 Container 寬度,所以 Container 的寬度是螢幕的寬度,所以如果直接在 Container 設定顏色,則會整個寬度都被填滿顏色。如下圖:

那麼,該如何將 Text 外面加上一層外框呢?

方法: 在 Text 外面加上一層 Container ,並且設定其寬度。

設定內部 Container :

  • 寬度設定為畫面寬度的一半: width: MediaQuery.of(context).size.width/2
  • 利用 BoxDecoration 設定填滿的顏色,以及圓角。

第三部分:CustomPainter

在第二部分,使用 Container 加上 BoxDecoration 就可以繪製出一個具有圓角的訊息框。

如果希望能夠替每一個對話框加上一個小角,讓訊息框更美觀,如下圖:

Step1:新建繼承 CustomPainter 的類別

  • 在 CustomPainter 中,有兩個方法需要實作:
  1. paint(Canvas canvas, Size size) :用來描述要如何繪製。
  2. shouldRepaint(CustomPainter oldDelegate) :用來決定是否需要重繪。

Step2:將預計要繪製的樣式分割如下:

  1. 紅色虛線框起來的部分:圓角對話框。
  2. 綠色虛線框起來的部分:對話框的角,寬度為 10.0 px。

Step2–1:圓角對話框

  • paint 方法中,第一的參數 Canvas 是用來繪製圖形重要的參數,裡面包含了許多繪製的方法。
  1. 利用 Canvas 的 方法 drawRRect 來繪製圓角長方形。
  • 在 drawRRect 方法中,需要帶入兩個參數:RRect 以及 Paint。

→ RRect 是圖形的樣子,Paint 是圖形的風格。

  1. 利用 RRect 類中 fromLTRBAndCorners 建構子來設定圓角長方形的大小,這邊需要注意的是,因為是實際繪製的位置,由於綠色部分寬度為 10.0 px ,所以我們的圖形的最左側為 10.0。最右側則為 size.width
  2. fromLTRBAndCorners 預設的角落都是沒有圓角的,所以我們可以針對需求設定圓角的半徑,這邊我對每一個角落都設定半徑為 10.0 的圓角。

Step2–2:對話框左側的角。

  • 將左側角各個點標示如上,我打算將角繪製在高度三分之一的位置,並且其高度為 10.0 px。
  • 利用 Path ,我們可以按照需求繪製所需要的圖形。
  1. path.moveTo 將繪製點移動到 (0, 1/3 的高度)
  2. path.lineTo 繪製一條直線到 (10.0, 1/3 的高度)
  3. path.lineTo 繪製一條直線到 (10.0, 1/3 的高度 + 10.0)
  4. canvas.clipPath(path) 將 Canvas 裁減其他的區域 (只保留這個區域)
  • 接者,利用 canvas.drawRect 填滿左側區域。
  • drawRect 會與 clipPath 產生出一個角。

Step 3:將內部 Container 用 CustomPaint 包起來

  • 利用 CustomPaint 將 Container 包起來,並且將 ChatBubble() 設為 painter 的參數。
  • CustomPaint 會將子 Widget 的資訊傳入 ChatBubble 中,所以在 ChatBubble 就能取得其尺寸,並繪製於指定的位置。
  • 眼尖的朋友應該有發現,右邊的對話框的角應該是在右邊而不是在左邊,這個部分讓各位朋友想想看該怎麼處理。

小結

  1. 如果要產生一個訊息列表,我們可以使用 ListView 來建立。利用 ListView.builder 我們可以將所需要繪製的內容填寫在 itemBuilder 中,ListView 就會依照每一個 index 去取得相對應的資料填入。
  2. 要替 Text 加上外框,我們可以使用 Container 包在 Text 的外面,接者在 Container 內部設定 decoration ,如此就可以加上簡單的外框。
  3. 如果需要較為複雜的外框,我們可以利用 CustomPainter 類,繼承 CustomPainter 之後,我們可以覆寫 paint 方法來繪製我們預期的樣子。

謝謝收看

Github: https://github.com/andyludeveloper/flutter_chat_bubble_example

--

--

Andy Lu
Flutter Taipei

Android/Flutter developer, Kotlin Expert, like to learn and share.