Android自定义View之圆形头像


本篇:自定义圆形View并显示圆形的头像


目录:

1. 预备:阅读本篇文章,需具备View的绘制基本知识。

2. 讲解:PorterDuff.Mode https://developer.android.com/reference/android/graphics/PorterDuff.Mode

3. 实战:使用PorterDuff.Mode实现圆形头像。

核心代码:

paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));

PorterDuff.Mode

1. SRC

PorterDuff.Mode.SRC

composite_SRC.png

PorterDuff.Mode.SRC_OVER

composite_SRC_OVER.png

PorterDuff.Mode.SRC_IN

composite_SRC_IN.png

PorterDuff.Mode.SRC_OUT

composite_SRC_OUT.png

PorterDuff.Mode.SRC_ATOP

composite_SRC_ATOP.png

2. Destination

PorterDuff.Mode.DST

composite_DST.png

PorterDuff.Mode.DST_OVER

composite_DST_OVER.png

PorterDuff.Mode.DST_IN

composite_DST_IN.png

PorterDuff.Mode.DST_OUT

composite_DST_OUT.png

PorterDuff.Mode.DST_ATOP

composite_DST_ATOP.png

3. Clear

######PorterDuff.Mode.CLEAR
composite_CLEAR.png

4. Exclusive or

PorterDuff.Mode.XOR

composite_XOR.png

PorterDuff.Mode,实现圆形头像 (支持Padding、wrap_content属性)

1. 核心代码

public class AirXfermodeCircleView extends ImageView {

    private static final String TAG = "AirXfermodeCircleView";

    private static final int MIN_SIZE_DEFAULT = 100;

    private Paint mDrawablePaint;

    public AirXfermodeCircleView(Context context) {
        this(context, null);
    }

    public AirXfermodeCircleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AirXfermodeCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public AirXfermodeCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);


        initializePaints();
    }

    private void initializePaints() {

        mDrawablePaint = new Paint();
        mDrawablePaint.setAntiAlias(true);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);


        switch (widthMode) {
            case MeasureSpec.AT_MOST:
                widthSize = dpToPx(MIN_SIZE_DEFAULT);
                break;
        }

        switch (heightMode) {
            case MeasureSpec.AT_MOST:
                heightSize = dpToPx(MIN_SIZE_DEFAULT);
                break;
        }

        int minSize = Math.min(widthSize, heightSize);

        //Update measured dimension.
        setMeasuredDimension(minSize, minSize);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        //Canvas circle image.
        drawCircleImage(canvas);

    }

    /**
    * Draw circle image with paint PorterDuff.
    *
    * @param canvas
    *         canvas.
    */
    private void drawCircleImage(Canvas canvas) {

        //Save layer with parameter.
        canvas.saveLayerAlpha(getLeft(), getTop(), getRight(), getBottom(), 200);

        //Get drawable source.
        Drawable drawable = getDrawable();
        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
        Bitmap bitmap = bitmapDrawable.getBitmap();

        //Computer circle image radius.
        float radiusX = (getWidth() - getPaddingLeft() - getPaddingRight()) / 2f;
        float radiusY = (getHeight() - getPaddingTop() - getPaddingBottom()) / 2f;
        float radius = Math.min(radiusX, radiusY);

        //Computer
        Rect rectF = new Rect();
        rectF.left = getLeft() + getPaddingLeft();
        rectF.top = getTop() + getPaddingTop();
        rectF.right = getRight() - getPaddingRight();
        rectF.bottom = getBottom() - getPaddingBottom();

        int targetBitmapWidth = rectF.right - rectF.left;
        int targetBitmapHeight = rectF.bottom - rectF.top;

        int diameter = (int) (radius * 2 + 0.5);

        float circleX = getPaddingLeft() + radius;
        float circleY = getPaddingTop() + radius;

        Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, targetBitmapWidth, targetBitmapHeight, false);

        /*
        Draw destination bitmap.
        */
        Bitmap bitmapDestination = Bitmap.createBitmap(targetBitmapWidth, targetBitmapHeight, Bitmap.Config.ARGB_8888);
        Canvas canvasDestination = new Canvas(bitmapDestination);
        //Draw circle.
        canvasDestination.drawCircle(circleX, circleY, radius, mDrawablePaint);
        //Draw destination bitmap.
        canvas.drawBitmap(bitmapDestination, 0, 0, mDrawablePaint);

        /*
        Set  paint's porterDuffMode
        */
        mDrawablePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

        /*
        Draw source bitmap.
        */
        canvas.drawBitmap(scaledBitmap, rectF, rectF, mDrawablePaint);

        //Reset mode value.
        mDrawablePaint.setXfermode(null);
        //Restore.
        canvas.restore();
    }


    private int dpToPx(int dp) {
        return (int) (dp * getResources().getDisplayMetrics().density + 0.5);
    }
}

圆形头像效果图

* 如果,您认为到这里就万事大吉了,那么很遗憾:请看下图 *

收尾点

所以,在绘制完成后,切记要加上:

Paint.setXfermode(null);

未完待续。。。


   转载规则


《Android自定义View之圆形头像》 Air 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录