目錄:
一、背景
在采用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); } }
作者:軟通夏德旺
想了解更多內容,請訪問: 51CTO和華為官方戰略合作共建的鴻蒙技術社區https://harmonyos.51cto.com/