一、問題背景
最近在開發(fā)直播的需求,有如圖以下聊天室彈幕的場景,一開始想的是用ListView來做,然后Container包裹Text來實(shí)現(xiàn)每一個(gè)對(duì)話。

實(shí)現(xiàn)代碼如下:
ListView.builder(
shrinkWrap: true,
controller: widget.scrollController,
itemCount: widget.messages != null ? widget.messages.length : 0,
itemBuilder: (BuildContext context, int index) {
EMMessage message = widget.messages[index];
EMTextMessageBody messageBody = message.body;
return Container(
margin: EdgeInsets.only(top: 5, left: 15, right: 75),
child: Text(
"${messageBody.content}",
style:
TextStyle(color: Color(0xFF00B4E6), fontSize: 14),
),
padding:
EdgeInsets.symmetric(vertical: 5, horizontal: 8),
decoration: BoxDecoration(
color: ThemeColors.live_background,
borderRadius: BorderRadius.circular(15)),
);
})
結(jié)果卻不是我預(yù)期的效果,我發(fā)現(xiàn)這么寫每一個(gè)對(duì)話都會(huì)撐滿屏幕的寬度,不能根據(jù)文本的長度來進(jìn)行自適應(yīng)。

二、嘗試解決
進(jìn)過網(wǎng)上查閱資料,發(fā)現(xiàn)只要在Container外層套一個(gè)Row,然后設(shè)置mainAxisSize屬性為 MainAxisSize.min,如下代碼所示
ListView.builder(
shrinkWrap: true,
controller: widget.scrollController,
itemCount: widget.messages != null ? widget.messages.length : 0,
itemBuilder: (BuildContext context, int index) {
EMMessage message = widget.messages[index];
EMTextMessageBody messageBody = message.body;
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(top: 5, left: 15, right: 75),
child: Text(
"${messageBody.content}",
style:
TextStyle(color: Color(0xFF00B4E6), fontSize: 14),
),
padding:
EdgeInsets.symmetric(vertical: 5, horizontal: 8),
decoration: BoxDecoration(
color: ThemeColors.live_background,
borderRadius: BorderRadius.circular(15)),
),
]);
})
發(fā)現(xiàn)這樣確實(shí)可以根據(jù)文本自適應(yīng)了,但是如果文案過長會(huì)有另一個(gè)問題,會(huì)導(dǎo)致寬度溢出問題,文本不會(huì)自動(dòng)換行

然后又想著是不是給Container加上一層Expend就不會(huì)寬度溢出了,代碼如下:
ListView.builder(
shrinkWrap: true,
controller: widget.scrollController,
itemCount: widget.messages != null ? widget.messages.length : 0,
itemBuilder: (BuildContext context, int index) {
EMMessage message = widget.messages[index];
EMTextMessageBody messageBody = message.body;
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(top: 5, left: 15, right: 75),
child: Text(
"${messageBody.content}",
style:
TextStyle(color: Color(0xFF00B4E6), fontSize: 14),
),
padding:
EdgeInsets.symmetric(vertical: 5, horizontal: 8),
decoration: BoxDecoration(
color: ThemeColors.live_background,
borderRadius: BorderRadius.circular(15)),
),
),
]);
})

是不會(huì)寬度溢出了,但是其余的文本又不隨文本寬度自適應(yīng)了,這可咋整?后來我發(fā)現(xiàn)了最終的解決方案,不用加Expand,只需要把套在item外層的Row改成Column即可,最終代碼:
ListView.builder(
shrinkWrap: true,
controller: widget.scrollController,
itemCount: widget.messages != null ? widget.messages.length : 0,
itemBuilder: (BuildContext context, int index) {
EMMessage message = widget.messages[index];
EMTextMessageBody messageBody = message.body;
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(top: 5, left: 15, right: 75),
child: Text(
"${messageBody.content}",
style:
TextStyle(color: Color(0xFF00B4E6), fontSize: 14),
),
padding:
EdgeInsets.symmetric(vertical: 5, horizontal: 8),
decoration: BoxDecoration(
color: ThemeColors.live_background,
borderRadius: BorderRadius.circular(15)),
),
]);
})

三、問題產(chǎn)生原因
那回歸問題的本質(zhì),為什么ListView里的Item Container是自動(dòng)撐滿和父視圖一樣寬的呢?而不是像我們想的一樣跟隨子視圖寬高進(jìn)行自適應(yīng)的。
后來我查閱了Flutter的約束篇文章,找到了答案,在彈性視圖Row、Column以及滾動(dòng)區(qū)域的子視圖ListView、ScrollView內(nèi)的子視圖默認(rèn)是無邊界約束的,默認(rèn)的寬高都是,所以ListView里的Item Container是自動(dòng)撐滿和父視圖一樣寬。
