Android实现圆形头像

ClipPath

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;

import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;


public class ClipPathCircleView extends AppCompatImageView {

    private Paint mPaint;
    private int mRadius;// 圆形图片的半径

    private Path mPath;
    private RectF mRect;
    private Bitmap mBitmap;


    public ClipPathCircleView(Context context) {
        super(context);
        init();
    }

    public ClipPathCircleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ClipPathCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }


    private void init(){
        mPaint = new Paint();
        mPaint.setDither(true);
        mPaint.setAntiAlias(true);

        mPath = new Path();
        mRect = new RectF();
        mBitmap = drawableToBitmap(getDrawable());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int size = Math.min(getMeasuredWidth(),getMeasuredHeight());
        mRadius = size / 2;
        setMeasuredDimension(size,size);
    }

    //canvas.save();
    //Path path = new Path();
    //path.addCircle(300, 300, 200, Path.Direction.CCW); // 画一个圆形的path
    //canvas.clipPath(path); // 裁剪画布的区域为圆形
    //RectF rectF = new RectF(100, 100, 500, 500);
    //canvas.drawBitmap(photo, null, rectF, paint); // 在区域之外的部分不会被渲染出来
    //canvas.restore();
    @Override
    protected void onDraw(Canvas canvas) {
        // 注意如果这行不注释调,ImageView会把原图画在底部
        //super.onDraw(canvas);
        mRect.set(0,0,mRadius*2,mRadius*2);
        mBitmap = thumbImageWithMatrix(mRadius*2,mRadius*2,mBitmap);

        mPath.addCircle(mRadius,mRadius,mRadius, Path.Direction.CCW);// 逆时针
        canvas.clipPath(mPath);
        // 第一个rect是要画图片的哪个区域,第一个rect是画到哪里
        canvas.drawBitmap(mBitmap,null,mRect,mPaint);

    }

    //写一个drawble转BitMap的方法
    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }



    // https://www.jianshu.com/p/abcfa74c967b
    /**
     * 此方法对图片进行缩小,无法放大
     * @param targetWidth
     * @param targetHeight
     * @return
     */
    private Bitmap zoomBitmap(int targetWidth,int targetHeight, int bitmapRes){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(),bitmapRes,options);
        float scaleW = options.outWidth / (targetWidth*1f);
        float scaleH = options.outHeight / (targetHeight*1f);
        int size = (int)Math.max(scaleW,scaleH);
        if (size <= 1){
            options.inSampleSize = 1;
        }else {
            options.inSampleSize = size;
        }
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(getResources(),bitmapRes,options);
    }

    private Bitmap zoomBitmapV1(int targetWidth,int targetHeight, int bitmapRes){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(), bitmapRes, options);
        options.inJustDecodeBounds = false;
        //设置位图的屏幕密度,即每英寸有多少个像素
        options.inDensity = options.outWidth;
        //设置位图被画出来时的目标像素密度
        //与options.inDensity配合使用,可对图片进行缩放
        options.inTargetDensity = targetWidth;
        return BitmapFactory.decodeResource(getResources(),bitmapRes,options);
    }

    /**
     * 对图片进行缩放
     * 图片始终都会被加载到内存中,注意OOM
     * @param destWidth
     * @param destHeight
     * @param bitmapOrg
     * @return
     */
    public Bitmap thumbImageWithMatrix(float destWidth, float destHeight,Bitmap bitmapOrg) {
        float bitmapOrgW = bitmapOrg.getWidth();
        float bitmapOrgH = bitmapOrg.getHeight();

        float bitmapNewW = (int) destWidth;
        float bitmapNewH = (int) destHeight;

        Matrix matrix = new Matrix();
        matrix.postScale(bitmapNewW / bitmapOrgW, bitmapNewH / bitmapOrgH);
        Bitmap destBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0, (int) bitmapOrgW, (int) bitmapOrgH, matrix, true);
        //bitmapOrg.recycle();
        return destBitmap;
    }

}

BitmapShader

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;


public class BitmapShaderCircleView extends AppCompatImageView {

    private Paint mPaint;
    private int mRadius;// 圆形图片的半径


    public BitmapShaderCircleView(@NonNull Context context) {
        super(context);
        init();
    }

