HarmonyOS鸿蒙Next中属性字符串CustomSpan与同行字符串如何垂直居中对齐?

HarmonyOS鸿蒙Next中属性字符串CustomSpan与同行字符串如何垂直居中对齐?

demo如下,如何解决使用属性字符串的CustomSpan与同行字符串如何垂直居中对齐问题?

// xxx.ets
import { image } from '@kit.ImageKit'
import { LengthMetrics } from '@kit.ArkUI'
import { drawing, common2D } from '@kit.ArkGraphics2D'
import { MeasureText } from '@kit.ArkUI'

let gUIContext: UIContext;

class MyCustomSpan extends CustomSpan {
  constructor(word: string) {
    super();
    this.word = word;
  }

  onMeasure(measureInfo: CustomSpanMeasureInfo): CustomSpanMetrics {
    let textSize = MeasureText.measureTextSize({ textContent: this.word, fontSize: measureInfo.fontSize })
    this.width = textSize.width as number
    this.height = textSize.height as number

    console.info("test height: " + this.height)

    return { width: px2vp(this.width) + this.paddingLeft * 2, height: px2vp(this.height) + this.paddingTop * 2 };
  }

  onDraw(context: DrawContext, options: CustomSpanDrawInfo) {
    let canvas = context.canvas;

    const brush = new drawing.Brush();
    brush.setColor({
      alpha: 255,
      red: 0,
      green: 0,
      blue: 175
    });
    const font = new drawing.Font();
    font.setSize(fp2px(30));
    const textBlob = drawing.TextBlob.makeFromString(this.word, font, drawing.TextEncoding.TEXT_ENCODING_UTF8);
    canvas.attachBrush(brush);
    console.info("test : " + options.baseline + " : " + options.lineBottom)

    let rect: common2D.Rect = {
      left: options.x,
      right: options.x + this.width + vp2px(this.paddingLeft * 2),
      top: options.lineTop,
      bottom: options.lineBottom
    };
    let roundRect = new drawing.RoundRect(rect, this.paddingTop, this.paddingTop); // 自定义 x/y 方向的半径
    canvas.drawRoundRect(roundRect);
    brush.setColor({
      alpha: 255,
      red: 23,
      green: 169,
      blue: 141
    });
    canvas.attachBrush(brush);
    canvas.drawTextBlob(textBlob, options.x + vp2px(this.paddingLeft), options.baseline - vp2px(this.paddingTop));
    canvas.detachBrush();
  }

  setWord(word: string) {
    this.word = word;
  }

  width: number = 100;
  word: string = "drawing";
  height: number = 30;
  paddingLeft: number = vp2px(8)
  paddingTop: number = vp2px(8)
}

@Entry
@Component
struct AtSpan {
  controller: TextController = new TextController();
  imagePixelMap: image.PixelMap | undefined = undefined
  customSpan1: MyCustomSpan = new MyCustomSpan("@小喵吃鱼");

  async onPageShow() {
    let customStyle = new MutableStyledString(this.customSpan1)
    let message =
      new StyledString('我是只可爱的小猫咪hhh,我每天需要吃很多好吃的,睡很多觉,这是我在论坛发布的探讨问题!')
    customStyle.appendStyledString(message)
    this.controller.setStyledString(customStyle)
  }

  build() {
    Row() {
      Column({ space: 5 }) {
        Text(undefined, { controller: this.controller })
          .copyOption(CopyOptions.InApp)
          .draggable(true)
          .fontSize(30)
          .borderWidth(1)
      }
      .width('100%')
    }
    .height('100%')
  }
}

运行效果:

