想了解更多内容,请访问:
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