編輯:關於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);
}
}
太長了,先到這裡了…….未完待續啊
Android從零單排之獲取ImageView的寬高為0?
問題描述 說起來我也夠菜的!⊙﹏⊙b汗。 今天搞了一個關於圖片的demo,想動態的改變一張圖片的大小和margin值。但是在activity
Android編程之繪制文本(FontMetrics)實現方法
本文實例講述了Android編程之繪制文本(FontMetrics)實現方法。分享給大家供大家參考,具體如下:Canvas 作為繪制文本時,使用FontMetrics對象
View的繪制原理
1.初識ViewRoot和DecorViewViewRoot對應於ViewRootImpl類,它是連接WindowManager和DecorView的紐帶,View的三大
Android圖片緩存原理、特性對比
這是我在 MDCC 上分享的內容(略微改動),也是源碼解析第一期發布時介紹的源碼解析後續會慢慢做的事。從總體設計和原理上對幾個圖片緩存進行對比,沒用到他們的朋友也可以了解