f SQL-Server-鸿蒙Harmony开发实战:自定义圆形组件-Canvas - Powered by qidao123.com技术社区

鸿蒙Harmony开发实战:自定义圆形组件-Canvas

打印 上一主题 下一主题

主题 1732|帖子 1732|积分 5196

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在接纳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末了输出的图片为圆形,必要将图片在结构中的宽度和高度设置成一样,否则输出的为圆角矩形大概椭圆形。
末了封装后的详细代码如下:
  1. package com.xdw.customview;
  2. import ohos.agp.components.AttrSet;
  3. import ohos.agp.components.Image;
  4. import ohos.agp.render.PixelMapHolder;
  5. import ohos.agp.utils.RectFloat;
  6. import ohos.app.Context;
  7. import ohos.hiviewdfx.HiLog;
  8. import ohos.hiviewdfx.HiLogLabel;
  9. import ohos.media.image.ImageSource;
  10. import ohos.media.image.PixelMap;
  11. import ohos.media.image.common.PixelFormat;
  12. import ohos.media.image.common.Rect;
  13. import ohos.media.image.common.Size;
  14. import java.io.InputStream;
  15. /**
  16. * Created by 夏德旺 on 2021/1/1 11:00
  17. */
  18. public class RoundImage extends Image {
  19.     private static final HiLogLabel LABEL = new HiLogLabel(HiLog.DEBUG, 0, "RoundImage");
  20.     private PixelMapHolder pixelMapHolder;//像素图片持有者
  21.     private RectFloat rectDst;//目标区域
  22.     private RectFloat rectSrc;//源区域
  23.     public RoundImage(Context context) {
  24.         this(context,null);
  25.     }
  26.     public RoundImage(Context context, AttrSet attrSet) {
  27.         this(context,attrSet,null);
  28.     }
  29.     /**
  30.      * 加载包含该控件的xml布局,会执行该构造函数
  31.      * @param context
  32.      * @param attrSet
  33.      * @param styleName
  34.      */
  35.     public RoundImage(Context context, AttrSet attrSet, String styleName) {
  36.         super(context, attrSet, styleName);
  37.         HiLog.error(LABEL,"RoundImage");
  38.     }
  39.     public void onRoundRectDraw(int radius){
  40.         //添加绘制任务
  41.         this.addDrawTask((view, canvas) -> {
  42.             if (pixelMapHolder == null){
  43.                 return;
  44.             }
  45.             synchronized (pixelMapHolder) {
  46.                 //给目标区域赋值,宽度和高度取自xml配置文件中的属性
  47.                 rectDst = new RectFloat(0,0,getWidth(),getHeight());
  48.                 //绘制圆角图片
  49.                 canvas.drawPixelMapHolderRoundRectShape(pixelMapHolder, rectSrc, rectDst, radius, radius);
  50.                 pixelMapHolder = null;
  51.             }
  52.         });
  53.     }
  54.     //使用canvas绘制圆形
  55.     private void onCircleDraw(){
  56.         //添加绘制任务,自定义组件的核心api调用,该接口的参数为Component下的DrawTask接口
  57.         this.addDrawTask((view, canvas) -> {
  58.             if (pixelMapHolder == null){
  59.                 return;
  60.             }
  61.             synchronized (pixelMapHolder) {
  62.                 //给目标区域赋值,宽度和高度取自xml配置文件中的属性
  63.                 rectDst = new RectFloat(0,0,getWidth(),getHeight());
  64.                 //使用canvas绘制输出圆角矩形的位图,该方法第4个参数和第5个参数为radios参数,
  65.                 // 绘制图片,必须把图片的宽度和高度先设置成一样,然后把它们设置为图片宽度或者高度一半时则绘制的为圆形
  66.                 canvas.drawPixelMapHolderRoundRectShape(pixelMapHolder, rectSrc, rectDst, getWidth()/2, getHeight()/2);
  67.                 pixelMapHolder = null;
  68.             }
  69.         });
  70.     }
  71.     /**
  72.      *获取原有Image中的位图资源后重新检验绘制该组件
  73.      * @param pixelMap
  74.      */
  75.     private void putPixelMap(PixelMap pixelMap){
  76.         if (pixelMap != null) {
  77.             rectSrc = new RectFloat(0, 0, pixelMap.getImageInfo().size.width, pixelMap.getImageInfo().size.height);
  78.             pixelMapHolder = new PixelMapHolder(pixelMap);
  79.             invalidate();//重新检验该组件
  80.         }else{
  81.             pixelMapHolder = null;
  82.             setPixelMap(null);
  83.         }
  84.     }
  85.     /**
  86.      * 通过资源ID获取位图对象
  87.      **/
  88.     private PixelMap getPixelMap(int resId) {
  89.         InputStream drawableInputStream = null;
  90.         try {
  91.             drawableInputStream = getResourceManager().getResource(resId);
  92.             ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
  93.             sourceOptions.formatHint = "image/png";
  94.             ImageSource imageSource = ImageSource.create(drawableInputStream, null);
  95.             ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
  96.             decodingOptions.desiredSize = new Size(0, 0);
  97.             decodingOptions.desiredRegion = new Rect(0, 0, 0, 0);
  98.             decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888;
  99.             PixelMap pixelMap = imageSource.createPixelmap(decodingOptions);
  100.             return pixelMap;
  101.         } catch (Exception e) {
  102.             e.printStackTrace();
  103.         } finally {
  104.             try{
  105.                 if (drawableInputStream != null){
  106.                     drawableInputStream.close();
  107.                 }
  108.             }catch (Exception e) {
  109.                 e.printStackTrace();
  110.             }
  111.         }
  112.         return null;
  113.     }
  114.     /**
  115.      * 对外调用的api,设置圆形图片方法
  116.      * @param resId
  117.      */
  118.     public void setPixelMapAndCircle(int resId){
  119.         PixelMap pixelMap = getPixelMap(resId);
  120.         putPixelMap(pixelMap);
  121.         onCircleDraw();
  122.     }
  123.     /**
  124.      * 对外调用的api,设置圆角图片方法
  125.      * @param resId
  126.      * @param radius
  127.      */
  128.     public void setPixelMapAndRoundRect(int resId,int radius){
  129.         PixelMap pixelMap = getPixelMap(resId);
  130.         putPixelMap(pixelMap);
  131.         onRoundRectDraw(radius);
  132.     }
  133. }
