Android自定义View之圆形头像

来源:互联网 发布:淘宝外卖系统繁忙 编辑:程序博客网 时间:2024/05/21 22:22

圆形头像是我们在开发中经常用到的控件,下面我们就来自定义这样一个控件:
这里写图片描述
1.自定义CircleImageView类继承ImageView

package com.example.qw.circleimageview;/** * Created by quwei on 2015/5/13 0013. */import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.Rect;import android.graphics.RectF;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.util.Log;import android.widget.ImageView;public class CircleImageView extends ImageView {    private static final String TAG = "vvv";    private Bitmap mask;    private Paint paint;    private Paint mBorderPaint;    private int mBorderWidth = 2;    private int mBorderColor = Color.BLUE;    public CircleImageView(Context paramContext) {        super(paramContext);    }    public CircleImageView(Context paramContext, AttributeSet paramAttributeSet) {        this(paramContext, paramAttributeSet, 0);    }    public CircleImageView(Context context, AttributeSet paramAttributeSet, int paramInt) {        super(context, paramAttributeSet, paramInt);        TypedArray a = context.obtainStyledAttributes(paramAttributeSet, R.styleable.CircularImage);        mBorderColor = a.getColor(R.styleable.CircularImage_border_color, mBorderColor);//        float density = context.getResources().getDisplayMetrics().density; // 获取屏幕密度        mBorderWidth = a.getDimensionPixelOffset(R.styleable.CircularImage_border_width, 0);        a.recycle();    }    private boolean useDefaultStyle = false;    public void setUseDefaultStyle(boolean useDefaultStyle) {        this.useDefaultStyle = useDefaultStyle;    }    @Override    protected void onDraw(Canvas canvas) {        if (useDefaultStyle) {            super.onDraw(canvas);            return;        }        Drawable drawable = getDrawable();        if (drawable == null) {            super.draw(canvas);            return;        }        /**         * 第一种方法,使用图层进行图片混合         */        Drawable localDrawable = editDrawable(drawable);        drawCircleImage(canvas, localDrawable);        /**         * 第二种方法,创建新的画布,并在该画布上进行混合,生成混合后的bitmap,         * 再将该bitmap画回到该View的原画布上         *///        Bitmap src = ((BitmapDrawable) drawable).getBitmap();//        Bitmap bitmap = createCircleImage(src);//        canvas.drawBitmap(bitmap, 0, 0, null);        // 对圆形图像进行描边        drawBorder(canvas, getWidth(), getHeight());    }    private void drawCircleImage(Canvas canvas, Drawable localDrawable) {        canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);        localDrawable.draw(canvas);        if (mask == null)            mask = createOvalBitmap(getWidth(), getHeight());        if (this.paint == null) {            final Paint localPaint = new Paint();            localPaint.setFilterBitmap(false);            localPaint.setAntiAlias(true);            // 关键!DST_IN具体情况请查阅官方文档            localPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));            this.paint = localPaint;        }        canvas.drawBitmap(mask, 0, 0, paint);        canvas.restore();    }    private void drawBorder(Canvas canvas, final int width, final int height) {        if (mBorderWidth == 0) {            return;        }        if (mBorderPaint == null) {            mBorderPaint = new Paint();            mBorderPaint.setStyle(Paint.Style.STROKE);            mBorderPaint.setAntiAlias(true);            mBorderPaint.setColor(mBorderColor);            mBorderPaint.setStrokeWidth(mBorderWidth);        }        RectF rectF = new RectF(0 + mBorderWidth, 0 + mBorderWidth,                width - mBorderWidth, height - mBorderWidth);        canvas.drawOval(rectF, mBorderPaint);    }    private Drawable editDrawable(Drawable localDrawable) {        int drawableWidth = localDrawable.getIntrinsicWidth();        int drawableHeight = localDrawable.getIntrinsicHeight();        Log.i(TAG, "" + drawableWidth + "," + drawableHeight);        final int width = getWidth();        final int height = getHeight();        Log.i(TAG, "" + width + "," + height);        float rw = (float) drawableWidth / (float) width;        float rh = (float) drawableHeight / (float) height;        int dWidth;        int dHeight;        if (rw < rh) {            dWidth = width;            dHeight = (int) (drawableHeight / rw);            //移动到中间的偏移量            int yOff = (dHeight - height) / 2;            localDrawable.setBounds(0, -yOff, dWidth, dHeight - yOff);        } else {            dWidth = (int) (drawableWidth / rh);            dHeight = height;            int xOff = (dWidth - width) / 2;            localDrawable.setBounds(-xOff, 0, dWidth - xOff, dHeight);        }        return localDrawable;    }    /**     * 创建圆形画布     *     * @param width     * @param height     * @return     */    public Bitmap createOvalBitmap(final int width, final int height) {        Bitmap localBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);        Canvas localCanvas = new Canvas(localBitmap);        Paint localPaint = new Paint();        localPaint.setColor(Color.GREEN);        localPaint.setAntiAlias(true); // 很重要!设置抗锯齿        int padding = mBorderWidth;        RectF localRectF = new RectF(padding, padding, width - padding, height - padding);        localCanvas.drawOval(localRectF, localPaint);        return localBitmap;    }    private Bitmap createCircleImage(Bitmap source) {        Bitmap target = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);        /**         * 产生一个同样大小的画布         */        Canvas canvas = new Canvas(target);        final Paint paint = new Paint();        paint.setAntiAlias(true);        /**         * 首先绘制圆形         */        int padding = mBorderWidth;        RectF localRectF = new RectF(padding, padding, getWidth() - padding, getHeight() - padding);        canvas.drawOval(localRectF, paint);        /**         * 使用SRC_IN         */        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));        /**         * 绘制图片         */        int sourceWidth = source.getWidth();        int sourceHeight = source.getHeight();        Log.i(TAG, "sourceWidth:" + sourceWidth + ",sourceHeight:" + sourceHeight);        final int width = getWidth();        final int height = getHeight();        Log.i(TAG, "width:" + width + ",height:" + height);        float rw = (float) sourceWidth / (float) width;        float rh = (float) sourceHeight / (float) height;        int dWidth;        int dHeight;        if (rw < rh) {            dWidth = width;            dHeight = (int) (sourceHeight / rw);            //移动到中间的偏移量            int yOff = (dHeight - height) / 2;            canvas.drawBitmap(source, new Rect(0, 0, sourceWidth, sourceHeight),                    new Rect(0, -yOff, dWidth, dHeight - yOff), paint);        } else {            dWidth = (int) (sourceWidth / rh);            dHeight = height;            int xOff = (dWidth - width) / 2;            canvas.drawBitmap(source, new Rect(0, 0, sourceWidth, sourceHeight),                    new Rect(-xOff, 0, dWidth - xOff, dHeight), paint);        }        Log.i(TAG, "dWidth:" + dWidth + ",dHeight:" + dHeight);        return target;    }}

代码没什么好说,有难度的地方都注释了
2.我们使用描边的时候自定义了属性,在value/atrr.xml文件中加上

    <declare-styleable name="CircularImage">        <attr name="border_width" format="dimension" />        <attr name="border_color" format="color" />    </declare-styleable>

3.在布局文件中使用自定义View

    <com.example.qw.circleimageview.CircleImageView         xmlns:def="http://schemas.android.com/apk/res-auto"        android:layout_width="150dp"        android:layout_height="150dp"        android:scaleType="centerCrop"        android:src="@drawable/head"        def:border_color="#F6170F"        def:border_width="2dp" />

对混合模式有疑惑的请参考大神爱哥的博客:自定义控件其实很简单1/6

0 0