鸿蒙HarmonyOS App开发造轮子之自定义圆形图片组件的实例代码

一、背景

在采用Java配合xml布局编写鸿蒙app页面的时候,发现sdk自带的Image组件并不能将图片设置成圆形,反复了翻阅了官方API手册(主要查阅了Compont和Image相关的API),起初发现了一个setCornerRadius方法,于是想着将图片宽度和高度设置为一样,然后调用该方法将radios设置为宽度或者高度的一半,以为可以实现圆形图片的效果,后来发现不行。于是乎想着能不能通过继承原有的Image自己来动手重新自定义一个支持圆形的图片组件。

二、思路:

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

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

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

三、自定义组件模块

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);
 }
}

到此这篇关于鸿蒙HarmonyOS App开发造轮子之自定义圆形图片组件的文章就介绍到这了,更多相关鸿蒙HarmonyOS自定义圆形图片组件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 鸿蒙开源第三方组件之连续滚动图像组件功能

    前言 基于安卓平台的连续滚动图像组件ContinuousScrollableImageView(https://github.com/Cutta/ContinuousScrollableImageView),实现了鸿蒙化迁移和重构,代码已经开源到(https://gitee.com/isrc_ohos/continuous-scrollable-image-view_ohos),欢迎各位开发者下载使用并提出宝贵意见! 背景 ContinuousScrollableImageView_ohos组件

  • 鸿蒙自定义组件之鸿蒙画板

    初识鸿蒙OS 2.0 华为的鸿蒙OS 2.0是目前唯一个有希望和安卓.IOS对抗的全新生态系统.9月10日,在东莞正式发布.华为喊出了"HarmonyOS 2.0 连接无限可能"的口号,将是未来十年很有竞争力的优秀操作系统. 自定义Component 这里我编写一个简易的画板. 1.新建一个类DrawComponment 继承自Componment: 2.实现Component.TouchEventListener,用于对touch事件生成相应的path: 3.实现Component.

  • 鸿蒙HarmonyOS App开发造轮子之自定义圆形图片组件的实例代码

    一.背景 在采用Java配合xml布局编写鸿蒙app页面的时候,发现sdk自带的Image组件并不能将图片设置成圆形,反复了翻阅了官方API手册(主要查阅了Compont和Image相关的API),起初发现了一个setCornerRadius方法,于是想着将图片宽度和高度设置为一样,然后调用该方法将radios设置为宽度或者高度的一半,以为可以实现圆形图片的效果,后来发现不行.于是乎想着能不能通过继承原有的Image自己来动手重新自定义一个支持圆形的图片组件. 二.思路: 1.对比之前自己在其他

  • Android 实现自定义圆形listview功能的实例代码

    最近遇到一个需求需要圆形listview作为悬浮窗,费了九牛二虎之力终于开发出来了,特别有成就感,下面分享下案例,项目原因,只能分享一部分供大家参考 1.有图有真相 下面就来讲解下代码: 1.自定义listview import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory;

  • 使用Vue 自定义文件选择器组件的实例代码

    本文 GitHub  https://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料.欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西. 文件选择元素是web上最难看的 input 类型之一.它们在每个浏览器中实现的方式不同,而且通常非常难看.这里有一个解决办法,就是把它封装成一个组件. 安装 如果你尚未设置项目,可以使用 vue-cli 的 webpack-simple 模板启动一个新项目. $ npm

  • Android 实现自定义圆形进度条的实例代码

    Android 自定义圆形进度条 今天无意中发现一个圆形进度,想想自己实现一个,如下图: 基本思路是这样的: 1.首先绘制一个实心圆 2.绘制一个白色实心的正方形,遮住实心圆 3.在圆的中心动态绘制当前进度的百分比字符 4.绘制一个与之前实心圆相同颜色的空心圆 5.逐渐改变当前的百分比 6.根据百分比,逐渐改变正方形的大小,逐渐减小正方形的底部y轴的坐标,不断重绘,直到达到100% 首先看看自定义的属性 在values目录下新建attrs.xml内容如下: 定义绘制圆形的背景色,和绘制圆形的半径

  • Android自定义水波纹动画Layout实例代码

    话不多说,我们先来看看效果: Hi前辈搜索预览 这一张是<Hi前辈>的搜索预览图,你可以在这里下载这个APP查看更多效果: http://www.wandoujia.com/apps/com.superlity.hiqianbei LSearchView 这是一个MD风格的搜索框,集成了ripple动画以及search时的loading,使用很简单,如果你也需要这样的搜索控件不妨来试试:https://github.com/onlynight/LSearchView RippleEverywh

  • Android 中TabLayout自定义选择背景滑块的实例代码

    TabLayout是Android 的Material Design包中的一个控件,可以和V4包中的ViewPager搭配产生一个联动的效果.这里我自定义了一个滑块能够跟随TabLayout进行滑动选择的SliderLayout.效果见下图(白色方框): 下面是SliderLayout的源码: import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawabl

  • Android自定义指示器时间轴效果实例代码详解

    指示器时间轴在外卖.购物类的APP里会经常用到,效果大概就像下面这样,看了网上很多文章,大都是自己绘制,太麻烦,其实通过ListView就可以实现. 在Activity关联的布局文件activity_main.xml中放置一个ListView,代码如下.由于这个列表只是用于展示信息,并不需要用户去点击,所以将其clickable属性置为false:为了消除ListView点击产生的波纹效果,我们设置其listSelector属性的值为透明:我们不需要列表项之间的分割线,所以设置其divider属

  • Android自定义view实现圆环效果实例代码

    先上效果图,如果大家感觉不错,请参考实现代码.           重要的是如何实现自定义的view效果 (1)创建类,继承view,重写onDraw和onMesure方法 public class CirclePercentBar extends View{ private Context mContext; private int mArcColor; private int mArcWidth; private int mCenterTextColor; private int mCent

  • 微信小程序自定义音乐进度条的实例代码

    需求:显示音乐播放按钮.可手动拖拽进度条:页面中含多个音乐,播放当前音乐时暂停其他音乐播放. 小程序自带标签 audio 小程序自带的audio标签含固定的样式,且有最小尺寸.目前项目也不含name和author字段,所以放弃audio标签. 实现效果图 初始化音乐数据 <text>{{currentProcess}}</text> <slider bindchange="" bindtouchstart="" bindtouchend

  • android 自定义圆角button效果的实例代码(自定义view Demo)

    概述 在平时开发过程中经常会碰到需要使用圆角button的情况,一般也会包括很多其他小功能,比如要在里面添加img,设置不同的圆角大小等. 针对这样的场景,直接使用创建多个shape,定义多个xml文件也是可以实现的.但是如果使用非常频繁,那么直接自定义一个就会来的非常方便. 甚至在一些情况下,不是可以用shape定义的规则图形,比如需要用到贝塞尔曲线等. 如果全局需要这样风格的view,那么自定义一个View是非常必要的. 本文主要是个demo记录,如有需要的读者可以借鉴学习. Demo 主要

随机推荐