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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章