深圳幻海软件技术有限公司 欢迎您!

HarmonyOS自定义组件之图层的使用

2023-02-28

想了解更多内容,请访问:51CTO和华为官方合作共建的鸿蒙技术社区https://harmonyos.51cto.com前言HarmonyOS目前已经有较丰富的自定义组件了,但是多数自定义组件都没有讲到图层这个概念,都是使用默认图层进行绘制。这里就通过几个小例子介绍一下HarmonyOS自定义组件中

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

前言

HarmonyOS目前已经有较丰富的自定义组件了,但是多数自定义组件都没有讲到图层这个概念,都是使用默认图层进行绘制。这里就通过几个小例子介绍一下HarmonyOS自定义组件中图层概念和使用。

使用说明

1.HarmonyOS的绘制入口

1.1 DrawTask接口

HarmonyOS的Component组件对外提供了一个DrawTask接口,通过addDrawTask方法为组件添加一个DrawTask,让开发者可以进行自定义绘制逻辑。首先我们看下DrawTask的描述:

public interface DrawTask { 
      int BETWEEN_BACKGROUND_AND_CONTENT = 1; 
      int BETWEEN_CONTENT_AND_FOREGROUND = 2; 
 
      void onDraw(Component component, Canvas canvas); 
  } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

 1.2 onDraw绘制方法

这个接口中只有一个onDraw方法,做移动开发的同学对这个名称的方法应该都很熟悉,在这个回调里系统提供了一块canvas画布,我们可以调用canvas的api进行一些基础图形的组合绘制。

2.HarmonyOS图层介绍

2.1 图层概念介绍

HarmonyOS为每个组件定义了5个图层,从下往上分别为:Background -> UserLayer1 -> Content -> UserLayer2 -> Foreground,并且绘制流程也是按照从下往上的顺序进行绘制的,这点其实和我们熟悉的View的绘制流程基本一致。这中设计和PS中的图层概念基本一致,通过构建多个图层分别进行操作,最终再合成为一个图层渲染到屏幕上。我们可以用下面这图来理解:


在这个图层结构中,有两个layer是提供给上层应用使用的,分别如图中的UserLayer1和UserLayer2。他们分别位于背景与内容之间,内容与前景之间。其中,背景,内容,前景为系统私有,应用层无法对其进行干预。(这里补充说明一点,从官方API文档说明来看是存在Foreground图层的,但是实际中尚不清楚系统是如何使用该图层,个人猜测应该是留给列表的滚动条这类场景使用。)

2.2 图层概念实践

在第一节的DrawTask接口介绍中,里面定义和图层相关的两个常量:BETWEEN_BACKGROUND_AND_CONTENT 和 BETWEEN_CONTENT_AND_FOREGROUND,对应的就是上图中的两个User Layer。

下面我们用代码来实践一下这个图层结构和这两个常量的作用。

自定义一个Text组件,分别在上图中的两个UserLayer中绘制不同颜色的实心矩形:

public class CustomText extends Text { 
 
    public CustomText(Context context, AttrSet attrSet) { 
        super(context, attrSet); 
        init(); 
    } 
 
    private void prepare() { 
        // 绘制红色背景 
        ShapeElement background = new ShapeElement(); 
        background.setShaderType(ShapeElement.RECTANGLE); 
        background.setRgbColor(new RgbColor(255,0,0)); 
        setBackground(background); 
        // 绘制白色文字 
        setText("你好你好你好你好你好"); 
        setTextColor(Color.WHITE); 
    } 
 
    private void init() { 
        prepare(); 
        // 在BETWEEN_BACKGROUND_AND_CONTENT图层上绘制蓝色矩形 
        addDrawTask(new BackDrawTask(), DrawTask.BETWEEN_BACKGROUND_AND_CONTENT); 
        // 在BETWEEN_CONTENT_AND_FOREGROUND图层上绘制绿色矩形 
        addDrawTask(new ForeDrawTask(), DrawTask.BETWEEN_CONTENT_AND_FOREGROUND); 
    } 
 
    // BETWEEN_BACKGROUND_AND_CONTENT 
    private static class BackDrawTask implements DrawTask { 
        @Override 
        public void onDraw(Component component, Canvas canvas) { 
            final int offset = 50; 
            Paint paint = new Paint(); 
            paint.setStyle(Paint.Style.FILL_STYLE); 
            paint.setColor(Color.BLUE); 
            canvas.drawRect(new Rect(offset, offset, component.getWidth() - offset, component.getHeight() - offset), paint); 
        } 
    } 
 
    // BETWEEN_CONTENT_AND_FOREGROUND 
    private static class ForeDrawTask implements DrawTask { 
        @Override 
        public void onDraw(Component component, Canvas canvas) { 
            final int offset = 100; 
            Paint paint = new Paint(); 
            paint.setStyle(Paint.Style.FILL_STYLE); 
            paint.setColor(Color.GREEN); 
            canvas.drawRect(new Rect(offset, offset, component.getWidth() - offset, component.getHeight() - offset), paint); 
        } 
    } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.

布局代码如下:

<DirectionalLayout 
    xmlns:ohos="http://schemas.huawei.com/res/ohos" 
    ohos:height="match_parent" 
    ohos:width="match_parent" 
    ohos:alignment="center" 
    ohos:orientation="vertical"
 
