flutter 图标+段落布局实现
2020-06-07 本文已影响0人
梁典典
flutter自学交流群1102781545,欢迎提问
效果预览
![](https://img.haomeiwen.com/i3671684/d24a52d770394ef6.jpg)
创建my_drawable_start_text.dart
文件
import 'package:flutter/material.dart';
class DrawableStartText extends StatefulWidget{
final TextStyle textStyle;
final String text;
final String assetImage;
final int maxLines;
///尽可能写出图片后大概有多少字母,这样能快速计算第一行显示多少个字母(例如有20个字母 可以设置该值为12左右),默认为0
final int lettersCountOfAfterImage;
DrawableStartText({
this.textStyle,
@required this.text,
@required this.assetImage,
this.maxLines,
this.lettersCountOfAfterImage:0,
});
@override
State<StatefulWidget> createState() {
return new DrawableStartTextState();
}
}
class DrawableStartTextState extends State<DrawableStartText>{
double _textHeight;
GlobalKey rowKey=GlobalKey();
GlobalKey imageKey=GlobalKey();
String _topText="";
String _bottomText="";
Image _image;
bool _isOneShow = true; // 一行是否能显示完
@override
void initState() {
super.initState();
//计算文字的高度,根据文字的高度设定图片的高度,然后让图片自适应
TextPainter painter=new TextPainter();
if(widget.textStyle!=null) {
painter.text = TextSpan(style: widget.textStyle, text: widget.text);
}else{
painter.text = TextSpan(text: widget.text);
}
painter.maxLines=1;
painter.textDirection=TextDirection.ltr;
painter.layout();
_textHeight=painter.size.height;
//在第一帧后计算下第一行能显示多少个字母,然后将字母分成两段显示
WidgetsBinding.instance.addPostFrameCallback((callback){
_image.image.resolve(new ImageConfiguration())
.addListener(ImageStreamListener((imageInfo,synchronousCall){
//计算图片的宽高
double imgHeight = imageInfo.image.height . toDouble();
double imgWidth = imageInfo.image.width . toDouble();
//由于图片缩放了。所以根据缩放大小计算出宽图,这里没有用key去取值,是因为取出的值是空的
double scale=_textHeight/imgHeight;
double _imageWidth=imgWidth*scale;
//再用父控件的宽度减去图片的宽度就是文字显示的宽度
double parentWidth = rowKey.currentContext.findRenderObject().paintBounds.size.width;
print("父控件的宽度:${parentWidth},图片的宽度:${_imageWidth}");
double textWidth = parentWidth - _imageWidth;
// 判断一行是否能显示全部文字
int index=0;
//计算出在哪个字母时超出了显示范围
for(;index<widget.text.length;index++){
if(widget.textStyle!=null) {
painter.text = TextSpan(style: widget.textStyle, text: widget.text.substring(0,index));
}else{
painter.text = TextSpan(text: widget.text.substring(0,index));
}
painter.layout();
if(painter.size.width>textWidth){
setState(() {
_isOneShow = false;
});
break;
}
}
if(_isOneShow){
// 一行就能显示
setState(() {
_topText = widget.text;
_bottomText = null;
});
}else{
//将超出的哪个位置减掉,剩下的字母就不会超出范围了
int validIndex=index-1;
//根据计算的位置,分别截取前半部分 和后半部分显示
setState(() {
_topText= widget.text.substring(0,validIndex);
_bottomText = widget.text.substring(validIndex);
});
}
}));
});
}
@override
Widget build(BuildContext context) {
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
return new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Row(
key: rowKey,
children: <Widget>[
_image=new Image.asset(
widget.assetImage,
key:imageKey,
height:_textHeight,
fit : BoxFit.fitHeight,
),
new Text(
_topText,
style: widget.textStyle,
maxLines: 1,
),
],
),
!_isOneShow ? Text(
_bottomText,
style: widget.textStyle,
textAlign: TextAlign.left,
maxLines: widget.maxLines ==null ? defaultTextStyle.maxLines : widget.maxLines-1,
overflow: widget.maxLines ==null ? defaultTextStyle.overflow : TextOverflow.ellipsis,
) : Container(),
],
);
}
}
使用
DrawableStartText(
lettersCountOfAfterImage: info.itemshorttitle.length, // 段落文本长度
assetImage: "assets/icons/tianmao.png", // 本地图片
text: " 【三只松鼠_零食大礼包】网红美味零食小吃休闲饼干散装充饥夜宵", // 段落文本
textStyle: new TextStyle(fontSize: ScreenUtil().setSp(50),fontWeight: FontWeight.w400), // 文本样式
),