Flutter-----LabelView---文字自适应其大小

最近再写FlutterDemo,需要用到一个labelview,网上找了找,没有合适的,就对网上一位大神写的demoLabelDemo改了下,就有l了这么一个文字自适应大小的labelViewGithub

先看下效果图

说白了就是对CustomPainter 和对画布的操作(旋转和平移)

  • labelAlignment: LabelAlignment.leftTop,
    Flutter-----LabelView---文字自适应其大小_第1张图片
  • labelAlignment: LabelAlignment.leftBottom
    Flutter-----LabelView---文字自适应其大小_第2张图片
  • labelAlignment: LabelAlignment.rightTop
    Flutter-----LabelView---文字自适应其大小_第3张图片
  • LabelAlignment.rightBottom
    Flutter-----LabelView---文字自适应其大小_第4张图片

使用

@override
  Widget build(BuildContext context) {
    return LabelViewDecoration(
        size: Size(80.0, 80.0),//label size
        labelColor: Colors.red,//label color
        labelAlignment: LabelAlignment.leftTop,//The orientation of the label attached to the widget
        useAngle: true,//
        labelText: "Hot",
        labelTextColor: Colors.white,
        child: _builderItem()//Label attached widget
    );
  }

关键代码

其中最重要的就是对形状和文字的绘制,形状的绘制采用Path,就是以size尺寸绘制一个三角形,根据三角形的大小测量文字的大小,然后旋转画布的角度,然后平移。画布默认旋转中心为坐标轴原点,而且貌似不能更改,至少我没找到,所以需要旋转后再平移,对canvas的位置操作需要倒着写,所以实际代码是先写translate,再写rotate。其余的就是数学计算了。