    <com.example.myapplication.CustomText 
        ohos:height="300vp" 
        ohos:width="300vp" 
        ohos:layout_alignment="horizontal_center" 
        ohos:text_size="40vp" /> 
 
</DirectionalLayout> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

 运行项目,我们来看下实际的渲染效果,的确符合预期。


从目视的垂直方向,从底部往上的内容依次是:

最底层的红色背景(Background),

自定义的蓝色矩形(BackDrawTask),

Text自己的文本内容(Content),

自定义的绿色矩形(ForeDrawTask)。

3.HarmonyOS图层的使用

3.1 继承Component的自定义组件

当我们继承Component去实现自定义组件时,这时候不论选用哪个图层进行绘制都是一样。因为两个UserLayer都是位于Background图层之上,而默认的Component组件并没有内容层和前景的默认绘制,因此可以忽略这两个图层。

3.2 通过图层实现水波纹效果

当我们继承系统组件,系统组件的内容层和前景层都有内部绘制逻辑,因此我们慎重选择UserLayer图层了。

给自定义Button添加一个水波纹的触摸反馈效果**(水波纹效果是需要绘制在button文字之下,button背景之上,因此使用 BETWEEN_BACKGROUND_AND_CONTENT)**:

public class CustomButton extends Button implements Component.TouchEventListener, Component.DrawTask { 
    private float downX, downY; 
    private int maxRadius; 
    private float currentRadius; 
    private final Paint paint = new Paint(); 
 
    { 
        paint.setColor(Color.YELLOW); 
        paint.setStyle(Paint.Style.FILL_STYLE); 
    } 
 
    private AnimatorValue av = new AnimatorValue(); 
 
    public CustomButton(Context context, AttrSet attrSet) { 
        super(context, attrSet); 
        av.setValueUpdateListener((animatorValue, v) -> { 
            currentRadius = maxRadius * v; 
            invalidate(); 
        }); 
        init(); 
    } 
 
    @Override 
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) { 
        if (touchEvent.getAction() == TouchEvent.PRIMARY_POINT_DOWN) { 
            if (maxRadius == 0) { 
                int w = component.getWidth(); 
                int h = component.getHeight(); 
                maxRadius = (int) Math.sqrt(w * w + h * h); 
            } 
            int index = touchEvent.getIndex(); 
            MmiPoint pointer = touchEvent.getPointerPosition(index); 
            downX = pointer.getX(); 
            downY = pointer.getY(); 
            av.cancel(); 
            av.start(); 
            return true
        } else if (touchEvent.getAction() == TouchEvent.PRIMARY_POINT_UP) { 
            av.cancel(); 
            currentRadius = 0; 
            invalidate(); 
            return true
        } 
        return false
    } 
 
    private void init() { 
        setTouchEventListener(this); 
        addDrawTask(this, DrawTask.BETWEEN_BACKGROUND_AND_CONTENT); 
    } 
 
    @Override 
    public void onDraw(Component component, Canvas canvas) { 
        canvas.drawCircle(downX, downY, currentRadius, paint); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.

效果如下:


3.3 通过图层实现蒙层效果

给自定义Image增加一个颜色遮罩效果**(图片蒙层是在图片内容上加一个遮罩,因此需要在图片之上进行蒙层绘制,因此使用 BETWEEN_CONTENT_AND_FOREGROUND)**:

public class CustomImage extends Image implements Component.DrawTask { 
    private final Paint paint = new Paint(); 
 
    { 
        paint.setColor(Color.YELLOW); 
        paint.setStyle(Paint.Style.FILL_STYLE); 
        paint.setAlpha(0.3f); 
    } 
 
    public CustomImage(Context context, AttrSet attrSet) { 
        super(context, attrSet); 
        // 图片蒙层是在图片内容上加一个遮罩,因此需要在内容层和前景层进行蒙层绘制 
        addDrawTask(this, DrawTask.BETWEEN_CONTENT_AND_FOREGROUND); 
    } 
 
    @Override 
    public void onDraw(Component component, Canvas canvas) { 
        canvas.drawRect(new Rect(0, 0, component.getWidth(), component.getHeight()), paint); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

4.效果展示

效果如下,左边为原始Image,右边的为添加蒙版的Image:


总结

以上就是关于鸿蒙图层的介绍,核心内容概括如下:

  • HarmonyOS为每个组件定义了5个图层,从下往上分别为:Background、UserLayer1、Content、UserLayer2、Foreground。
  • HarmonyOS自定义组件能够使用的图层有两个,分别位于Background和Content、Content和Foreground之间。
  • 灵活的选择绘制图层,可以实现特殊的UI效果,例如水波纹触摸反馈、图片遮罩蒙层效果等。

文章相关附件可以点击下面的原文链接前往下载

https://harmonyos.51cto.com/resource/1612

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com