    public BitmapShaderCircleView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public BitmapShaderCircleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //因为是圆形图片,所以应该让宽高保持一致
        int size = Math.min(getMeasuredWidth(),getMeasuredHeight());
        mRadius = size / 2;
        setMeasuredDimension(size,size);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        Bitmap bitmap = drawableToBitmap(getDrawable());
        //初始化BitmapShader,传入bitmap对象
        BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        //计算图片的缩放比例
        float mScale = (mRadius * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());
        Matrix matrix = new Matrix();
        matrix.setScale(mScale, mScale);
        bitmapShader.setLocalMatrix(matrix);

        mPaint.setShader(bitmapShader);

        //画圆形,指定好中心点坐标、半径、画笔
        canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
    }

    //写一个drawble转BitMap的方法
    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }

}

Xfermode

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Xfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;


public class PorterDuffXfermodeCircleView extends AppCompatImageView {

    private Paint mPaint;
    private int mRadius;// 圆形图片的半径
    private Xfermode mPorterDuffXfermode; // 图像混合模式

    public PorterDuffXfermodeCircleView(@NonNull Context context) {
        super(context);
        init();
    }

    public PorterDuffXfermodeCircleView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PorterDuffXfermodeCircleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        //绘制两层,先绘制形状(DST),再绘制图片(SRC),然后根据Xfermode来去计算两个图层的关系(SRC_IN:显示的区域是二者交集部分的SRC)。
        mPorterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //因为是圆形图片,所以应该让宽高保持一致
        int size = Math.min(getMeasuredWidth(),getMeasuredHeight());
        mRadius = size / 2;
        setMeasuredDimension(size,size);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //获取sourceBitmap,即通过xml或者java设置进来的图片
        Drawable drawable = getDrawable();
        if (drawable == null) return;

        Bitmap sourceBitmap = ((BitmapDrawable)getDrawable()).getBitmap();
        if (sourceBitmap != null){
            //对图片进行缩放,以适应控件的大小
            Bitmap bitmap = resizeBitmap(sourceBitmap,getWidth(),getHeight());
            drawCircleBitmapByXfermode(canvas,bitmap);    //(1)利用PorterDuffXfermode实现
        }
    }

    private Bitmap resizeBitmap(Bitmap sourceBitmap,int dstWidth,int dstHeight){
        int width = sourceBitmap.getWidth();
        int height = sourceBitmap.getHeight();

        float widthScale = ((float)dstWidth) / width;
        float heightScale = ((float)dstHeight) / height;

        //取最大缩放比
        float scale = Math.max(widthScale,heightScale);
        Matrix matrix = new Matrix();
        matrix.postScale(scale,scale);

        return Bitmap.createBitmap(sourceBitmap,0,0,width,height,matrix,true);
    }

    //相同点
    //saveLayer可以实现save所能实现的功能
    //不同点
    //1,saveLaye生成一个独立的图层而save只是保存了一下当时画布的状态类似于一个还原点(本来就是)。
    //2,saveLaye因为多了一个图层的原因更加耗费内存慎用。
    //3,saveLaye可指定保存相应区域,尽量避免2中所指的情况。
    //4,在使用混合模式setXfermode时会产生不同的影响。

    //https://blog.csdn.net/lijiuche/article/details/53467844
    //https://blog.csdn.net/qq_24000367/article/details/120796261
    // https://blog.csdn.net/u010852160/article/details/72918551
    private void drawCircleBitmapByXfermode(Canvas canvas,Bitmap bitmap){
        final int sc = canvas.saveLayer(0,0,getWidth(),getHeight(),null,Canvas.ALL_SAVE_FLAG);
        //canvas.save();这里不能使用
        //绘制dst层
        canvas.drawCircle(mRadius,mRadius,mRadius,mPaint);
        //设置图层混合模式为SRC_IN
        mPaint.setXfermode(mPorterDuffXfermode);
        //绘制src层
        canvas.drawBitmap(bitmap,0,0,mPaint);
        //canvas.restore();
        canvas.restoreToCount(sc);
    }
}

参考文章
Android圆形图片不求人,自定义View实现(BitmapShader使用)
android圆形图片效果
Android 实现圆角/圆形图片的几种方式
Android绘制圆形图片的3个方法
浅谈Android实现圆形头像效果的几种思路和方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值