更多内容请访问:与华为官方共建的鸿蒙技术社区https://harmonyos.51cto.com/#zz1.后台使用Java和xml时布局写鸿蒙app页面,发现sdk自带的Image组件无法将图片设置成圆形。反复看了官方的API手册(主要是查阅了Component和Image相关的API),发现最开始我创建了一个setCornerRadius方法,于是想着把图片的宽高设置成一样,然后调用这个方法将radio设置为半宽或者半高,以为可以实现圆形图片的效果,后来发现不行。于是就想能不能通过继承原来的Image重新定制一个圆形的图片组件。二、思路1、相对于之前其他程序开发中自定义组件的思路,先找父组件Image和Component相关的Api,看看有没有OnDraw方法。2.了解Canvas相关的Api操作,尤其是涉及位图的。看了很多资料,找到了两个关键的API,分别是Component的addDrawTask方法和它内部的静态接口DrawTask三、自定义组件模块1.新建一个项目后,新建一个独立的JavaFA模块,然后删除所有布局和自动生成java代码,然后创建类继承ImageView;2、写一个继承ImageView的类,其中暴露出设置圆形图片的公共API方法,供后面调用;3.在原始Image组件中获取位图后,使用位图数据使用addDrawTask方法配合Canvas重绘位图输出形状。这里需要用到Canvas的一个关键api方法drawPixelMapHolderRoundRectShape;4.注意为了让Canvas最终输出的图片是圆形的,需要在布局中设置图片的宽高相同,否则输出的会是圆角矩形或者椭圆。最终打包后的详细代码如下:应用程序。语境;importohos.hiviewdfx.HiLog;importohos.hiviewdfx.HiLogLabel;importohos.media.image.ImageSource;importohos.media.image.PixelMap;importohos.media.image.common.PixelFormat;importohos.media.image.common.Rect;importohos.media.image.common.Size;importjava.io.InputStream;/***创建者夏德旺于2021/1/111:00*/publicclassRoundImageextendsImage{privatestaticfinalHiLogLabelLABEL=newHiLogLabel(HiLog.DEBUG,0,"RoundImage");privatePixelMapHolderpixelMapHolder;//像素图像持有者privateRectFloatrectDst;//目标区域privateRectFloatrectSrc;//源区域publicRoundImage(Contextcontext){this(context,null);}publicRoundImage(Contextcontext,AttrSetattrSet){this(context,attrSet,null);}/***加载包含控件的xml布局,并执行构造函数*@paramcontext*@paramattrSet*@paramstyleName*/publicRoundImage(Contextcontext,AttrSetattrSet,StringstyleName){super(context,attrSet,styleName);HiLog.error(LABEL,"RoundImage");}publicvoidonRoundRectDraw(intradius){//添加绘图任务this.addDrawTask((view,canvas)->{if(pixelMapHolder==null){return;}synchronized(pixelMapHolder){//给目标区域赋值,宽高取自xml配置文件中的属性rectDst=newRectFloat(0,0,getWidth(),getHeight());//绘制圆角图片canvas.drawPixelMapHolderRoundRectShape(pixelMapHolder,rectSrc,rectDst,radius,radius);pixelMapHolder=null;}});//使用画布绘制圆privatevoidonCircleDraw(){//添加绘图任务,自定义组件核心api调用,该接口的参数为Component下的DrawTask接口this.addDrawTask((view,canvas)->{if(pixelMapHolder==null){return;}synchronized(pixelMapHolder){//给目标区域赋值,width和height取自xml配置文件中的属性rectDst=newRectFloat(0,0,getWidth(),getHeight());//使用即可vas绘制输出圆角矩形的位图,该方法的第四个参数和第五个参数是radios参数,//要绘制图片,首先要设置图片的宽高相同,然后将它们设置为图片宽度或高度的一半,然后绘制一个圆形canvas.drawPixelMapHolderRoundRectShape(pixelMapHolder,rectSrc,rectDst,getWidth()/2,getHeight()/2);pixelMapHolder=null;}});}/***获取原始Image中的位图资源,重新检查绘制组件*@parampixelMap*/privatevoidputPixelMap(PixelMappixelMap){if(pixelMap!=null){rectSrc=newRectFloat(0,0,pixelMap.getImageInfo().size.width,pixelMap.getImageInfo().size.height);pixelMapHolder=newPixelMapHolder(pixelMap);invalidate();//重新检验该组件}else{pixelMapHolder=null;setPixelMap(null);}}/***通过资源ID获取位置图**/privatePixelMapgetPixelMap(intresId){InputStreamdrawableInputStream=null;try{drawableInputStream=getResourceManager().getResource(resId);ImageSource.SourceOptionssourceOptions=newImageSource.SourceOptions();sourceOptions.formatHint="image/png";ImageSourceimageSource=ImageSource.create(drawableInputStream,null);ImageSource.DecodingOptions解码选项=newImageSource.DecodingOptions();decodingOptions.desiredSize=newSize(0,0);decodingOptions.desiredRegion=newRect(0,0,0,0);decodingOptions.desiredPixelFormat=PixelFormat.ARGB_8888;PixelMappixelMap=imageSource.createPixelmap(decodingOptions);returnpixelMap;}catch(Exceptione){e.printStackTrace();}finally{try{if(drawableInputStream!=null){drawableInputStream.close();}}catch(Exceptione){e.printStackTrace();}}returnnull;}/***外部调用api,设置圆形图片方法*@paramresId*/publicvoidsetPixelMapAndCircle(intresId){PixelMappixelMap=getPixelMap(resId);putPixelMap(pixelMap);onCircleDraw();}/***外部调用api,设置圆角图片方法*@paramresId*@paramradius*/publicvoidsetPixelMapAndRoundRect(intresId,intradius){PixelMappixelMap=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","汽车","wearable"],"reqPermissions":[{"name":"ohos.permission.INTERNET"}],"distro":{"deliveryWithInstall":true,"moduleName":"roundimage","moduleType":"har"}}}这样,该模块就可以被导出并随后被所有其他项目引用。后面可以通过添加依赖编译发布到gradle直接使用(这个是后话)。接下来,我们将首先使用本地依赖项。通过导入调用此自定义组件模块。四、其他项目调用此自定义组件并测试效果1、新建一个项目,然后将之前的模块导入到新项目中(DevEco暂时不支持自动导入外部模块,操作需要手动导入操作,请关注我的另一篇博客)。2.引用gradle中导入模块的组件,代码如下:dependencies{entryImplementationproject(':entry')implementationfileTree(dir:'libs',include:['*.jar','*.har'])testCompile'junit:junit:4.12'}3.布局中引用自定义圆形图片,代码如下:
