HarmonyOS App开发造轮子--自定义圆形图片

news2025/1/15 16:57:06

思路:

1、对比之前自己在其他程序开发中自定义组件的思路,首先寻找父组件Image和Component相关的Api,看看是否具备OnDraw方法。

2、了解Canvas相关Api操作,特别是涉及到位图的操作。

通过翻阅大量资料,发现了两个关键的api,分别是Component的addDrawTask方法和其内部静态接口DrawTask

#2020征文-手机# HarmonyOS App开发造轮子--自定义圆形图片组件-鸿蒙开发者社区

#2020征文-手机# HarmonyOS App开发造轮子--自定义圆形图片组件-鸿蒙开发者社区

三、自定义组件模块

1、新建一个工程之后,创建一个独立的Java FA模块,然后删除掉里面所有布局以及自动生成的java代码,然后自己创建一个class继承ImageView

2、写一个类继承ImageView,在其中暴露出public的设置圆形图片的api方法以供后面调用;

3、在原有的Image组件获取到位图之后,利用该位图数据利用addDrawTask方法配合Canvas进行位图输出形状的重新绘制,这里需要使用Canvas的一个

关键api方法drawPixelMapHolderRoundRectShape;

4、注意,为了让Canvas最后输出的图片为圆形,需要将图片在布局中的宽度和高度设置成一样,否则输出的为圆角矩形或者椭圆形。

最后封装后的详细代码如下:

package com.xdw.customview;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Image;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Rect;
import ohos.media.image.common.Size;

import java.io.InputStream;

/**
 * Created by 夏德旺 on 2021/1/1 11:00
 */
