HarmonyOS App開發造輪子--自定義圓形圖片組件

1、背景javascript

        在採用Java配合xml佈局編寫鴻蒙app頁面的時候,發現sdk自帶的Image組件並不能將圖片設置成圓形,反覆了翻閱了官方API手冊(主要查閱了Compont和Image相關的API),起初發現了一個setCornerRadius方法,因而想着將圖片寬度和高度設置爲同樣,而後調用該方法將radios設置爲寬度或者高度的一半,覺得能夠實現圓形圖片的效果,後來發現不行。因而乎想着能不能經過繼承原有的Image本身來動手從新自定義一個支持圓形的圖片組件。java

 

2、思路:ios

一、對比以前本身在其餘程序開發中自定義組件的思路,首先尋找父組件Image和Component相關的Api,看看是否具有OnDraw方法。json

二、瞭解Canvas相關Api操做,特別是涉及到位圖的操做。canvas

經過翻閱大量資料,發現了兩個關鍵的api,分別是Component的addDrawTask方法和其內部靜態接口DrawTaskapi

#2020徵文-手機# HarmonyOS App開發造輪子--自定義圓形圖片組件

#2020徵文-手機# HarmonyOS App開發造輪子--自定義圓形圖片組件

3、自定義組件模塊app

一、新建一個工程以後,建立一個獨立的Java FA模塊,而後刪除掉裏面全部佈局以及自動生成的java代碼,而後本身建立一個class繼承ImageViewiview

二、寫一個類繼承ImageView,在其中暴露出public的設置圓形圖片的api方法以供後面調用;ide

三、在原有的Image組件獲取到位圖以後,利用該位圖數據利用addDrawTask方法配合Canvas進行位圖輸出形狀的從新繪製,這裏須要使用Canvas的一個函數

關鍵api方法drawPixelMapHolderRoundRectShape;

四、注意,爲了讓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);
    }
}

 

五、修改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上直接經過添加依賴來進行使用(這個是後話),下面咱們先經過本地依賴導入的方式來調用這個自定義組件模塊吧。

 

4、其餘工程調用該自定義組件並測試效果

一、再來新建一個工程,而後將以前的模塊導入到新建的工程中(DevEco暫時不支持自動導入外部模塊的操做,須要手動導入操做,請關注個人另一篇博客)

二、在gradle中引用導入的模塊的組件,代碼以下:


文章後續內容和相關附件能夠點擊下面的原文連接前往學習

原文連接:https://harmonyos.51cto.com/posts/2423#bkwz


想了解更多關於鴻蒙的內容,請訪問:

51CTO和華爲官方戰略合做共建的鴻蒙技術社區

https://harmonyos.51cto.com/#bkwz

相關文章
相關標籤/搜索