IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Android实现圆形头像 -> 正文阅读

[游戏开发]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实现圆形头像效果的几种思路和方法

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-02-26 12:03:55  更:2022-02-26 12:06:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 16:26:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码