Flutter 开发实战——自定义省略后缀

直接说具体需求样式吧

一行里有三个widget,只有第一个widget内容确定,第二个widget内容由接口返回,返回什么显示什么,第三个widget,位置也由第二个确定。只显示一排,如果内容过多,widget2要省略以...可见结束。
画个图吧,清晰点,然后在给出一个具体样子。

image.png
具体栗子:
这是一个提示语:widget1: 最大发布范围
widget2:为接口返回发布范围名单,可能很长,也可能很短。当很长时,widget1、3都确定了位置,widget2尽可能的显示多的内容,然后以”…可见”文案结束。
可能是下面这样:

eg1:最大可见范围:张三、李四、王五三人可见。 ✅ (widget2 内容很少时)

eg2:最大可见范围:张三、李四、王五、赵…等26人可见。✅ (widget2 内容很多,超过了一行最大显示时)

UED效果图:

具体样式图.png

实现方式:
方式一:

Row-> widget1 -> Container(BoxConstraints 限定宽度约束)->widget2/widget3

Row(children: [
      Container(
        constraints: BoxConstraints(
            minWidth: margin,
            maxWidth: MediaQuery.of(context).size.width - margin),
        child: Text(
          str,
          style: titleStyle,
          maxLines: 1,
          overflow: TextOverflow.ellipsis,
        ),
      ),
      Text(
        endStr,
        style: StyleConstant.subtitleStyle,
      )
    ]);
复制代码
实现二:

使用系统的自带的CustomMultiChildLayout,自定义一个widget 继承自它

class MultipleChildWrapWidget extends CustomMultiChildLayout {
  MultipleChildWrapWidget({Key key, List<Widget> children})
      : super(
            key: key, children: children, delegate: MultiChildrenWidgetDelegate());
}


class MultiChildrenWidgetDelegate extends MultiChildLayoutDelegate {

  @override
  void performLayout(Size size) {
    // 一行里剩余的size
    var surplus = Size(size.width, size.height);
    // 第一个控件
    if (hasChild("former")) {
      var formerSize = layoutChild("former", BoxConstraints.loose(surplus));
      positionChild("former", Offset.zero);

      //更新剩余size
      surplus = Size(surplus.width - formerSize.width, surplus.height);
    }

    // 第二个控件
    if (hasChild("middle") && hasChild("last")) {
      // 先计算最后一个控件
      var lastSize = layoutChild("last", BoxConstraints.loose(surplus));
      // 在计算中间控件
      var middleSize = layoutChild("middle", BoxConstraints.loose(Size(surplus.width - lastSize.width, surplus.height)));

      // 放置控件
      positionChild("middle", Offset(size.width - surplus.width, 0));
      positionChild("last", Offset(size.width - surplus.width + middleSize.width, 0));

    }
  }

复制代码

使用的时候只需将它作为一个widget即可,但要注意控件的id不要写错了,前后要对应上。
使用例子:

Container(
      child: MultipleChildWrapWidget(
        children: [
          LayoutId(id: "former", child: child), // 这个id 要和 里面控件对应上
          LayoutId(id: "middle", child: child,),
          LayoutId(id: "last", child: child)
        ],
      ),
    );
复制代码

同样类似的需求

弹窗提示,最多展示两行文本,超过两行以”…可见”结束。

image.png

实现方式

最开始想用偷鸡方式实现来着,让文本就显示两行,然后第二行底部用”…可见”Text覆盖上去。
很快三下五初二干完了,搞定, 哈哈?
理想很丰满,现实很果敢啊。 一运行发现,后面直接盖一个固定的widget会有问题,可能压住了半边字,你懂的哈。

不行那就换一种吧。后来又想两行分别显示,第二行用两个widget组合来显示。 但是问题又来了,怎么确定每行显示多少文字呢?在哪个文字那里断开呢?? 这样就得一个一个字的绘制出来,太麻烦,不想这么干。 程序猿都是懒人嘛,我要找简便的方法。

既然文本超过固定的行数,会以”…”结束,那我能不能自定义让其以"...可见"结束呢?? 这不就实现了我的要求了么!! 嗯,这样很好。 于是就去看省略样式设定overflow: TextOverflow.ellipsis。 然而TextWidget系统给出的省略样式就那几种,还不能自定义。

不行,我不干,既然你这能给出那几种省略样式,就可以设置别的样式。 我继续找,你Text不行,我找其他的东西。那我自己画的方式呢,TextPainter;

  TextPainter({
    InlineSpan? text,
    TextAlign textAlign = TextAlign.start,
    TextDirection? textDirection,
    double textScaleFactor = 1.0,
    int? maxLines,
    String? ellipsis,
    Locale? locale,
    StrutStyle? strutStyle,
    TextWidthBasis textWidthBasis = TextWidthBasis.parent,
    ui.TextHeightBehavior? textHeightBehavior,
  })
复制代码

誒,这里可以把ellipsis 传进来,那我就用我自己希望的String当结尾就好了啊。
这个貌似可以。 嘿嘿 就是你了。

自定义一个widget继承自CustomPainter, 实现对应的协议即可。

class CustomTextPaintWidget extends CustomPainter {
  final String text;
  final String endStr;
  final TextStyle textStyle;
  final int maxLines;

  TextPainter _textPainter;

  CustomTextPaintWidget({this.text, this.endStr,this.textStyle, this.maxLines}) {
    _textPainter = TextPainter(
        text: TextSpan(text: text, style: textStyle),
        maxLines: maxLines,
        ellipsis: endStr,
        textDirection: TextDirection.ltr);
  }

  @override
  void paint(Canvas canvas, Size size) {
    _textPainter.layout(maxWidth: size.width);
    _textPainter.paint(canvas, Offset(0, 0));
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }

}
复制代码

使用方式如下,就是一个widget
这个也可以解决上面那个问题。

Widget CustomPaint(
      size: Size(MediaQuery.of(context).size.width - margin, 20),
      painter: CustomTextPaintWidget(
          text: str,
          endStr: endStr,
          textStyle: TextStyle,
          maxLines: 2),
    );
复制代码

完美 搞定。?

其实需求很简单,不要急,先想好在干,总会有更优的方式。

如果大佬有更好的实现样式,还望不吝赐教,小弟在此先感谢了[抱拳].

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享