【鸿蒙】HarMonyOS的自定义组件一

当Java UI框架提供的组件无法满足设计需求时,可以创建自定义组件,根据设计需求添加绘制任务,并定义组件的属性及事件响应,完成组件的自定义。

常用接口

表1 Component类相关接口

接口名

作用

setEstimateSizeListener

设置测量组件的侦听器。

onEstimateSize

测量组件的大小以确定宽度和高度。

setEstimatedSize

将测量的宽度和高度设置给组件。

EstimateSpec.getChildSizeWithMode

基于指定的大小和模式为子组件创建度量规范。

EstimateSpec.getSize

从提供的度量规范中提取大小。

EstimateSpec.getMode

获取该组件的显示模式。

addDrawTask

添加绘制任务。

onDraw

通过绘制任务更新组件时调用。

如何实现自定义组件

下面以自定义圆环组件为例,介绍自定义组件的通用配置方法:在屏幕中绘制蓝色圆环,并实现点击变化圆环颜色的功能。

图1 在界面中显示的自定义圆环组件

  1. 创建自定义组件的类,并继承Component或其子类,添加构造方法。

    示例代码如下:

    public class CustomComponent extends Component{
    public CustomComponent(Context context) {
    super(context);
    }
    }

  2. 实现Component.EstimateSizeListener接口,在onEstimateSize方法中进行组件测量,并通过setEstimatedSize方法将测量的宽度和高度设置给组件。示例代码如下:
    public class CustomComponent extends Component implements Component.EstimateSizeListener {
    public CustomComponent(Context context) {
    super(context);
    
    ...
    
    // 设置测量组件的侦听器
    setEstimateSizeListener(this);
    }
    
    ...
    
    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
    int width = Component.EstimateSpec.getSize(widthEstimateConfig);
    int height = Component.EstimateSpec.getSize(heightEstimateConfig);
    setEstimatedSize(
    Component.EstimateSpec.getChildSizeWithMode(width, width, Component.EstimateSpec.NOT_EXCEED),
    Component.EstimateSpec.getChildSizeWithMode(height, height, Component.EstimateSpec.NOT_EXCEED));
    return true;
    }
    }
    • 注意事项
      1. 自定义组件测量出的大小需通过setEstimatedSize设置给组件,并且必须返回true使测量值生效。
      2. setEstimatedSize方法的入参携带模式信息,可使用Component.EstimateSpec.getChildSizeWithMode方法进行拼接。
    • 测量模式测量组件的宽高需要携带模式信息,不同测量模式下的测量结果也不相同,需要根据实际需求选择适合的测量模式。
      表2 测量模式信息

      模式

      作用

      UNCONSTRAINT

      父组件对子组件没有约束,表示子组件可以任意大小。

      PRECISE

      父组件已确定子组件的大小。

      NOT_EXCEED

      已为子组件确定了最大大小,子组件不能超过指定大小。

  3. 实现Component.DrawTask接口,在onDraw方法中执行绘制任务,该方法提供的画布Canvas,可以精确控制屏幕元素的外观。在执行绘制任务之前,需要定义画笔Paint。

    示例代码如下:

    public class CustomComponent extends Component implements Component.DrawTask,Component.EstimateSizeListener {
    // 圆环宽度
    private static final float CIRCLE_STROKE_WIDTH = 100f;
    
    // 绘制圆环的画笔
    private Paint circlePaint;
    
    public CustomComponent(Context context) {
    super(context);
    
    // 初始化画笔
    initPaint();
    
    // 添加绘制任务
    addDrawTask(this);
    }
    
    private void initPaint(){
    circlePaint = new Paint();
    circlePaint.setColor(Color.BLUE);
    circlePaint.setStrokeWidth(CIRCLE_STROKE_WIDTH);
    circlePaint.setStyle(Paint.Style.STROKE_STYLE);
    }
    
    @Override
    public void onDraw(Component component, Canvas canvas) {
    
    // 在界面中绘制一个圆心坐标为(500,500),半径为400的圆
    canvas.drawCircle(500,500,400,circlePaint);
    }
    
    ...
    }

  4. 实现Component.TouchEventListener或其他事件的接口,使组件可响应用户输入。示例代码如下:
    public class CustomComponent extends Component implements Component.DrawTask, Component.EstimateSizeListener, Component.TouchEventListener {
    ...
    public CustomComponent(Context context) {
    ...
    
    // 设置TouchEvent响应事件
    setTouchEventListener(this);
    }
    
    ...
    
    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
    switch (touchEvent.getAction()) {
    case TouchEvent.PRIMARY_POINT_DOWN:
    circlePaint.setColor(Color.GREEN);
    invalidate();
    break;
    case TouchEvent.PRIMARY_POINT_UP:
    circlePaint.setColor(Color.YELLOW);
    invalidate();
    break;
    }
    //允许触摸事件触发后进行回调,一定要为true,不然只会监听按下的点击事件,不会触发弹起的事件
    return true;
    }
    }
    • 注意事项
      1. 需要更新UI显示时,可调用invalidate()方法。
      2. 示例中展示TouchEventListener为响应触摸事件,除此之外还可实现ClickedListener响应点击事件、LongClickedListener响应长按事件等。
  5. 在onStart()方法中,将自定义组件添加至UI界面中。
    @Override
    protected void onStart(Intent intent) {
    super.onStart(intent);
    DirectionalLayout.LayoutConfig config = new DirectionalLayout.LayoutConfig(
    DirectionalLayout.LayoutConfig.MATCH_PARENT, DirectionalLayout.LayoutConfig.MATCH_PARENT);
    myLayout.setLayoutConfig(config);
    
    CustomComponent customComponent = new CustomComponent(this);
    DirectionalLayout.LayoutConfig layoutConfig = new DirectionalLayout.LayoutConfig(1080, 1000);
    customComponent.setLayoutConfig(layoutConfig);
    
    myLayout.addComponent(customComponent);
    super.setUIContent(myLayout);
    }

    接下来是绘制矩形,三角形,线条,三角形,点,绘制文字等等效果,代码如下

 @Override
    public void onDraw(Component component, Canvas canvas) {
        //绘制图形

        // 在界面中绘制一个圆心坐标为(500,500),半径为400的圆
        canvas.drawCircle(200,400,100,paint);
        //左上角坐标点为(100,100),右下角坐标点为(200,200),绘制一个正方形
        canvas.drawRect(100,100,200,200,paint);
        //绘制文字
        canvas.drawChars(paint,new char[]{'你','好','鸿','蒙'},100,700);
        canvas.drawCharSequence(paint,"加油华为",100,900);
        //画线
        canvas.drawLine(500,100,700,500,paint);
        //画点
        canvas.drawPoint(900,900,paint);
        //画三角形
        canvas.drawLines(new float[]{400,700,600,800,
                600,800,500,600,
                500,600,400,700},paint);
    }