@override
  void paint(Canvas canvas, Size size) {
    var drawSize = size.height > size.width ? size.width / 2 : size.height / 2;
    Path path = new Path();
    switch (labelAlignment) {
      case LabelAlignment.leftTop:
        if (!useAngle) {
          path.moveTo(drawSize / 2, 0);
          path.lineTo(0, drawSize / 2);
        }
        path.lineTo(0, drawSize);
        path.lineTo(drawSize, 0);
        break;
      case LabelAlignment.leftBottom:
        path.moveTo(0, size.height - drawSize);

        if (useAngle) {
          path.lineTo(drawSize, size.height);
          path.lineTo(0, size.height);
        } else {
          path.lineTo(0, size.height - drawSize / 2);
          path.lineTo(drawSize / 2, size.height);
          path.lineTo(drawSize, size.height);
        }
        break;
      case LabelAlignment.rightTop:
        path.moveTo(size.width - drawSize, 0);
        if (useAngle) {
          path.lineTo(size.width, 0);
        } else {
          path.lineTo(size.width - drawSize / 2, 0);
          path.lineTo(size.width, drawSize / 2);
        }

        path.lineTo(size.width, drawSize);
        break;
      case LabelAlignment.rightBottom:
        if (useAngle) {
          path.moveTo(size.width, size.height);

          path.lineTo(size.width - drawSize, size.height);
          path.lineTo(size.width, size.height - drawSize);
        } else {
          path.moveTo(size.width - drawSize, size.height);
          path.lineTo(size.width - drawSize / 2, size.height);
          path.lineTo(size.width, size.height - drawSize / 2);
          path.lineTo(size.width, size.height - drawSize);
        }
        break;
      default:
        if (!useAngle) {
          path.moveTo(drawSize / 2, 0);
          path.lineTo(0, drawSize / 2);
        }
        path.lineTo(0, drawSize);
        path.lineTo(drawSize, 0);
        break;
    }
    path.close();
    canvas.drawPath(path, _paint);

    canvas.save();

    //计算字体size
    double minWidth = 0;
    switch(labelAlignment){
      case LabelAlignment.leftTop:
      //旋转画布并平移  代码上是先做平移在旋转操作,反着来
        canvas.translate(0.0, drawSize);
        canvas.rotate(angleToRadian(-45.0));
        if (useAngle) {
          double x = ((drawSize / 2) * (drawSize / 2) / 2);
          minWidth = sqrt(x);
          //方法一:使用drawParagraph绘制文字,Paragraph是ui包内的
          Paragraph paragraph = buildParagraph(labelText, minWidth, drawSize);
          canvas.drawParagraph(paragraph, Offset(0, -drawSize / 2));
        } else {
          double x = ((drawSize / 3) * (drawSize / 3) / 2);
          minWidth = sqrt(x);
          //方法一:使用drawParagraph绘制文字,Paragraph是ui包内的
          Paragraph paragraph = buildParagraph(labelText, minWidth, drawSize / 2);
          canvas.drawParagraph(paragraph, Offset(drawSize / 3, -drawSize / 3));
        }
        break;
      case LabelAlignment.leftBottom:
        canvas.translate(0.0, drawSize);
        canvas.rotate(angleToRadian(45.0));
        if (useAngle) {
          double x = ((drawSize / 2) * (drawSize / 2) / 2);
          minWidth = sqrt(x);
          //方法一:使用drawParagraph绘制文字,Paragraph是ui包内的
          Paragraph paragraph = buildParagraph(labelText, minWidth, drawSize);
          canvas.drawParagraph(paragraph, Offset(0, 0));
        } else {
          double x = ((drawSize / 3) * (drawSize / 3) / 2);
          minWidth = sqrt(x);
          //方法一:使用drawParagraph绘制文字,Paragraph是ui包内的
          Paragraph paragraph = buildParagraph(labelText, minWidth, drawSize / 2);
          canvas.drawParagraph(paragraph, Offset(drawSize / 3, drawSize /27));
        }
        break;
      case LabelAlignment.rightTop:
      //旋转画布并平移  代码上是先做平移在旋转操作,反着来
        canvas.translate(0.0, drawSize);
        canvas.rotate(angleToRadian(45.0));
        if (useAngle) {
          double x = ((drawSize / 2) * (drawSize / 2) / 2);
          minWidth = sqrt(x);
          //方法一:使用drawParagraph绘制文字,Paragraph是ui包内的
          Paragraph paragraph = buildParagraph(labelText, minWidth, drawSize);
          canvas.drawParagraph(paragraph, Offset(drawSize/8,-drawSize*2));
        } else {
          double x = ((drawSize / 3) * (drawSize / 3) / 2);
          minWidth = sqrt(x);
          //方法一:使用drawParagraph绘制文字,Paragraph是ui包内的
          Paragraph paragraph = buildParagraph(labelText, minWidth, drawSize / 2);
          canvas.drawParagraph(paragraph, Offset(drawSize/2 , -drawSize*7/4 ));
        }
        break;
      case LabelAlignment.rightBottom:
      //旋转画布并平移  代码上是先做平移在旋转操作,反着来
        canvas.translate(0.0, drawSize);
        canvas.rotate(angleToRadian(-45.0));
        if (useAngle) {
          double x = ((drawSize / 2) * (drawSize / 2) / 2);
          minWidth = sqrt(x);
          //方法一:使用drawParagraph绘制文字,Paragraph是ui包内的
          Paragraph paragraph = buildParagraph(labelText, minWidth, drawSize);
          canvas.drawParagraph(paragraph, Offset(drawSize*8/5, -drawSize/4));
        } else {
          double x = ((drawSize / 3) * (drawSize / 3) / 2);
          minWidth = sqrt(x);
          //方法一:使用drawParagraph绘制文字,Paragraph是ui包内的
          Paragraph paragraph = buildParagraph(labelText, minWidth, drawSize / 2);
          canvas.drawParagraph(paragraph, Offset(drawSize*2, -drawSize/5));
        }
        break;
      default:

        break;
    }
    canvas.restore();
  }
//根据文本内容和字体大小等构建一段文本
  Paragraph buildParagraph(String text, double textSize, double constWidth) {
    ParagraphBuilder builder = ParagraphBuilder(
      ParagraphStyle(
        textAlign: TextAlign.right,
        fontSize: textSize,
        fontWeight: FontWeight.normal,
      ),
    );
    builder.pushStyle(ui.TextStyle(color: labelTextColor));
    builder.addText(text);
    ParagraphConstraints constraints = ParagraphConstraints(width: constWidth);
    return builder.build()..layout(constraints);
  }

拼搏在技术道路上的一只小白And成长之路

你可能感兴趣的:(Flutter)