Android自定義View之繪製圓形頭像

  • 2019 年 10 月 4 日
  • 筆記

版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

本文鏈接:https://blog.csdn.net/huangliniqng/article/details/100813623

前言

做APP應用開發的時候,用戶頭像肯定是必不可少的,但是90%以上的需求頭像都是圓形的。那麼,如何通過自定義View的方式實現圓形頭像呢,那麼,本片博文會告訴你不僅僅是實現過程。一定會有意想不到的收穫哦!

最終效果

國際慣例,我們先來看最終實現的效果圖

自定義RoundImageView繼承自ImageView

public class RoundImageView extends ImageView {        public RoundImageView(Context context) {          super(context);      }        public RoundImageView(Context context, @Nullable AttributeSet attrs) {          super(context, attrs);      }        public RoundImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {          super(context, attrs, defStyleAttr);      }  }

不知你是否注意過每當我們繼承自View的時候,系統都會提示我們覆蓋重寫4個構造方法,這裡我們只覆蓋了三個,然後就開始在每個構造方法中進行初始化,那麼,是不是每次都會調用所有的構造方法呢,如果不是,這三個構造方法又會什麼時候調用呢?下面我們來通過例子來驗證。

使用自定義View無非就兩種情況下,第一種就是直接在xml布局中使用,另一種就是在Activity中new出來,下面我們分別使用上述兩種方式,為了便於觀察我們在三個構造方法中分別加入一行列印。

首先我們在xml直接使用,運行列印如下:

com.example.roundimageview D/RoundImageView: RoundImageView: 兩個參數的構造方法

然後我們在Activity中,new一個RoundImageView

roundImageView = RoundImageView(this@MainActivity)  roundImageView = RoundImageView(this@MainActivity, null)  roundImageView = RoundImageView(this@MainActivity, null,0)

運行列印日誌如下:

結論:自定義View當在xml中使用,使用的是第二個構造方法,當在Activity中使用時,實例化時傳入幾個參數調用的就是含有幾個參數的構造方法。

實現圓形頭像的思想

我始終認為自定義View的難度只在於它的實現思想,通常我們遇到問題的時候,並不是Google不到,而是壓根就不知道這個問題該去如何Google,如果知道了問題所產生的原因,其實問題已經迎刃而解了,最怕的是不知道問題為什麼會產生。

實現圓形頭像的思想一個簡單的圖就可以表示了。

矩形區域是完整的圖片,圓形區域就是我們最終顯示的頭像區域,那麼就很簡單了,圓形區域與矩形區域相交,取並集區域?在矩形中畫一個與矩形長或寬相切的圓,而圓的直徑是長或寬較短的一邊。

編碼實現

  • 獲取原有頭像的bitmap

首先我們需要獲取設置頭像的bitmap,我們可以直接通過API來獲取設置的圖片資源,

drawable = this.getDrawable();

再將圖片資源轉化為bitmap

首先我們判斷drawable是否為空,如果為空說明用戶沒有設置,拋出資源未找到的異常。

if (drawable == null) {      throw new Resources.NotFoundException("Image resource not set");  }

如果不為空,我們創建一個與圖片資源大小相等的bitmap,並將bitmap繪製出來,程式碼如下所示:

bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),          Bitmap.Config.ARGB_8888);  Canvas canvas = new Canvas(bitmap);  drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),          drawable.getIntrinsicHeight());  drawable.draw(canvas);
  • 繪製圓形bitmap

通過上面的程式碼,我們得到了原有的bitmap影像,緊接著我們需要繪製圓形的bitmap,與上面類似,首先創建一個和bitmap大小一致的點陣圖

circleBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);

我們畫一個與bitmap等大的矩形

Paint paint = new Paint();  Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());  canvas.drawRect(rect,paint);  RectF rectF = new RectF(rect);

將較短的一邊設置圓的半徑

float roundRa = 0.0f;  if (bitmap.getWidth() > bitmap.getHeight()) {      roundRa = bitmap.getHeight() / 2.0f;  } else {      roundRa = bitmap.getWidth() / 2.0f;  }

設置paint和canvas屬性

paint.setAntiAlias(true);  canvas.drawARGB(0, 0, 0, 0);  paint.setColor(Color.WHITE);  paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

canvas.drawARGB將繪製裁剪設為透明,paint.setXfermode中的PorterDuffXfermode類很強大,後面我們會單獨一篇文章講解。

最終我們重新將bitmap繪製出來即可

canvas.drawBitmap(bitmap, rect, rect, paint);

繪製部分完整程式碼如下所示:

 * 獲取圓形裁剪的bitmap   *   * @param bitmap 原bitmap   */  private Bitmap getCircleBitmap(Bitmap bitmap) {      circleBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);      Canvas canvas = new Canvas(circleBitmap);      Paint paint = new Paint();      Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());      RectF rectF = new RectF(rect);        float roundRa = 0.0f;      if (bitmap.getWidth() > bitmap.getHeight()) {          roundRa = bitmap.getHeight() / 2.0f;      } else {          roundRa = bitmap.getWidth() / 2.0f;      }        paint.setAntiAlias(true);      canvas.drawARGB(0, 0, 0, 0);      paint.setColor(Color.GRAY);      canvas.drawRoundRect(rectF, roundRa, roundRa, paint);      paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));      canvas.drawBitmap(bitmap, rect, rect, paint);      return circleBitmap;    }
  • 設置最終的bitmap

得到bitma後我們直接重新設置即可顯示

 setImageBitmap(getCircleBitmap(bitmap));

本實例較為簡單,就不貼所有程式碼了,如有需要留言郵箱即可,如有紕漏之處,歡迎指正!晚安!

9.15 22:17 更新

程式碼已上傳github:https://github.com/huanglinqing123/RoundImageView