思路:
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中引用導入的模塊的組件,代碼如下:
dependencies {entryImplementation project(':entry')implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])testCompile'junit:junit:4.12'
}
3、在布局中引用自定義的圓形圖片,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayoutxmlns:ohos="http://schemas.huawei.com/res/ohos"ohos:height="match_parent"ohos:width="match_parent"ohos:orientation="vertical"><Textohos:id="$+id:text_helloworld"ohos:height="match_content"ohos:width="match_content"ohos:background_element="$graphic:background_ability_main"ohos:layout_alignment="horizontal_center"ohos:text="Hello World"ohos:text_size="50"/><com.xdw.customview.RoundImageohos:id="$+id:image"ohos:height="200vp"ohos:width="200vp"/>
</DirectionalLayout>
4、在Java代碼中進行調用,代碼如下:
package com.example.testcustomview.slice;import com.example.testcustomview.ResourceTable;
import com.xdw.customview.RoundImage;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;public class MainAbilitySlice extends AbilitySlice {@Overridepublic void onStart(Intent intent) {super.onStart(intent);super.setUIContent(ResourceTable.Layout_ability_main);RoundImage roundImage = (RoundImage) findComponentById(ResourceTable.Id_image);roundImage.setPixelMapAndCircle(ResourceTable.Media_man);}@Overridepublic void onActive() {super.onActive();}@Overridepublic void onForeground(Intent intent) {super.onForeground(intent);}
}
5、開啟手機模擬器進行測試,效果如下
最后
如果你想快速提升鴻蒙技術,那么可以直接領取這份包含了:【OpenHarmony多媒體技術、Stage模型、ArkUI多端部署、分布式應用開發、音頻、視頻、WebGL、Napi組件、OpenHarmony內核、Harmony南向開發、鴻蒙項目實戰】等技術知識點。
鴻蒙Next全套VIP學資料←點擊領取!(安全鏈接,放心點擊)