public class RoundImage extends Image {
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.DEBUG, 0, "RoundImage");
    private PixelMapHolder pixelMapHolder;//像素图片持有者
    private RectFloat rectDst;//目标区域
    private RectFloat rectSrc;//源区域
    public RoundImage(Context context) {
        this(context,null);

    }

    public RoundImage(Context context, AttrSet attrSet) {
        this(context,attrSet,null);
    }

    /**
     * 加载包含该控件的xml布局,会执行该构造函数
     * @param context
     * @param attrSet
     * @param styleName
     */
    public RoundImage(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        HiLog.error(LABEL,"RoundImage");
    }



    public void onRoundRectDraw(int radius){
        //添加绘制任务
        this.addDrawTask((view, canvas) -> {
            if (pixelMapHolder == null){
                return;
            }
            synchronized (pixelMapHolder) {
                //给目标区域赋值,宽度和高度取自xml配置文件中的属性
                rectDst = new RectFloat(0,0,getWidth(),getHeight());
                //绘制圆角图片
                canvas.drawPixelMapHolderRoundRectShape(pixelMapHolder, rectSrc, rectDst, radius, radius);
                pixelMapHolder = null;
            }
        });
    }

    //使用canvas绘制圆形
    private void onCircleDraw(){
        //添加绘制任务,自定义组件的核心api调用,该接口的参数为Component下的DrawTask接口
        this.addDrawTask((view, canvas) -> {
            if (pixelMapHolder == null){
                return;
            }
            synchronized (pixelMapHolder) {
                //给目标区域赋值,宽度和高度取自xml配置文件中的属性
                rectDst = new RectFloat(0,0,getWidth(),getHeight());
                //使用canvas绘制输出圆角矩形的位图,该方法第4个参数和第5个参数为radios参数,
                // 绘制图片,必须把图片的宽度和高度先设置成一样,然后把它们设置为图片宽度或者高度一半时则绘制的为圆形
                canvas.drawPixelMapHolderRoundRectShape(pixelMapHolder, rectSrc, rectDst, getWidth()/2, getHeight()/2);
                pixelMapHolder = null;
            }
        });
    }


    /**
     *获取原有Image中的位图资源后重新检验绘制该组件
     * @param pixelMap
     */
    private void putPixelMap(PixelMap pixelMap){
        if (pixelMap != null) {
            rectSrc = new RectFloat(0, 0, pixelMap.getImageInfo().size.width, pixelMap.getImageInfo().size.height);
            pixelMapHolder = new PixelMapHolder(pixelMap);
            invalidate();//重新检验该组件
        }else{
            pixelMapHolder = null;
            setPixelMap(null);
        }
    }


    /**
     * 通过资源ID获取位图对象
     **/
    private PixelMap getPixelMap(int resId) {
        InputStream drawableInputStream = null;
        try {
            drawableInputStream = getResourceManager().getResource(resId);
            ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
            sourceOptions.formatHint = "image/png";
            ImageSource imageSource = ImageSource.create(drawableInputStream, null);
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
            decodingOptions.desiredSize = new Size(0, 0);
            decodingOptions.desiredRegion = new Rect(0, 0, 0, 0);
            decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888;
            PixelMap pixelMap = imageSource.createPixelmap(decodingOptions);
            return pixelMap;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try{
                if (drawableInputStream != null){
                    drawableInputStream.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 对外调用的api,设置圆形图片方法
     * @param resId
     */
    public void setPixelMapAndCircle(int resId){
        PixelMap pixelMap = getPixelMap(resId);
        putPixelMap(pixelMap);
        onCircleDraw();
    }

    /**
     * 对外调用的api,设置圆角图片方法
     * @param resId
     * @param radius
     */
    public void setPixelMapAndRoundRect(int resId,int radius){
        PixelMap pixelMap = getPixelMap(resId);
        putPixelMap(pixelMap);
        onRoundRectDraw(radius);
    }
}

5、修改config.json文件,代码如下

{
  "app": {
    "bundleName": "com.xdw.customview",
    "vendor": "xdw",
    "version": {
      "code": 1,
      "name": "1.0"
    },
    "apiVersion": {
      "compatible": 4,
      "target": 4,
      "releaseType": "Beta1"
    }
  },
  "deviceConfig": {},
  "module": {
    "package": "com.xdw.customview",
    "deviceType": [
      "phone",
      "tv",
      "tablet",
      "car",
      "wearable"
    ],
    "reqPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ],
    "distro": {
      "deliveryWithInstall": true,
      "moduleName": "roundimage",
      "moduleType": "har"
    }
  }
}

这样该模块就可以导出后续给其他所有工程引用了,后面还可以编译之后发布到gradle上直接通过添加依赖来进行使用(这个是后话),下面我们先通过本地依赖导入的方式来调用这个自定义组件模块吧。

四、其他工程调用该自定义组件并测试效果

1、再来新建一个工程,然后将之前的模块导入到新建的工程中(DevEco暂时不支持自动导入外部模块的操作,需要手动导入操作,请关注我的另外一篇博客)

2、在gradle中引用导入的模块的组件,代码如下:

dependencies {
    entryImplementation project(':entry')
    implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
    testCompile'junit:junit:4.12'
}

3、在布局中引用自定义的圆形图片,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:orientation="vertical">

    <Text
        ohos:id="$+id:text_helloworld"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:background_element="$graphic:background_ability_main"
        ohos:layout_alignment="horizontal_center"
        ohos:text="Hello World"
        ohos:text_size="50"
        />

    <com.xdw.customview.RoundImage
        ohos:id="$+id:image"
        ohos:height="200vp"
        ohos:width="200vp"/>
</DirectionalLayout>

4、在Java代码中进行调用,代码如下:

package com.example.testcustomview.slice;

import com.example.testcustomview.ResourceTable;
import com.xdw.customview.RoundImage;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;

public class MainAbilitySlice extends AbilitySlice {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        RoundImage roundImage = (RoundImage) findComponentById(ResourceTable.Id_image);
        roundImage.setPixelMapAndCircle(ResourceTable.Media_man);
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}

5、开启手机模拟器进行测试,效果如下

#2020征文-手机# HarmonyOS App开发造轮子--自定义圆形图片组件-鸿蒙开发者社区

最后

如果你想快速提升鸿蒙技术,那么可以直接领取这份包含了:【OpenHarmony多媒体技术、Stage模型、ArkUI多端部署、分布式应用开发、音频、视频、WebGL、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战】等技术知识点。

鸿蒙Next全套VIP学资料←点击领取!(安全链接,放心点击

1.鸿蒙核心技术学习路线

2.大厂面试必问面试题

3.鸿蒙南向开发技术

 4.鸿蒙APP开发必备

 5.HarmonyOS Next 最新全套视频教程

 6.鸿蒙生态应用开发白皮书V2.0PDF

这份全套完整版的学习资料已经全部打包好,朋友们如果需要可以点击→鸿蒙Next全套VIP学习资料免费领取(安全链接,放心点击

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1791171.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【漏洞复现】Apache OFBiz 路径遍历导致RCE漏洞(CVE-2024-36104)

0x01 产品简介 Apache OFBiz是一个电子商务平台&#xff0c;用于构建大中型企业级、跨平台、跨数据库、跨应用服务器的多层、分布式电子商务类应用系统。是美国阿帕奇(Apache)基金会的一套企业资源计划(ERP)系统。该系统提供了一整套基于Java的Web应用程序组件和工具。 0x02 …

德克萨斯大学奥斯汀分校自然语言处理硕士课程汉化版(第五周) - Transformer

Transformer 1. 注意力机制 在语言建模中&#xff0c;注意力(attention)是一个关键机制&#xff0c;用于在给定上下文中访问相关信息以进行预测。注意力机制允许模型根据输入上下文中的重要信息来加权关注不同的部分&#xff0c;并根据其重要性来决定对不同部分的关注程度。 …

C#操作MySQL从入门到精通(10)——对查询数据进行通配符过滤

前言 我们有时候需要查询数据,并且这个数据包含某个字符串,这时候我们再使用where就无法实现了,所以mysql中提供了一种模糊查询机制,通过Like关键字来实现,下面进行详细介绍: 本次查询的表中数据如下: 1、使用(%)通配符 %通配符的作用是,表示任意字符出现任意次数…

C++ list链表的使用和简单模拟实现

目录 前言 1. list的简介 2.list讲解和模拟实现 2.1 默认构造函数和push_back函数 2.2 迭代器实现 2.2.1 非const正向迭代器 2.2.2 const正向迭代器 2.2.3 反向迭代器 2.3 插入删除函数 2.3.1 insert和erase 2.3.2 push_back pop_back push_front pop_front 2.4 构…

QT+FFmpeg+Windows开发环境搭建(加薪点)

01、Windows 环境搭建 FFMPEG官网:http://ffmpeg.org/ 02、下载4.2.1版本源码 源码:https://ffmpeg.org/releases/ffmpeg-4.2.1.tar.bz2 03、下载4.2.1编译好的文件 下载已经编译好的FFMPEG)(迅雷下载很快) 网址:https://ffmpeg.zeranoe.com/builds/ 32位下载地址:(迅雷…

这家公司的39亿存款,无法收回了?

新闻提要 4日晚间&#xff0c;亿利洁能发布公告称&#xff0c;亿利财务公司对于公司存放在亿利财务公司的 39.06 亿元货币资金的用途主要是向亿利集团及其关联方发放贷款&#xff0c;近日公司获悉相关贷款已被划分为次级贷款&#xff08;不良贷款的一种&#xff09;&#xff0…

重大变化,2024软考!

根据官方发布的2024年度计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试安排&#xff0c;2024年软考上、下半年开考科目有着巨大变化&#xff0c;我为大家整理了相关信息&#xff0c;大家可以看看&#xff01; &#x1f3af;2024年上半年&#xff1a;5月25日&am…

特征工程及python实现

一、特征构建 概述 从原始数据中构建新的特征&#xff0c;一般需要根据业务分析&#xff0c;生成能更好体现业务特性的新特征&#xff0c;这些新特征要与目标关系紧密&#xff0c;能提升模型表现或更好地解释模型。 方法 时间周期&#xff1a;不同的时间切片长度&#xff0…

Linux信号大揭秘-从中断到控制进程,一步步掌握进程通信利器!

在Linux环境下&#xff0c;信号(Signal)是一种软件中断&#xff0c;用于通知进程发生了某些重要事件。无论你是在编写命令行工具、服务程序&#xff0c;还是开发图形界面应用&#xff0c;都离不开对信号的处理。本文将全面解析信号的工作原理&#xff0c;并通过实例代码让你彻底…

实用软件分享---简单菜谱 0.3版本 几千种美食(安卓)

专栏介绍:本专栏主要分享一些实用的软件(Po Jie版); 声明1:软件不保证时效性;只能保证在写本文时,该软件是可用的;不保证后续时间该软件能一直正常运行;不保证没有bug;如果软件不可用了,我知道后会第一时间在题目上注明(已失效)。介意者请勿订阅。 声明2:本专栏的…

重生之 SpringBoot3 入门保姆级学习(14、内容协商基础简介)

重生之 SpringBoot3 入门保姆级学习&#xff08;14、内容协商基础简介&#xff09; 3.3 内容协商3.3.1 基础简介3.3.2 演示效果 3.3 内容协商 3.3.1 基础简介 默认规则 基于请求头的内容协商&#xff08;默认开启&#xff09; 客户端向服务器发送请求&#xff0c;携带 HTTP 标…

大归纳!!教你使用<string.h>的字符函数与字符串函数!!☑

这篇博客为你归纳了所有的字符函数和最常用的字符串函数&#xff0c;以及对应的模拟实现&#xff01;&#xff01;你可以直接循着目录跳到你需要的段落哦&#xff01;&#xff01;&#x1f60d; 目录 字符函数 字符分类 字符判断函数 islower——判断小写字母 isupper——…

上位机图像处理和嵌入式模块部署(f407 mcu中的udp server开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 既然lwip已经port到407上面了&#xff0c;接下来其实就可以做一些测试了。本身lwip支持tcp、udp&#xff0c;也支持client和server&#xff0c;既然…

Qt信号槽与函数直接调用性能对比

1. 测试方法 定义一个类Recv&#xff0c;其中包含一个成员变量num和一个成员函数add()&#xff0c;add()实现num的递增。 另一个类Send通过信号槽或直接调用的方法调用Recv的add函数。 单独开一个线程Watcher&#xff0c;每秒计算num变量的增长数值&#xff0c;作为add函数被调…

STL中vector动态二维数组理解(杨辉三角)

题目链接&#xff1a;118.杨辉三角 题目描述&#xff1a; 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 题目指要&#xff1a; 本题的主要目的是理解vector<vector<int&…

编译原理总结

编译器构成 1. 前端分析部分 1.1 词法分析 确定词性&#xff0c;输出为token序列 1.2 语法分析 识别短语 1.3 语义分析 分析短语在句子中的成分 IR中间代码生成 2. 机器无关代码优化 3. 后端综合部分 目标代码生成 机器相关代码优化 4. 其他 全局信息表 异常输出

电影推荐系统配置运行

电影推荐系统配置运行 代码地址项目介绍&#xff08;引自原文&#xff09; 环境创建新环境激活环境安装包创建管理员用户(可选)启动 代码地址 movie 项目介绍&#xff08;引自原文&#xff09; 本推荐系统采用的是分层模型设计思想&#xff0c;第一层为前端页面模型设计&…

2024.6.5

1、react原理学习&#xff0c; hook、fiber 2、瀑布流组件完善 3、代码随想录二刷

【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【06】【商品服务】接口文档地址_三级分类_SPU_SKU

持续学习&持续更新中… 学习态度&#xff1a;守破离 【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【06】【商品服务】接口文档地址_三级分类_SPU_SKU 接口文档地址三级分类效果图建表后台组建数据的树形结构在人人(后台管理系统)中实现管理商品的三级分类路径规则使用…

DRIVEN|15分的CNN+LightGBM怎么做特征分类,适用于转录组

说在前面 今天分享一篇做深度学习模型的文章&#xff0c;这是一篇软硬结合的研究&#xff0c;排除转换实体产品&#xff0c;我们做生信基础研究的可以学习模仿这个算法&#xff0c;适用且不局限于临床资料&#xff0c;转录组数据&#xff0c;GWAS数据。 今天给大家分享的一篇文…