回顧一下亏钩,自定義view重寫的關(guān)鍵方法有:
measure 測(cè)量組件本身的大小
layout 確定組件在視圖中的位置
draw 根據(jù)位置和大小搬葬,將組件畫出來(lái)
float[] radii:必須傳入8個(gè)數(shù)值黄琼,分四組憾筏,分別對(duì)應(yīng)每個(gè)角所使用的橢圓的橫軸半徑和縱軸半徑的止,如{x1,y1,x2,y2,x3,y3,x4,y4}再扭,其中,x1,y1對(duì)應(yīng)第一個(gè)角的(左上角)用來(lái)產(chǎn)生圓角的橢圓的橫軸半徑和縱軸半徑肌括,其它類推……
定義幾種圓角模式
/**
* 圓形模式
*/
private static final int MODE_CIRCLE = 1;
/**
* 普通模式
*/
private static final int MODE_NONE = 0;
/**
* 圓角模式
*/
private static final int MODE_ROUND = 2;
/**
* 上面的圓角模式
*/
private static final int MODE_ROUND_TOP = 3;
/**
* 下方圓角模式
*/
private static final int MODE_ROUND_BOTTOM = 4;
- attr文件中定義
<declare-styleable name="RoundImageview">
<attr name="viewtype" format="enum">
<enum name="circle" value="1"/>
<enum name="round" value="2"/>
<enum name="roundtop" value="3"/>
<enum name="round_bottom" value="4"/>
</attr>
<attr name="radius" format="dimension"/>
</declare-styleable>
- 準(zhǔn)備就緒(畫筆点骑,矩陣等對(duì)象,不要在ondraw的時(shí)候去new對(duì)象,因?yàn)閛ndraw會(huì)被調(diào)用多次黑滴,容易導(dǎo)致內(nèi)存泄露)
private static final int MODE_ROUND_BOTTOM = 4;
private BitmapShader bitmapShader;
private Paint mPaint;
private int currMode = 0;
private Path path = new Path();
private RectF rectF = new RectF();
private Matrix matrix = new Matrix();
private Bitmap bitmap;
// 圓角矩形路徑
private float[] radii = new float[8];
/**
* 圓角半徑
*/
private int currRound = dp2px(10);
private int dp2px(float value) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics());
}
- 重寫三個(gè)構(gòu)造函數(shù) ,并在里面初始化數(shù)據(jù)
public RoundImageview(Context context) {
super(context);
initViews();
}
public RoundImageview(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundImageview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
obtainStyledAttrs(context, attrs, defStyleAttr);
initViews();
}
private void obtainStyledAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundImageview, defStyleAttr, 0);
currMode = a.hasValue(R.styleable.RoundImageview_viewtype) ? a.getInt(R.styleable.RoundImageview_viewtype, MODE_NONE) : MODE_NONE;
currRound = a.hasValue(R.styleable.RoundImageview_radius) ? a.getDimensionPixelSize(R.styleable.RoundImageview_radius, currRound) : currRound;
//用完后記得回收
a.recycle();
}
private void initViews() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
}
- 測(cè)量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/*
* 當(dāng)模式為圓形模式的時(shí)候憨募,我們強(qiáng)制讓寬高一致
*/
if (currMode == MODE_CIRCLE) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int result = Math.min(getMeasuredHeight(), getMeasuredWidth());
setMeasuredDimension(result, result);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
path.reset();
rectF.left = getPaddingLeft();
rectF.top = getPaddingTop();
rectF.right = getMeasuredWidth() - getPaddingRight();
rectF.bottom = getMeasuredHeight() - getPaddingBottom();
switch (currMode) {
case MODE_ROUND_TOP:
fillRadii(currRound, currRound, currRound, currRound, 0, 0, 0, 0);
break;
case MODE_ROUND_BOTTOM:
fillRadii(0, 0, 0, 0, currRound, currRound, currRound, currRound);
break;
case MODE_ROUND:
fillRadii(currRound, currRound, currRound, currRound, currRound, currRound, currRound, currRound);
break;
default:
fillRadii(0, 0, 0, 0, 0, 0, 0, 0);
break;
}
path.addRoundRect(rectF, radii, Path.Direction.CCW);
if (bitmapShader != null && bitmap != null && getMeasuredHeight() > 0 && getMeasuredWidth() > 0) {
matrix.reset();
float sx = getMeasuredWidth() / (float)bitmap.getWidth();
float sy = getMeasuredHeight() / (float)bitmap.getHeight();
float scale = Math.max(sx,sy);
matrix.postScale(scale, scale);
bitmapShader.setLocalMatrix(matrix);
}
}
private void fillRadii(float... radii) {
System.arraycopy(radii, 0, this.radii, 0, 8);
}
- 開始畫啦
@Override
protected void onDraw(Canvas canvas) {
final int saveCount = canvas.getSaveCount();
canvas.save();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (getCropToPadding()) {
final int scrollX = getScrollX();
final int scrollY = getScrollY();
canvas.clipRect(scrollX + getPaddingLeft(), scrollY + getPaddingTop(),
scrollX + getRight() - getLeft() - getPaddingRight(),
scrollY + getBottom() - getTop() - getPaddingBottom());
}
}
canvas.translate(getPaddingLeft(), getPaddingTop());
mPaint.reset();
if (bitmapShader != null) {
if (currMode == MODE_CIRCLE) {//當(dāng)為圓形模式的時(shí)候
mPaint.setShader(bitmapShader);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, mPaint);
} else if (currMode == MODE_ROUND) {//當(dāng)為圓角模式的時(shí)候
mPaint.setShader(bitmapShader);
canvas.drawRoundRect(rectF,
currRound, currRound, mPaint);
} else if (currMode == MODE_ROUND_TOP || currMode == MODE_ROUND_BOTTOM) {//當(dāng)為上/下圓角模式的時(shí)候
mPaint.setShader(bitmapShader);
canvas.drawPath(path, mPaint);
} else {
mPaint.setShader(bitmapShader);
canvas.drawPath(path, mPaint);
}
}
canvas.restoreToCount(saveCount);
}
- 最后暴露一個(gè)方法來(lái)設(shè)置圖片資源
public void setImage(@Nullable Bitmap bitmap) {
if (bitmap == null) return;
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
this.bitmap = bitmap;
requestLayout();
}
參考:https://blog.csdn.net/harvic880925/article/details/38926877