編輯:關於Android編程
看了看以前的項目,發現用了一個叫RoundImageView的類,當時直接從網上copy的(^__^) 嘻嘻……,今天偶爾看到了,覺得不能一直停留在直接拖別人的代碼了,於是自己實現了一下,發現以前的只支持CENTER_CROP類型的縮放,於是自己看了下ImageView的源碼,實現了下支持所有縮放類型的ImageView.
先上一張效果圖:
怎麼樣?效果還不錯吧!接下來我們來一步一步實現一下吧…….
實現圓角圓形的ImageView方式有很多,剛好在復習Paint的Xfermode,所以就先用Xfermode來實現了,
什麼時候Xfermode
我先上一張圖
簡單說一下Xfermode的一些模式:
1.PorterDuff.Mode.CLEAR
所繪制不會提交到畫布上。
2.PorterDuff.Mode.SRC
顯示上層繪制圖片
3.PorterDuff.Mode.DST
顯示下層繪制圖片
4.PorterDuff.Mode.SRC_OVER
正常繪制顯示,上下層繪制疊蓋。
5.PorterDuff.Mode.DST_OVER
上下層都顯示。下層居上顯示。
6.PorterDuff.Mode.SRC_IN
取兩層繪制交集。顯示上層。
7.PorterDuff.Mode.DST_IN
取兩層繪制交集。顯示下層。
8.PorterDuff.Mode.SRC_OUT
取上層繪制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下層繪制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下層非交集部分與上層交集部分
11.PorterDuff.Mode.DST_ATOP
取上層非交集部分與下層交集部分
12.PorterDuff.Mode.XOR
異或:去除兩圖層交集部分
13.PorterDuff.Mode.DARKEN
取兩圖層全部區域,交集部分顏色加深
14.PorterDuff.Mode.LIGHTEN
取兩圖層全部,點亮交集部分顏色
15.PorterDuff.Mode.MULTIPLY
取兩圖層交集部分疊加後顏色
16.PorterDuff.Mode.SCREEN
取兩圖層全部區域,交集部分變為透明色
思路:
畫一個圓角或圓形當做SRC(模板)然後自己設置的圖片當做DST然後用PorterDuff.Mode.DST_IN讓兩個相交的部分顯示出圖片,這樣說有點抽象,下面我們來一步一步實現以下。
attrs.xml:
然後我我們創建一個自定義View叫RoundImageView然後去獲取attrs中的屬性(想必這都是很簡單的操作了,老司機的你應該都敲爛了(^__^) 嘻嘻……):
package com.yqy.canvasdemo; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.widget.ImageView; /** * @author EX_YINQINGYANG * @version [Android PABank C01, @2016-10-08] * @date 2016-10-08 * @description */ public class RoundImageView extends ImageView { /** * 圓角ImageView圓角的半徑大小 */ private int mRadius=dp2px(10); /** * 圓形類型 */ private int TYPE_CIRCLE=0; /** * 圓角類型 */ private int TYPED_ROUND=1; /** * 圖片類型 */ private int mType=TYPE_CIRCLE; /** * 圖片縮放模式 */ private ScaleType mScaleType; public RoundImageView(Context context) { this(context,null); } public RoundImageView(Context context, AttributeSet attrs) { this(context, attrs,0); } public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); obtainStyleAttr(context,attrs,defStyleAttr); mScaleType=getScaleType(); } private void obtainStyleAttr(Context context, AttributeSet attrs, int defStyleAttr) { TypedArray a=context.getTheme().obtainStyledAttributes(attrs,R.styleable.RoundImageView,defStyleAttr,0); mRadius=a.getDimensionPixelSize(R.styleable.RoundImageView_borderRadius,mRadius); mType=a.getInteger(R.styleable.RoundImageView_type,mType); a.recycle(); } /** * dp2px * @param value * @return px */ private int dp2px(int value) { return (int) (value*getContext().getResources().getDisplayMetrics().density+0.5f); } }
然後我們就要實現最重要的一步了,重寫onDraw方法(為了防止多次繪制然後不斷創建bitmap耗內存,我們這使用一個弱引用做一下Bitmap的緩存):
@Override protected void onDraw(Canvas canvas) { Bitmap bitmap = mWeakReference==null?null:mWeakReference.get(); if(bitmap==null || bitmap.isRecycled()){ //獲取一下設置的圖片資源 Drawable drawable=getDrawable(); if(drawable!=null){ //創建一個空白畫布,用來畫模板跟原圖 bitmap=Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888); Canvas dstCanvas=new Canvas(bitmap); //畫原圖 drawable.draw(dstCanvas); //設置畫筆的Xfermode mPaint.setXfermode(mXfermode); //畫模板 if(mMaskBitmap==null||mMaskBitmap.isRecycled()){ mMaskBitmap=getShapeBitmap(); } dstCanvas.drawBitmap(mMaskBitmap,0,0,mPaint); mPaint.setXfermode(null); } } //最後把我們准備好的Bitmap畫在canvas上 canvas.drawBitmap(bitmap,0,0,null); } /** * 根據Shape類型創建ShapeBitmap */ private Bitmap getShapeBitmap() { Bitmap bitmap=Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas =new Canvas(bitmap); if(TYPE_CIRCLE==mType){ canvas.drawCircle(canvas.getWidth()/2,canvas.getHeight()/2,canvas.getWidth()/2,shapePaint); } else{ canvas.drawRound Rect(new RectF(0,0,canvas.getWidth(),canvas.getHeight()),mRadius,mRadius,shapePaint); } return bitmap; }
代碼比較簡單,都有注釋的,我就不解釋了。
寫到這裡一個簡單的圓角圓形ImageView就可以使用了,是不是很簡單呢?有些東西吧,還是得自己去琢磨琢磨,哪怕是什麼都不會,跟著敲一篇總會有收獲的。(不怕笑話,我一開始連別人代碼都看不懂(^__^) 嘻嘻…… 只會拖著用,然後一個一個查到底什麼意思。)廢話不說了。
我們運行代碼:
**問題來了:效果是有了,但有發現麼?我設置的scaleType只有fitxy
是有效果的,其他的都沒有效果了。設置為其他的scaleType都變成matrix那種效果了,也就是圖片默認從控件的左上角開始擺放。**
現附上現階段的源碼:
package com.yqy.canvasdemo; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.Xfermode; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.ImageView; import com.cisetech.circleviewdemo.R; import java.lang.ref.WeakReference; /** * @author EX_YINQINGYANG * @version [Android PABank C01, @2016-10-08] * @date 2016-10-08 * @description */ public class RoundImageView extends ImageView { /** * 圓角ImageView圓角的半徑大小 */ private int mRadius=dp2px(10); /** * 圓形類型 */ private int TYPE_CIRCLE=0; /** * 圓角類型 */ private int TYPED_ROUND=1; /** * 圖片類型 */ private int mType=TYPE_CIRCLE; /** * 圖片縮放模式 */ private ScaleType mScaleType; /** * 緩存bitmap */ private WeakReferencemWeakReference; /** * 模板Bitmap */ private Bitmap mMaskBitmap; /** * 畫筆 */ private Paint mPaint; /** * shape paint */ private Paint shapePaint; /** * 畫筆Xfermode */ private Xfermode mXfermode=new PorterDuffXfermode(PorterDuff.Mode.DST_IN); public RoundImageView(Context context) { this(context,null); } public RoundImageView(Context context, AttributeSet attrs) { this(context, attrs,0); } public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); obtainStyleAttr(context,attrs,defStyleAttr); mScaleType=getScaleType(); mPaint=new Paint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG); shapePaint=new Paint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG); } private void obtainStyleAttr(Context context, AttributeSet attrs, int defStyleAttr) { TypedArray a=context.getTheme().obtainStyledAttributes(attrs, R.styleable.RoundImageView,defStyleAttr,0); mRadius=a.getDimensionPixelSize(R.styleable.RoundImageView_borderRadius,mRadius); mType=a.getInteger(R.styleable.RoundImageView_type,mType); a.recycle(); } @Override protected void onDraw(Canvas canvas) { Bitmap bitmap = mWeakReference==null?null:mWeakReference.get(); if(bitmap==null || bitmap.isRecycled()){ //獲取一下設置的圖片資源 Drawable drawable=getDrawable(); if(drawable!=null){ //創建一個空白畫布,用來畫模板跟原圖 bitmap=Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888); Canvas dstCanvas=new Canvas(bitmap); //畫原圖 drawable.draw(dstCanvas); //設置畫筆的Xfermode mPaint.setXfermode(mXfermode); //畫模板 if(mMaskBitmap==null||mMaskBitmap.isRecycled()){ mMaskBitmap=getShapeBitmap(); } dstCanvas.drawBitmap(mMaskBitmap,0,0,mPaint); mPaint.setXfermode(null); } } //最後把我們准備好的Bitmap畫在canvas上 canvas.drawBitmap(bitmap,0,0,null); } /** * 根據Shape類型創建ShapeBitmap */ private Bitmap getShapeBitmap() { Bitmap bitmap=Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas =new Canvas(bitmap); if(TYPE_CIRCLE==mType){ canvas.drawCircle(canvas.getWidth()/2,canvas.getHeight()/2,canvas.getWidth()/2,shapePaint); } else{ canvas.drawRoundRect(new RectF(0,0,canvas.getWidth(),canvas.getHeight()),mRadius,mRadius,shapePaint); } return bitmap; } /** * dp2px * @param value * @return px */ private int dp2px(int value) { return (int) (value*getContext().getResources().getDisplayMetrics().density+0.5f); } }
太長了,先到這裡了…….未完待續啊
問題描述 說起來我也夠菜的!⊙﹏⊙b汗。 今天搞了一個關於圖片的demo,想動態的改變一張圖片的大小和margin值。但是在activity
本文實例講述了Android編程之繪制文本(FontMetrics)實現方法。分享給大家供大家參考,具體如下:Canvas 作為繪制文本時,使用FontMetrics對象
1.初識ViewRoot和DecorViewViewRoot對應於ViewRootImpl類,它是連接WindowManager和DecorView的紐帶,View的三大
這是我在 MDCC 上分享的內容(略微改動),也是源碼解析第一期發布時介紹的源碼解析後續會慢慢做的事。從總體設計和原理上對幾個圖片緩存進行對比,沒用到他們的朋友也可以了解