![cke_5932.png](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR42u1dCbhV1Zm+899199999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999


更多关于HarmonyOS鸿蒙Next中属性字符串CustomSpan与同行字符串如何垂直居中对齐?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

尝试了下可以转换成ImageAttachment通过ImageSpanAlignment实现文字和自定义的同行垂直居中

// xxx.ets
import { image } from '@kit.ImageKit'
import { LengthMetrics } from '@kit.ArkUI'
import { MeasureText } from '@kit.ArkUI'
import { drawing, common2D, text } from '@kit.ArkGraphics2D';

@Entry
@Component
struct Index {
  controller: TextController = new TextController();

  private createCustomSpan(name: string) {
    let fontSize = 30 // fp
    let textSize = MeasureText.measureTextSize({ textContent: name, fontSize: fontSize })
    let paddingLeft = vp2px(8)
    let paddingTop = vp2px(8)
    let width = (textSize.width as number) + paddingLeft * 2;
    let height = (textSize.height as number) + paddingTop * 2;

    const color: ArrayBuffer = new ArrayBuffer(width * height * 4); // 为需要创建的像素buffer大小,取值为:height * width *4
    let opts: image.InitializationOptions = { pixelFormat: 3, size: { height: height, width: width } }
    let pixelMap: image.PixelMap = image.createPixelMapSync(color, opts);

    // 绘制背景
    const canvas = new drawing.Canvas(pixelMap);
    const brush = new drawing.Brush();
    const color2: common2D.Color = {
      alpha: 255,
      red: 88,
      green: 0,
      blue: 0
    };
    brush.setColor(color2);
    canvas.attachBrush(brush);
    let rect: common2D.Rect = {
      left: 0,
      top: 0,
      right: width,
      bottom: height
    };
    let roundRect = new drawing.RoundRect(rect, paddingTop, paddingTop); // 自定义 x/y 方向的半径
    canvas.drawRoundRect(roundRect);
    canvas.detachBrush();

    // 绘制文字
    let myTextStyle: text.TextStyle = {
      fontSize: vp2px(fontSize),
    };
    let myParagraphStyle: text.ParagraphStyle = {
      textStyle: myTextStyle,
      align: text.TextAlign.START,
    };
    let fontCollection = new text.FontCollection();
    let paragraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
    paragraphGraphBuilder.addText(name);
    let paragraph = paragraphGraphBuilder.build();
    paragraph.layoutSync(textSize.width as number);
    paragraph.paint(canvas, paddingLeft, paddingTop);

    // 创建ImageAttachment字符串
    let customSpan = new MutableStyledString(new ImageAttachment({
      value: pixelMap,
      size: { width: px2vp(width), height: px2vp(height) },
      layoutStyle: { margin: LengthMetrics.vp(2) }, // 行内margin
      verticalAlign: ImageSpanAlignment.CENTER,
      objectFit: ImageFit.None
    }))
    return customSpan
  }

  async onPageShow() {
    let customSpan = this.createCustomSpan('@小喵吃鱼')
    let message = new StyledString('我是只可爱的小猫咪hhh,我每天需要吃很多好吃的,睡很多觉,这是我在论坛发布的探讨问题!')
    customSpan.appendStyledString(message)
    this.controller.setStyledString(customSpan)
  }

  build() {
    Row() {
      Column({ space: 5 }) {
        Text(undefined, { controller: this.controller })
          .copyOption(CopyOptions.InApp)
          .draggable(true)
          .fontSize(30)
          .borderWidth(1)

      }
      .width('100%')
    }
    .height('100%')
  }
}

更多关于HarmonyOS鸿蒙Next中属性字符串CustomSpan与同行字符串如何垂直居中对齐?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,要使属性字符串CustomSpan与同行字符串垂直居中对齐,可以通过设置TextPaintbaselineShift属性来实现。具体步骤如下:

  1. 创建CustomSpan实例。
  2. CustomSpanupdateDrawState方法中,通过TextPaintbaselineShift调整基线偏移量,使其与同行字符串对齐。
  3. 使用SpannableStringCustomSpan应用到文本中。

示例代码:

CustomSpan customSpan = new CustomSpan() {
    @Override
    public void updateDrawState(TextPaint tp) {
        tp.baselineShift = (int) (tp.ascent() / 2); // 调整基线偏移量
    }
};
SpannableString spannableString = new SpannableString("Text with CustomSpan");
spannableString.setSpan(customSpan, 0, spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);

通过调整baselineShift,可以实现CustomSpan与同行字符串的垂直居中对齐。

回到顶部