鸿蒙Next实现在页面上添加水印 原创

auhgnixgnahz
发布于 2025-9-2 17:30
浏览
0收藏

水印在我们日常使用的APP中是很常见的。本文记录一下如何实现一个自定义的水印,可以自定义设置水印文字、间距、旋转角度。
实现效果:
鸿蒙Next实现在页面上添加水印-鸿蒙开发者社区
实现思路:
核心方法是使用Canvas绘制文字,只需要在指定的间隔上绘制我们想要展示的水印文字内容就可以了。需要使用到Canvas的坐标系平移、坐标系旋转、文字绘制。
源码:

import { WindowUtils } from "../utils/WindowUtils"

@Entry
@ComponentV2
struct WaterMarkTest{
  private maxHorizontalSpace:number = Math.floor(px2vp(WindowUtils.getWindowWidth()/2))
  private maxVerticalSpace:number = Math.floor(px2vp(WindowUtils.getWindowHeight()/2))
  @Local horizontalSpace:number=100  //文字水印中心 水平间距
  @Local verticalSpace:number=100    //文字水印中心 垂直间距
  @Local rotateAngle:number=10      //文字水印中心 旋转角度
  @Local textSize:number=20   //水印字体大小

  build() {
    Stack(){
      Column(){
        Row({ space: 10 }) {
          Text('水平间距:' + this.horizontalSpace)
          Slider({
            value: this.horizontalSpace,
            min: 30,
            max: this.maxHorizontalSpace,
            style: SliderStyle.OutSet
          }).width('50%')
            .onChange((value: number) => {
              this.horizontalSpace = value;
            })
        }
        Row({ space: 10 }) {
          Text('垂直间距:' + this.verticalSpace)
          Slider({
            value: this.verticalSpace,
            min: 30,
            max: this.maxVerticalSpace,
            style: SliderStyle.OutSet
          }).width('50%')
            .onChange((value: number) => {
              this.verticalSpace = value;
            })
        }
        Row({ space: 10 }) {
          Text('旋转角度:' + this.rotateAngle)
          Slider({
            value: this.rotateAngle,
            min: 10,
            max: 90,
            style: SliderStyle.OutSet
          }).width('50%')
            .onChange((value: number) => {
              this.rotateAngle = value;
            })
        }
        Row({ space: 10 }) {
          Text('textSize:' + this.textSize)
          Slider({
            value: this.textSize,
            min: 20,
            max: 40,
            style: SliderStyle.OutSet
          }).width('50%')
            .onChange((value: number) => {
              this.textSize = value;
            })
        }
      }
      WaterMark({waterMarkProperties: { horizontalSpace:this.horizontalSpace,
        verticalSpace:this.verticalSpace,
        rotateAngle:this.rotateAngle,
        textColor:'#80000000',
        textSize:this.textSize+'vp'}})
    }
    //以上是测试演示方法,实际使用可以使用overlay添加浮层
    // .overlay(createWaterMarkView())
    .width('100%')
    .height('100%')

  }
}

export interface WaterMarkProperties {
  horizontalSpace: number //文字水印中心 水平间距
  verticalSpace: number //文字水印中心 垂直间距
  rotateAngle: number //文字水印中心 旋转角度
  textColor: string //水印字体颜色
  textSize: string //水印字体大小
}
@Builder
export function createWaterMarkView(waterMarkProperties:WaterMarkProperties={
  horizontalSpace:60,
  verticalSpace:60,
  rotateAngle:30,
  textColor:'#10000000',
  textSize:'20vp'
}) {
  WaterMark({waterMarkProperties:waterMarkProperties}).hitTestBehavior(HitTestMode.None)
}

@ComponentV2
struct WaterMark{
  private waterMarkSettings: RenderingContextSettings = new RenderingContextSettings(true);
  private waterMarkContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.waterMarkSettings);
  @Require  @Param waterMarkProperties:WaterMarkProperties
  private waterMarkText:string='HarmonyOS开发笔记';
  private waterMarkTextWidth:number = 0

  @Monitor('waterMarkProperties')
  draw(){
    this.waterMarkContext.reset()
    this.waterMarkTextWidth=this.getUIContext().getMeasureUtils().measureTextSize({
      textContent: this.waterMarkText,
      fontSize: this.waterMarkProperties.textSize
    }).width as number
    //设置水印文字的填充颜色
    this.waterMarkContext.fillStyle = this.waterMarkProperties.textColor;
    //设置水印文字大小
    this.waterMarkContext.font = this.waterMarkProperties.textSize;
    //设置水印对齐方式  文字水平和垂直方向居中
    this.waterMarkContext.textAlign = 'center';
    this.waterMarkContext.textBaseline = 'middle';

    //外层循环:水平方向遍历(控制水印的水平分布)
    //循环次数 = Canvas宽度 / 水平间距
    for (let i = 0; i < this.waterMarkContext.width / this.waterMarkProperties.horizontalSpace; i++) {
      //将Canvas原点(0,0)向右移动一个间距(每次循环右移,实现水平排列)
      this.waterMarkContext.translate(this.waterMarkProperties.horizontalSpace, 0);
      let j = 0;
      // 内层循环:垂直方向遍历(控制水印的垂直分布)
      // 循环次数 = Canvas高度 / 垂直间距
      for (; j < this.waterMarkContext.height /this.waterMarkProperties.verticalSpace; j++) {
        //文字旋转:将文字逆时针旋转指定角度(公式:Math.PI/180 * 角度)
        this.waterMarkContext.rotate(-Math.PI / 180 * this.waterMarkProperties.rotateAngle);
        this.waterMarkContext.fillText(this.waterMarkText, -px2vp(this.waterMarkTextWidth)/2, 0);
        //恢复旋转:将Canvas旋转状态还原
        this.waterMarkContext.rotate(Math.PI / 180 * this.waterMarkProperties.rotateAngle);
        // 垂直平移:将Canvas原点向下移动一个间距(每次循环下移,实现垂直排列)
        this.waterMarkContext.translate(0, this.waterMarkProperties.verticalSpace);
      }
      // 恢复垂直原点:内层循环结束后,将垂直方向的原点还原到初始高度
      this.waterMarkContext.translate(0, -this.waterMarkProperties.verticalSpace * j);
    }
  }
  build() {
    Canvas(this.waterMarkContext)
      .width('100%')
      .height('100%')
      .hitTestBehavior(HitTestMode.None)
      .onReady(() => {
        this.draw()
      })
  }
}

注意:
以上为了演示间距和角度,把水印组件的属性设置成可动态变化的,实际使用时,我们可以直接将配置的参数写死,不要重复渲染。给需要添加水印的组件使用overlay的方法添加。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
收藏
回复
举报
回复
    相关推荐