鸿蒙居中绘制文本到正方形区域内

发布于:2025-04-21 ⋅ 阅读:(67) ⋅ 点赞:(0)

绘制文本到正方形区域内,使其水平、垂直居中于该正方形区域,并尽量撑满该正方形区域。

注意,这里是通过 OffscreenCanvas 进行绘制文本,而不是使用支持文本的鸿蒙UI组件。

1、首先根据文本长度(业务上最长4位文本)、正方形边长来计算所需绘制文本的字号:

getFontSize(text:string, lenSqure:number) {
    let lenText = text.length;

    for (let fontSize = 1; ; fontSize++) {
      this.textSize = this.uiContextMeasure.measureTextSize({
        textContent: text,
        fontSize: fontSize + 'vp'
      })

      let width = Number(this.textSize.width);
      let height = Number(this.textSize.height);

      let cond:boolean = false;
      if(1 == lenText) {
        cond = px2vp(height) > lenSqure*.9;// 文本长度为1时的“撑满参数”,使不显得过于拥挤;经验值,下同
      } else if(2 == lenText) {
        cond = px2vp(height) > lenSqure*.7;
      } else if(3 == lenText) {
        cond = px2vp(height) > lenSqure*.5;
      } else if(4 == lenText) {
        cond = px2vp(height) > lenSqure*.4;
      } else {
        cond = px2vp(height) > lenSqure*.3;
      }

      if (cond) {
        console.info(text + ' exceeding font size = ' + fontSize)
        console.info(text + ' exceeding: width = ' + px2vp(width) + ', height = ' + px2vp(height))
        return fontSize - 1;
      }
    }

    return fontSize;
  }

上边代码思路:从字号1开始循环,不断计算文本高度,若超过正方形边长则返回fontSize - 1。
这里被迫使用“经验值”,即上边的.9至.3的参数,因为业务上的“撑满”需求是不要过于撑满。

2、对于1至4位文本(业务需求最高仅支持4位)用上述方法分别求得各自的fontSize:

this.font1 = this.getFontSize('1', squreWidth);
this.font2 = this.getFontSize('10', squreWidth);
this.font3 = this.getFontSize('100', squreWidth);
this.font4 = this.getFontSize('1000', squreWidth);

3、绘制:

              // 绘制文字方法的坐标指的是文字的左下角
              let xBL = x+1, yBL = y+1;
              // 2至4位数字,xBL, yBL所代表的左下角应逐渐向右上偏移一定比例
              // 偏移参数,使得手数看起来中心点为交叉点
              let xRatio:number = 0, yRatio:number = 0;
              if(1 == step.length) {
                xRatio = -0.25; yRatio = 0.25;
                offContext.font = this.font1 + 'vp';
              } else if(2 == step.length) {
                xRatio = -0.375; yRatio = 0.1875;
                offContext.font = this.font2 + 'vp';
              } else if(3 == step.length) {
                xRatio = -0.375; yRatio = 0.15625;
                offContext.font = this.font3 + 'vp';
              } else {// step.length >= 4
                xRatio = -0.375; yRatio = 0.125;
                offContext.font = this.font4 + 'vp';
              }

              xBL += xRatio; yBL += yRatio;
              xBL *= squreWidth; yBL *= squreWidth;

              offContext.strokeText(step, xBL, yBL);
              offContext.fillText(step, xBL, yBL);//否则中空

仍然被迫使用了另一组经验值:用于尽量居中于目标正方形区域。因为对于不同长度的文本,绘制时的所需坐标相对于正方形中心不是固定的。

所幸,上述代码中的两套经验值并不因为正方形边长的改变而导致文字不居中,因为经验值用的是正方形边长的百分比。