前一天的文章30天Flutter手滑系列 - 聊天室開發(Chat Room)(7),完成了TextField
和IconButton
的連動,今天來設計如何把訊息填入主畫面中。
首先來到ChatPageState
,宣告一個陣列,準備用來儲存每次輸入的訊息內容。
class ChatPageState extends State<ChatPage> {
final TextEditingController _chatController = new TextEditingController();
final List<Widget> _message = []; // 建立一個空陣列
...
}
然後到原本預留的Expanded
內,新增一個ListView
,將這個陣列綁定ListView
上
Expanded(
child: ListView.builder(
padding: new EdgeInsets.all(8.0),
itemBuilder: (context, index) => _messages[index],
itemCount: _messages.length,
),
)
再來我們需要透過setState
,把每次訊息輸入後的值存入這個陣列,使其能夠顯示在畫面上。
void _submitText(String text) {
_chatController.clear(); // 清空controller資料
setState(() {
_messages.insert(0, Container(child: Text(text))); // 把文字存入陣列0的位置
});
}
到目前為止,我們來看一下效果。
可以看到有兩個明顯問題:
- 訊息應該由下往上
- 一般來說,自己送出的訊息應該靠畫面右方。
第1點可以在ListView
內加入reverse: true
。
Expanded(
child: ListView.builder(
padding: new EdgeInsets.all(8.0),
reverse: true, // 加入reverse,讓它反轉
itemBuilder: (context, index) => _messages[index],
itemCount: _messages.length,
),
)
第2點可以在Text
外層包一個Container
,並用alignment: Alignment.centerRight
,讓他靠右對齊。
_messages.insert(0, Container(child: Text(text), alignment: Alignment.centerRight));
修正後如下圖
在軟體開發過程中,如果是複雜的UI,很常會被設計成獨立的component
,在這個APP中的訊息就是很單純的UI(指沒有邏輯行為),我們來將其模組化。
首先在/lib/
下,建立一個components
資料夾,並且新增一個messageBox.dart
的檔案。
為了放置頭像在訊息右邊,我們用Row
去排列,因此原先在Container
的alignment
就可以拿掉了。
要讓Row
內的children都靠右,需要加入
mainAxisAlignment: MainAxisAlignment.end
然後再用一個Flexible
包裝訊息長度,使其可以根據內容長度去彈性延伸長度。
在Flexible
和Text
之間再加入一個Container
用來調整其樣式。
在Text
中,為了怕訊息太長爆掉,可以加入overflow
和maxLines
overflow: TextOverflow.ellipsis,
maxLines: 5,
小提示
在List
、Column
中,若要讓Text
的換行起作用,需要加入Expanded
或Flexible
包裝
完整程式碼如下
import 'package:flutter/material.dart';
class MessageBox extends StatelessWidget {
final String text;
MessageBox({Key key, this.text}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Flexible(
child: Container(
color: Colors.pink,
padding: EdgeInsets.all(10.0),
child: Text(text,
overflow: TextOverflow.ellipsis,
maxLines: 5,
style: TextStyle(fontSize: 18.0, color: Colors.white)),
),
),
Icon(Icons.person, size: 32)
],
),
);
}
}
基本的對話介面已經完成了,剩下就是美化它或是加強功能。明天要回到頭痛的Firebase
部分,希望能在完賽前把真正的即時訊息完成。