其效果如下:绘制的图形效果和通过触摸事件点击之后的效果,手指离开屏幕后恢复颜色

整个自定义组件完整代码如下:

package com.example.hm_phone_java.views;

import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

public class CustomComponent extends Component implements Component.EstimateSizeListener, Component.DrawTask, Component.TouchEventListener {
    public CustomComponent(Context context) {
        super(context);
        //添加组件大小监听器
        setEstimateSizeListener(this);
        //初始化画笔
        initPaint();
        // 添加绘制任务
        addDrawTask(this);

        //添加触摸事件
        setTouchEventListener(this);
    }


    @Override
    public boolean onEstimateSize(int width, int height) {
        int w=Component.EstimateSpec.getSize(width);
        int h=Component.EstimateSpec.getSize(height);
        setEstimatedSize(
                //NOT_EXCEED 已为子组件确定了最大大小,子组件不能超过指定大小。
                //PRECISE 父组件已确定子组件的大小。
                //UNCONSTRAINT 父组件对子组件没有约束,表示子组件可以任意大小。
                Component.EstimateSpec.getChildSizeWithMode(w,w, EstimateSpec.NOT_EXCEED),
                Component.EstimateSpec.getChildSizeWithMode(h,h, EstimateSpec.NOT_EXCEED)
        );
        return true;
    }

