美文网首页
Flutter ListView里的Item不能自适应的问题

Flutter ListView里的Item不能自适应的问题

作者: RmondJone | 来源:发表于2021-09-18 22:37 被阅读0次

    一、问题背景

    最近在开发直播的需求,有如图以下聊天室弹幕的场景,一开始想的是用ListView来做,然后Container包裹Text来实现每一个对话。



    实现代码如下:

    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)),
        );
      })
    

    结果却不是我预期的效果,我发现这么写每一个对话都会撑满屏幕的宽度,不能根据文本的长度来进行自适应。


    二、尝试解决

    进过网上查阅资料,发现只要在Container外层套一个Row,然后设置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)),
            ),
          ]);
      })
    

    发现这样确实可以根据文本自适应了,但是如果文案过长会有另一个问题,会导致宽度溢出问题,文本不会自动换行


    然后又想着是不是给Container加上一层Expend就不会宽度溢出了,代码如下:

    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)),
              ),
            ),
          ]);
      })
    

    是不会宽度溢出了,但是其余的文本又不随文本宽度自适应了,这可咋整?后来我发现了最终的解决方案,不用加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)),
            ),
          ]);
      })
    

    三、问题产生原因

    那回归问题的本质,为什么ListView里的Item Container是自动撑满和父视图一样宽的呢?而不是像我们想的一样跟随子视图宽高进行自适应的。

    后来我查阅了Flutter的约束篇文章,找到了答案,在弹性视图Row、Column以及滚动区域的子视图ListView、ScrollView内的子视图默认是无边界约束的,默认的宽高都是\color{red}{double.infinity},所以ListView里的Item Container是自动撑满和父视图一样宽。

    相关文章

      网友评论

          本文标题:Flutter ListView里的Item不能自适应的问题

          本文链接:https://www.haomeiwen.com/subject/dnaygltx.html