直接说具体需求样式吧
一行里有三个widget,只有第一个widget内容确定,第二个widget内容由接口返回,返回什么显示什么,第三个widget,位置也由第二个确定。只显示一排,如果内容过多,widget2要省略以...可见
结束。
画个图吧,清晰点,然后在给出一个具体样子。
具体栗子:
这是一个提示语:widget1: 最大发布范围
widget2:为接口返回发布范围名单,可能很长,也可能很短。当很长时,widget1、3都确定了位置,widget2尽可能的显示多的内容,然后以”…可见”文案结束。
可能是下面这样:
eg1:最大可见范围:张三、李四、王五三人可见。 ✅ (widget2 内容很少时)
eg2:最大可见范围:张三、李四、王五、赵…等26人可见。✅ (widget2 内容很多,超过了一行最大显示时)
UED效果图:
实现方式:
方式一:
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)
],
),
);
复制代码
同样类似的需求
弹窗提示,最多展示两行文本,超过两行以”…可见”结束。
实现方式
最开始想用偷鸡方式实现来着,让文本就显示两行,然后第二行底部用”…可见”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),
);
复制代码
完美 搞定。?
其实需求很简单,不要急,先想好在干,总会有更优的方式。
如果大佬有更好的实现样式,还望不吝赐教,小弟在此先感谢了[抱拳].