    // 圆环宽度
    private static final float CIRCLE_STROKE_WIDTH = 50f;
    // 绘制圆环的画笔
    private Paint paint;

    public void initPaint(){
        //创建画笔
        paint=new Paint();
        //设置画笔颜色
        paint.setColor(Color.BLUE);
        //设置线条宽度
        paint.setStrokeWidth(CIRCLE_STROKE_WIDTH);
        //设置线条样式
        //STROKE_STYLE 空心线条
        //FILL_STYLE 实心
        //FILLANDSTROKE_STYLE实心和边框线条
        paint.setStyle(Paint.Style.FILL_STYLE);
        //设置绘制文字大小
        paint.setTextSize(60);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        //绘制图形

        // 在界面中绘制一个圆心坐标为(500,500),半径为400的圆
        canvas.drawCircle(200,400,100,paint);
        //左上角坐标点为(100,100),右下角坐标点为(200,200),绘制一个正方形
        canvas.drawRect(100,100,200,200,paint);
        //绘制文字
        canvas.drawChars(paint,new char[]{'你','好','鸿','蒙'},100,700);
        canvas.drawCharSequence(paint,"加油华为",100,900);
        //画线
        canvas.drawLine(500,100,700,500,paint);
        //画点
        canvas.drawPoint(900,900,paint);
        //画三角形
        canvas.drawLines(new float[]{400,700,600,800,
                600,800,500,600,
                500,600,400,700},paint);
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        switch (touchEvent.getAction()){
            case TouchEvent.PRIMARY_POINT_DOWN:
                //自定义组件被按下,改变颜色为红色,并重新绘制,刷新图层
                paint.setColor(Color.RED);
                invalidate();
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                paint.setColor(Color.BLUE);
                invalidate();
                break;
        }
        //记得将返回值改为true,表示该监听事件允许回传
        return true;
    }
}

 界面完整代码如下:

package com.example.hm_phone_java.slice;

import com.example.hm_phone_java.ResourceTable;
import com.example.hm_phone_java.views.CustomComponent;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.DirectionalLayout;

public class OneCustomComponentAbilitySlice extends AbilitySlice {

    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);
        DirectionalLayout myLayout=new DirectionalLayout(this);
        DirectionalLayout.LayoutConfig config = new DirectionalLayout.LayoutConfig(
                DirectionalLayout.LayoutConfig.MATCH_PARENT, DirectionalLayout.LayoutConfig.MATCH_PARENT);
        myLayout.setLayoutConfig(config);

        CustomComponent customComponent = new CustomComponent(this);
        DirectionalLayout.LayoutConfig layoutConfig = new DirectionalLayout.LayoutConfig(1080, 1000);
        customComponent.setLayoutConfig(layoutConfig);

        myLayout.addComponent(customComponent);
        super.setUIContent(myLayout);
    }
}

并将该界面的类名添加至MainAbility进行引用,接着开启华为模拟器即可看到自定义控件的效果。

初次学习鸿蒙的自定义控件,大家如果掌握的,可以自行绘制图形,比如五边形,六边形,五角星等等

下一篇文章将带着大家使用鸿蒙开发学习自定义组件绘制五星红旗,尽请期待

今天就分享到这里,感谢大家的关注和阅读,因最近工作比较繁忙,没有及时更新文章!!!

下一篇 【鸿蒙】HarMonyOS的自定义组件之五星好评

猜你喜欢

转载自blog.csdn.net/u010321564/article/details/118712664