复制代码
5、修改config.json文件,代码如下
  1. {
  2.   "app": {
  3.     "bundleName": "com.xdw.customview",
  4.     "vendor": "xdw",
  5.     "version": {
  6.       "code": 1,
  7.       "name": "1.0"
  8.     },
  9.     "apiVersion": {
  10.       "compatible": 4,
  11.       "target": 4,
  12.       "releaseType": "Beta1"
  13.     }
  14.   },
  15.   "deviceConfig": {},
  16.   "module": {
  17.     "package": "com.xdw.customview",
  18.     "deviceType": [
  19.       "phone",
  20.       "tv",
  21.       "tablet",
  22.       "car",
  23.       "wearable"
  24.     ],
  25.     "reqPermissions": [
  26.       {
  27.         "name": "ohos.permission.INTERNET"
  28.       }
  29.     ],
  30.     "distro": {
  31.       "deliveryWithInstall": true,
  32.       "moduleName": "roundimage",
  33.       "moduleType": "har"
  34.     }
  35.   }
  36. }
复制代码
这样该模块就可以导出后续给其他全部工程引用了,后面还可以编译之后发布到gradle上直接通过添加依赖来进行使用(这个是后话),下面我们先通过当地依赖导入的方式来调用这个自定义组件模块吧。
四、其他工程调用该自定义组件并测试效果
1、再来新建一个工程,然后将之前的模块导入到新建的工程中(DevEco暂时不支持自动导入外部模块的利用,必要手动导入利用,请关注我的另外一篇博客)
2、在gradle中引用导入的模块的组件,代码如下:
  1. dependencies {
  2.     entryImplementation project(':entry')
  3.     implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
  4.     testCompile'junit:junit:4.12'
  5. }
复制代码
3、在结构中引用自定义的圆形图片,代码如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <DirectionalLayout
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos"
  4.     ohos:height="match_parent"
  5.     ohos:width="match_parent"
  6.     ohos:orientation="vertical">
  7.     <Text
  8.         ohos:id="$+id:text_helloworld"
  9.         ohos:height="match_content"
  10.         ohos:width="match_content"
  11.         ohos:background_element="$graphic:background_ability_main"
  12.         ohos:layout_alignment="horizontal_center"
  13.         ohos:text="Hello World"
  14.         ohos:text_size="50"
  15.         />
  16.     <com.xdw.customview.RoundImage
  17.         ohos:id="$+id:image"
  18.         ohos:height="200vp"
  19.         ohos:width="200vp"/>
  20. </DirectionalLayout>
复制代码
4、在Java代码中进行调用,代码如下:
  1. package com.example.testcustomview.slice;
  2. import com.example.testcustomview.ResourceTable;
  3. import com.xdw.customview.RoundImage;
  4. import ohos.aafwk.ability.AbilitySlice;
  5. import ohos.aafwk.content.Intent;
  6. public class MainAbilitySlice extends AbilitySlice {
  7.     @Override
  8.     public void onStart(Intent intent) {
  9.         super.onStart(intent);
  10.         super.setUIContent(ResourceTable.Layout_ability_main);
  11.         RoundImage roundImage = (RoundImage) findComponentById(ResourceTable.Id_image);
  12.         roundImage.setPixelMapAndCircle(ResourceTable.Media_man);
  13.     }
  14.     @Override
  15.     public void onActive() {
  16.         super.onActive();
  17.     }
  18.     @Override
  19.     public void onForeground(Intent intent) {
  20.         super.onForeground(intent);
  21.     }
  22. }
复制代码
5、开启手机模仿器进行测试,效果如下


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

慢吞云雾缓吐愁

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表