Flutter ListView里的Item不能自適應(yīng)的問題

一、問題背景

最近在開發(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)的寬高都是\color{red}{double.infinity},所以ListView里的Item Container是自動(dòng)撐滿和父視圖一樣寬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容