HarmonyOS图片,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);
}
}
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中引用導入的模塊的組件,代碼如下:
文章后續內容和相關附件可以點擊下面的原文鏈接前往學習
總結
以上是生活随笔為你收集整理的HarmonyOS图片,HarmonyOS App开发造轮子--自定义圆形图片组件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java类和方法
- 下一篇: 【python】BeautifulSou