Flutter以图片开头的Text-----DrawableStartText

hello,大家好,今天为大家介绍一个小控件,就是以图片开始的Text;如果你的文字需要多行显示,并且在开头的位置要能添加图片。不妨试试这个控件,图片会自适应文字的高度来显示;

安卓原生的TextView就自带drawableLeft等,使用很简单,到Flutter就得自己想办法了,这个控件以前帮别人写的,现在贡献出来,大家再也不用去为这些小控件去发愁,去查找了;老规矩,还是先看图,看一看图就知道是不是自己想要的了

这是仿天猫淘宝商品简述示例,还是先照顾快速开发的小伙伴,先看看怎么去使用控件呢

Usage

第一步:添加以下代码到你的 pubspec.yaml 文件

dependencies:
  drawablestarttext: ^0.1.1

第二步:导包,复制下面代码到你要使用的文件下

import 'package:drawablestarttext/drawablestarttext.dart';

第三步:写你的业务代码(以下为我写的示例代码)

import 'package:flutter/material.dart';
import 'package:drawablestarttext/drawablestarttext.dart';

class DrawableStartTextDemo extends StatelessWidget{
  @override
  Widget build(BuildContext context) {

    return new Scaffold(
      appBar: new AppBar(
        title: new Text("DrawableStartText"),
      ),
      body: new Center(
        child: new Container(
          child: new DrawableStartText(
            assetImage: "images/tianmao.jpg",
            text: " 莫顿 全自动感应壁挂式酒精喷雾式手消毒器 手消毒机杀菌净手器",
            textStyle: new TextStyle(fontSize: 17.0),
          ),
        ),
      ),
    );
  }
}

大家只需要设置要显示的文字,文字的样式,和要显示的图片即可,这样demo已经可以跑起来了,还有一个变量maxLines,用来设置显示多少行,使用很简单,就不再赘述了,下面我们看看怎么实现的

源码

我是将文字分开显示的  也就是说在2个Text显示的,那怎么去截取2段文字呢,这就要取决于图片的宽度了,但是图片的长宽比例不一样,缩放后宽度也不一样,所以我们第一步要做的就是缩放图片,并计算图片宽度

 @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;
  }

↑↑↑上面的代码是计算文字的高度,文字有多高,我们将图片就设置多高

↓↓↓将文字的高度设置成图片的高度,还要设置下fit 参数,让他适应高度 BoxFit.fitHeight, 它会让图片等比例缩放来适应高度,下来我们看下build方法怎么设置图片的,顺便看下2个Text控件的摆放

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

在第一次build之后,我们就可以拿到Image控件的宽高了,还有父控件Row的宽高,这样我们就能算出来第一行能显示多少个文字(第一行文字就是图片屁股后面的文字),然后截取文字,分段显示;

在写的时候,我发现在第一次build之后用key去获取Imge控件的宽高根本就不靠谱,经常返回null,报空指针异常,我呢,就根据缩放比例算出的宽高,再依次算出第一行剩下可显示文字的宽度(先假设叫 FirstRowTextWidth)

那怎么判断文字刚好够显示呢,我开了一个循环,每次累加一个字母,测量字母宽度是不是超过了FirstRowTextWidth,没超过就继续累加,直到超过为止  ,跳出循环;这时候我们就知道多少了字母不会超过了,(超过的哪个字母的前一个字母肯定没有超过FirstRowTextWidth),好了,看代码

//在第一帧后计算下第一行能显示多少个字母,然后将字母分成两段显示
    WidgetsBinding.instance.addPostFrameCallback((callback){
      _image.image.resolve(new ImageConfiguration())
          .addListener((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;
        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){
            break;
          }
        }

        //将超出的哪个位置减掉,剩下的字母就不会超出范围了
        int validIndex=index-1;
        //根据计算的位置,分别截取前半部分 和后半部分显示
        setState(() {
          _topText=  widget.text.substring(0,validIndex);
          _bottomText =  widget.text.substring(validIndex);
        });
      });

    });
  }

代码就这么多,是不是很简单,快去尝试一下吧。如果在使用的过程中有什么问题,也请留言,随时为你解答,

最后附上源码地址:https://github.com/OpenFlutter/PullToRefresh

里面有很多更酷的控件,欢迎Star;如果喜欢Flutter,可以加入我们哦,我们的QQ群是 :892398530

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

baoolong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值