flutter可伸缩文本区域实现

3,119 阅读3分钟

在文本模块的开发中,有一个常见的功能,那就是当该文本超过n行,则截取前n行进行展示,并在末尾加上“更多”按钮进行提示。点击后,展开显示全部文本,再次点击,则收缩起来。

百文不如一见,所以图片伺候。如下图中箭头指向的区域:

flutter stretchable text view

再来一张动态的,妥妥的:

Flutter点击伸展或收缩

ok,问题描述清楚,可以开始开发设计了。。。

此处,省略好几天的苦思冥想、数亿脑细胞的过劳死亡。。。

思路

听说,思路决定出路...

所以,我们先来讲讲实现的思路。

多行文本是由一行一行的文本组成的,没有条件进行多行文本的处理,但是我们可以进行单行文本的处理,最后把他们拼接到一起,这样便可以实现我们想要的效果。如何获取单行文本呢,大致流程如下:

  • 步骤一:设置一个只允许一行的容器container
  • 步骤二:读取文本区域的宽度containerW
  • 步骤三:把文本text往该容器container中填入,读取其宽度textW
  • 步骤四:如果textW>containerW,把text最后一个字符去掉,重复步骤三;否则则完成

用图片示意一下,可能更加清晰。下图中绿色框框代表容器container,黄色数字为文本。

flutter_stretchable_text_view

最后一行,由于需要在末尾添加其他的文本等,略有些不同,具体可看下图。

flutter_stretchable_text_view

开始编程

直接上代码:

String getOneLineText (String text, double containerW, TextPainter painter, {bool isLast = false}) {
    int i = 1;
    for (;i <= text.length; i++) {
      painter.text = this.createTextSpan(text.substring(0, i), isLast);
      painter.layout();
      if(painter.size.width > containerW){
        return text.substring(0, i - 1);
      }
    }
    return text;
  }

看过上述的思路描述,看这段代码应该不难,getOneLineText的功能就是截取刚刚好填充满一行的文本。isLast参数表示是否是最后一行,正如上面说的,最后一行和正常行,逻辑略有不同。而其差异提现在createTextSpan中,所以,接下来看看createTextSpan的代码:

TextSpan createTextSpan (String text, bool isLast) {
    if (isLast) { // 最后一行
      return TextSpan(
        text: text + '${widget.suffix}   ', // widget.suffix=...
        style: widget.textStyle,
        children: [
          widget.spreadBtn??this.createSpreadBtn() // 其实就是“更多”,可以简单理解,其等同于:TextSpan(text: '更多',)
        ]
      );
    } else {
      return TextSpan(
        text: text,
        style: widget.textStyle
      );
    }
  }

上述,便是收缩状态下的代码实现。而展开状态下,其实也是大同小异。

  • 收缩状态,假设展示n行,重复n次上面逻辑,然后记得最后一行传参有点不一样
  • 展开状态,重复上面逻辑,直到全部文本处理完成

当然,这看起来是两个遍历循环,但是其有很多雷同的地方,所以其实一个循环就可以解决了。

彩蛋

如果看完上面的讲解,还有疑问,或者不知道怎么实现。没关系,我还有源码,双手奉上,哈哈哈...

码字不易,看官如果还满意,麻烦给个赞和star!