文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

鸿蒙HarmonyOS App开发造轮子-自定义圆形图片组件

2024-12-03 13:36

关注

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com/ 

一、背景

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

二、思路

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

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

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



三、自定义组件模块

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

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

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

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

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

  1. package com.xdw.customview; 
  2.  
  3. import ohos.agp.components.AttrSet; 
  4. import ohos.agp.components.Image; 
  5. import ohos.agp.render.PixelMapHolder; 
  6. import ohos.agp.utils.RectFloat; 
  7. import ohos.app.Context; 
  8. import ohos.hiviewdfx.HiLog; 
  9. import ohos.hiviewdfx.HiLogLabel; 
  10. import ohos.media.image.ImageSource; 
  11. import ohos.media.image.PixelMap; 
  12. import ohos.media.image.common.PixelFormat; 
  13. import ohos.media.image.common.Rect; 
  14. import ohos.media.image.common.Size
  15.  
  16. import java.io.InputStream; 
  17.  
  18.  
  19. public class RoundImage extends Image { 
  20.     private static final HiLogLabel LABEL = new HiLogLabel(HiLog.DEBUG, 0, "RoundImage"); 
  21.     private PixelMapHolder pixelMapHolder;//像素图片持有者 
  22.     private RectFloat rectDst;//目标区域 
  23.     private RectFloat rectSrc;//源区域 
  24.     public RoundImage(Context context) { 
  25.         this(context,null); 
  26.  
  27.     } 
  28.  
  29.     public RoundImage(Context context, AttrSet attrSet) { 
  30.         this(context,attrSet,null); 
  31.     } 
  32.  
  33.      
  34.     public RoundImage(Context context, AttrSet attrSet, String styleName) { 
  35.         super(context, attrSet, styleName); 
  36.         HiLog.error(LABEL,"RoundImage"); 
  37.     } 
  38.  
  39.  
  40.  
  41.     public void onRoundRectDraw(int radius){ 
  42.         //添加绘制任务 
  43.         this.addDrawTask((view, canvas) -> { 
  44.             if (pixelMapHolder == null){ 
  45.                 return
  46.             } 
  47.             synchronized (pixelMapHolder) { 
  48.                 //给目标区域赋值,宽度和高度取自xml配置文件中的属性 
  49.                 rectDst = new RectFloat(0,0,getWidth(),getHeight()); 
  50.                 //绘制圆角图片 
  51.                 canvas.drawPixelMapHolderRoundRectShape(pixelMapHolder, rectSrc, rectDst, radius, radius); 
  52.                 pixelMapHolder = null
  53.             } 
  54.         }); 
  55.     } 
  56.  
  57.     //使用canvas绘制圆形 
  58.     private void onCircleDraw(){ 
  59.         //添加绘制任务,自定义组件的核心api调用,该接口的参数为Component下的DrawTask接口 
  60.         this.addDrawTask((view, canvas) -> { 
  61.             if (pixelMapHolder == null){ 
  62.                 return
  63.             } 
  64.             synchronized (pixelMapHolder) { 
  65.                 //给目标区域赋值,宽度和高度取自xml配置文件中的属性 
  66.                 rectDst = new RectFloat(0,0,getWidth(),getHeight()); 
  67.                 //使用canvas绘制输出圆角矩形的位图,该方法第4个参数和第5个参数为radios参数, 
  68.                 // 绘制图片,必须把图片的宽度和高度先设置成一样,然后把它们设置为图片宽度或者高度一半时则绘制的为圆形 
  69.                 canvas.drawPixelMapHolderRoundRectShape(pixelMapHolder, rectSrc, rectDst, getWidth()/2, getHeight()/2); 
  70.                 pixelMapHolder = null
  71.             } 
  72.         }); 
  73.     } 
  74.  
  75.  
  76.      
  77.     private void putPixelMap(PixelMap pixelMap){ 
  78.         if (pixelMap != null) { 
  79.             rectSrc = new RectFloat(0, 0, pixelMap.getImageInfo().size.width, pixelMap.getImageInfo().size.height); 
  80.             pixelMapHolder = new PixelMapHolder(pixelMap); 
  81.             invalidate();//重新检验该组件 
  82.         }else
  83.             pixelMapHolder = null
  84.             setPixelMap(null); 
  85.         } 
  86.     } 
  87.  
  88.  
  89.      
  90.     private PixelMap getPixelMap(int resId) { 
  91.         InputStream drawableInputStream = null
  92.         try { 
  93.             drawableInputStream = getResourceManager().getResource(resId); 
  94.             ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions(); 
  95.             sourceOptions.formatHint = "image/png"
  96.             ImageSource imageSource = ImageSource.create(drawableInputStream, null); 
  97.             ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions(); 
  98.             decodingOptions.desiredSize = new Size(0, 0); 
  99.             decodingOptions.desiredRegion = new Rect(0, 0, 0, 0); 
  100.             decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888; 
  101.             PixelMap pixelMap = imageSource.createPixelmap(decodingOptions); 
  102.             return pixelMap; 
  103.         } catch (Exception e) { 
  104.             e.printStackTrace(); 
  105.         } finally { 
  106.             try{ 
  107.                 if (drawableInputStream != null){ 
  108.                     drawableInputStream.close(); 
  109.                 } 
  110.             }catch (Exception e) { 
  111.                 e.printStackTrace(); 
  112.             } 
  113.         } 
  114.         return null
  115.     } 
  116.  
  117.      
  118.     public void setPixelMapAndCircle(int resId){ 
  119.         PixelMap pixelMap = getPixelMap(resId); 
  120.         putPixelMap(pixelMap); 
  121.         onCircleDraw(); 
  122.     } 
  123.  
  124.      
  125.     public void setPixelMapAndRoundRect(int resId,int radius){ 
  126.         PixelMap pixelMap = getPixelMap(resId); 
  127.         putPixelMap(pixelMap); 
  128.         onRoundRectDraw(radius); 
  129.     } 

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

  1.   "app": { 
  2.     "bundleName""com.xdw.customview"
  3.     "vendor""xdw"
  4.     "version": { 
  5.       "code": 1, 
  6.       "name""1.0" 
  7.     }, 
  8.     "apiVersion": { 
  9.       "compatible": 4, 
  10.       "target": 4, 
  11.       "releaseType""Beta1" 
  12.     } 
  13.   }, 
  14.   "deviceConfig": {}, 
  15.   "module": { 
  16.     "package""com.xdw.customview"
  17.     "deviceType": [ 
  18.       "phone"
  19.       "tv"
  20.       "tablet"
  21.       "car"
  22.       "wearable" 
  23.     ], 
  24.     "reqPermissions": [ 
  25.       { 
  26.         "name""ohos.permission.INTERNET" 
  27.       } 
  28.     ], 
  29.     "distro": { 
  30.       "deliveryWithInstall"true
  31.       "moduleName""roundimage"
  32.       "moduleType""har" 
  33.     } 
  34.   } 

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

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

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

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

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

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

  1. "1.0" encoding="utf-8"?> 
  2.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  3.     ohos:height="match_parent" 
  4.     ohos:width="match_parent" 
  5.     ohos:orientation="vertical"
  6.  
  7.     
  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.  
  17.     
  18.         ohos:id="$+id:image" 
  19.         ohos:height="200vp" 
  20.         ohos:width="200vp"/> 
  21.  

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

  1. package com.example.testcustomview.slice; 
  2.  
  3. import com.example.testcustomview.ResourceTable; 
  4. import com.xdw.customview.RoundImage; 
  5. import ohos.aafwk.ability.AbilitySlice; 
  6. import ohos.aafwk.content.Intent; 
  7.  
  8. public class MainAbilitySlice extends AbilitySlice { 
  9.     @Override 
  10.     public void onStart(Intent intent) { 
  11.         super.onStart(intent); 
  12.         super.setUIContent(ResourceTable.Layout_ability_main); 
  13.         RoundImage roundImage = (RoundImage) findComponentById(ResourceTable.Id_image); 
  14.         roundImage.setPixelMapAndCircle(ResourceTable.Media_man); 
  15.     } 
  16.  
  17.     @Override 
  18.     public void onActive() { 
  19.         super.onActive(); 
  20.     } 
  21.  
  22.     @Override 
  23.     public void onForeground(Intent intent) { 
  24.         super.onForeground(intent); 
  25.     } 

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


©著作权归作者和HarmonyOS技术社区共同所有,如需转载,请注明出处,否则将追究法律责任。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com/

 

来源:鸿蒙社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