zoukankan      html  css  js  c++  java
  • Android 自定义圆形图片 CircleImageView

    1.效果预览

    1.1.布局中写自定义圆形图片的路径即可

      

    1.2.然后看一看图片效果

      

    1.3.原图是这样的 @mipmap/ic_launcher

      


    2.使用过程

    2.1.CircleImageView源代码 

    public class CircleImageView extends AppCompatImageView {
    
        private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
    
        private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
        private static final int COLORDRAWABLE_DIMENSION = 1;
    
        private static final int DEFAULT_BORDER_WIDTH = 0;
        private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
    
        private final RectF mDrawableRect = new RectF();
        private final RectF mBorderRect = new RectF();
    
        private final Matrix mShaderMatrix = new Matrix();
        private final Paint mBitmapPaint = new Paint();
        private final Paint mBorderPaint = new Paint();
    
        private int mBorderColor = DEFAULT_BORDER_COLOR;
        private int mBorderWidth = DEFAULT_BORDER_WIDTH;
    
        private Bitmap mBitmap;
        private BitmapShader mBitmapShader;
        private int mBitmapWidth;
        private int mBitmapHeight;
    
        private float mDrawableRadius;
        private float mBorderRadius;
    
        private boolean mReady;
        private boolean mSetupPending;
    
        public CircleImageView(Context context) {
            super(context);
        }
    
        public CircleImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            super.setScaleType(SCALE_TYPE);
    
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
    
            mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH);
            mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR);
    
            a.recycle();
    
            mReady = true;
    
            if (mSetupPending) {
                setup();
                mSetupPending = false;
            }
        }
    
        @Override
        public ScaleType getScaleType() {
            return SCALE_TYPE;
        }
    
        @Override
        public void setScaleType(ScaleType scaleType) {
            if (scaleType != SCALE_TYPE) {
                throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            if (getDrawable() == null) {
                return;
            }
    
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            setup();
        }
    
        public int getBorderColor() {
            return mBorderColor;
        }
    
        public void setBorderColor(int borderColor) {
            if (borderColor == mBorderColor) {
                return;
            }
    
            mBorderColor = borderColor;
            mBorderPaint.setColor(mBorderColor);
            invalidate();
        }
    
        public int getBorderWidth() {
            return mBorderWidth;
        }
    
        public void setBorderWidth(int borderWidth) {
            if (borderWidth == mBorderWidth) {
                return;
            }
    
            mBorderWidth = borderWidth;
            setup();
        }
    
        @Override
        public void setImageBitmap(Bitmap bm) {
            super.setImageBitmap(bm);
            mBitmap = bm;
            setup();
        }
    
        @Override
        public void setImageDrawable(Drawable drawable) {
            super.setImageDrawable(drawable);
            mBitmap = getBitmapFromDrawable(drawable);
            setup();
        }
    
        @Override
        public void setImageResource(int resId) {
            super.setImageResource(resId);
            mBitmap = getBitmapFromDrawable(getDrawable());
            setup();
        }
    
        private Bitmap getBitmapFromDrawable(Drawable drawable) {
            if (drawable == null) {
                return null;
            }
    
            if (drawable instanceof BitmapDrawable) {
                return ((BitmapDrawable) drawable).getBitmap();
            }
    
            try {
                Bitmap bitmap;
    
                if (drawable instanceof ColorDrawable) {
                    bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
                } else {
                    bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
                }
    
                Canvas canvas = new Canvas(bitmap);
                drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
                drawable.draw(canvas);
                return bitmap;
            } catch (OutOfMemoryError e) {
                return null;
            }
        }
    
        private void setup() {
            if (!mReady) {
                mSetupPending = true;
                return;
            }
    
            if (mBitmap == null) {
                return;
            }
    
            mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    
            mBitmapPaint.setAntiAlias(true);
            mBitmapPaint.setShader(mBitmapShader);
    
            mBorderPaint.setStyle(Paint.Style.STROKE);
            mBorderPaint.setAntiAlias(true);
            mBorderPaint.setColor(mBorderColor);
            mBorderPaint.setStrokeWidth(mBorderWidth);
    
            mBitmapHeight = mBitmap.getHeight();
            mBitmapWidth = mBitmap.getWidth();
    
            mBorderRect.set(0, 0, getWidth(), getHeight());
            mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2);
    
            mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
            mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2);
    
            updateShaderMatrix();
            invalidate();
        }
    
        private void updateShaderMatrix() {
            float scale;
            float dx = 0;
            float dy = 0;
    
            mShaderMatrix.set(null);
    
            if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
                scale = mDrawableRect.height() / mBitmapHeight;
                dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
            } else {
                scale = mDrawableRect.width() / mBitmapWidth;
                dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
            }
    
            mShaderMatrix.setScale(scale, scale);
            mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth);
    
            mBitmapShader.setLocalMatrix(mShaderMatrix);
        }
    
    }
    View Code

    2.2.在values中新建一个资源文件==>attrs_CircleImageView.xml  

    <resources>
    
        <!-- 圆形头像 -->
        <declare-styleable name="CircleImageView">
            <attr name="border_width" format="dimension" />
            <attr name="border_color" format="color" />
        </declare-styleable>
    
    </resources>
    View Code

    2.3.布局中将ImageView视图换成自定义类,路径写自己的

      

      

    2.4.大功告成!然后图片就乖乖地变成圆形了。如果想了解源码,请看下方的分析。


    3.CircleImageView源代码分析

    3.1.成员变量分析

      

      ScaleType是图片显示方式。可以参考一下这篇文章了解ScaleType。

      可以有八种取值方式:

      ①.matrix==>表示原图从ImageView的左上角开始绘制。

      ②.fitXY==>填充整个ImageView,需要对图片进行一些缩放,会变形。

      ③.fitStart==>按比例缩放至View的宽度或者高度(取最小值),然后居上或者居左显示。

      ④.fitCenter==>将图片按比例缩放之后居中显示。

      ⑤.fitEnd==>按比例缩放之后居右或者居下显示。

      ⑥.center==>将原图按照原来的大小居中显示,如果超出ImageView的大小,剪裁掉多余的部分。

      ⑦.centerCrop==>将ImageView填充满,按照比例缩放原图,多余的宽和高裁剪掉,最常用的。

      ⑧.centerInside==>将原图完整的显示出来,按照比例缩放原图,一般都变得很小了。

      Bitmap.Config是什么东西呢?可以参考一下这篇文章了解Bitmap.Config。

      其实这都是色彩的存储方法,我们知道ARGB指的是一种色彩模式。

      里面A代表Alpha,R表示Red,G表示Green,B表示Blue。每个原色都存储着所表示的颜色的信息值。

      

      位图位数越高代表其可以存储的颜色信息越多,当然图像也就越逼真。

      这里定义了一个COLORDEAWABLE_DIMESION用来干什么呢?

      

      然后又定义了一个DEFAULT_BORDER_WIDTH,用来干啥呢?

      首先了解一下TypedArray,参考一下这篇文章。

      首先需要有一个资源文件,就是自定义的视图布局,这里是attrs_CircleImageView.xml

      

        然后这里用到了DEFAULT_BORDER_WIDTH了。

      

      了解一下RectF,参考一下这篇文章了解RectF。

      RectF类和Rect类似,但是RectF参数是传的Float,所以尾巴有个F了。

      

      可以参考一下这篇文章了解Matrix。

      这其实就是一个三维矩阵。

      

      然后主要作用分成4块。

      

       用到的方法有:

      

      

      postTranslate是指在setScale后平移。

      由于缩放是以(0,0)为中心,所以为了把界面的中心与(0,0)对齐,调用postTranslate(centerX,centerY)把

      图片向这(x,y)方向移动。

      什么是Paint类呢?参考这篇文章详细了解。

      这个类可以画集合图形,文本和Bitmap。

      

      什么是BitmapShader呢?参考这篇文章详细了解。

      就是处理图片渲染的。可以做到这样的效果。

      

      然后定义了两个整型数据,两个浮点型,两个boolean型,之后再分析作用。

      

    3.2.构造函数分析

      一个参数的构造函数

      

      两个参数的构造函数

      

      三个参数的构造函数

      

      这个是最关键的一个构造函数了。

      将资源文件中的宽度和颜色获取到。

      然后调用setup()函数进行初始化。

    3.3.重写函数getScaleType

      

      

    3.4.重写函数setScaleType

      

    3.5.重写onDraw

      

      这里用canvas画了两个圆。

      android中对于Canvas.drawCircle()方法不理解的可以参考这篇文章。

    3.6.重写onSizeChanged

      

    3.7.边界颜色  

      

    3.8.边界宽度

      

      调用了自己写的一个setup()函数。

    3.9.重写setImageBitmap

      

      调用了自己写的一个setup()函数。 

    3.10.重写setImageDrawable

      

      调用了自己写的一个setup()函数。

    3.11.重写setImageResource

      

      调用了自己写的一个setup()函数。

    3.12.将Drawable转换成Bitmap

      

    3.13.自己写的setup函数

      

    3.14.更新渲染

      


    4.其他自定义圆形图片

    4.1.Android开发之自定义圆形的ImageView的实现

      效果如下:

      

      自定类代码如下:

    /**
     * 自定义的圆形ImageView,可以直接当组件在布局中使用。
     * @author caizhiming
     *
     */
    public class XCRoundImageView extends ImageView{
    
        private Paint paint ;
        
        public XCRoundImageView(Context context) {  
            this(context,null);  
        }  
      
        public XCRoundImageView(Context context, AttributeSet attrs) {  
            this(context, attrs,0);  
        }  
      
        public XCRoundImageView(Context context, AttributeSet attrs, int defStyle) {  
            super(context, attrs, defStyle); 
            paint = new Paint();
            
        }  
      
        /**
         * 绘制圆形图片
         * @author caizhiming
         */
        @Override  
        protected void onDraw(Canvas canvas) {  
      
            Drawable drawable = getDrawable();  
            if (null != drawable) {  
                Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();  
                Bitmap b = getCircleBitmap(bitmap, 14);  
                final Rect rectSrc = new Rect(0, 0, b.getWidth(), b.getHeight());  
                final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
                paint.reset();  
                canvas.drawBitmap(b, rectSrc, rectDest, paint);  
      
            } else {  
                super.onDraw(canvas);  
            }  
        }  
      
        /**
         * 获取圆形图片方法
         * @param bitmap
         * @param pixels
         * @return Bitmap
         * @author caizhiming
         */
        private Bitmap getCircleBitmap(Bitmap bitmap, int pixels) {  
            Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),  
                    bitmap.getHeight(), Config.ARGB_8888);  
            Canvas canvas = new Canvas(output);  
              
            final int color = 0xff424242;
           
            final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());  
            paint.setAntiAlias(true);  
            canvas.drawARGB(0, 0, 0, 0);  
            paint.setColor(color);  
            int x = bitmap.getWidth(); 
            
            canvas.drawCircle(x / 2, x / 2, x / 2, paint);  
            paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));  
            canvas.drawBitmap(bitmap, rect, rect, paint);  
            return output;  
            
            
        }  
    }  
    View Code

    4.2.第三方库圆形头像CircleImageView的使用

      效果如下:

      

      用法如下:

      

    4.3.自定义ImageView系列——简单圆形图片

      效果如下:

      

      源代码:

    public class CircleImageView extends ImageView {
    
        //基本的三个构造函数
        public CircleImageView(Context context) {
            super(context);
        }
    
        public CircleImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        //自定义View实现过程中很重要的onDraw绘制图形的方法
        @Override
        protected void onDraw(Canvas canvas) {
    
            Drawable drawable = getDrawable();
    
            //空值判断,必要步骤,避免由于没有设置src导致的异常错误
            if (drawable == null) {
                return;
            }
    
            //必要步骤,避免由于初始化之前导致的异常错误
            if (getWidth() == 0 || getHeight() == 0) {
                return;
            }
    
            if (!(drawable instanceof BitmapDrawable)) {
                return;
            }
            Bitmap b = ((BitmapDrawable) drawable).getBitmap();
    
            if (null == b) {
                return;
            }
    
            Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
    
            int w = getWidth();
    
            Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
            canvas.drawBitmap(roundBitmap, 0, 0, null);
    
        }
    
        /**
         * 初始Bitmap对象的缩放裁剪过程
         * @param bmp       初始Bitmap对象
         * @param radius    圆形图片直径大小
         * @return 返回一个圆形的缩放裁剪过后的Bitmap对象
         */
        public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
            Bitmap sbmp;
            //比较初始Bitmap宽高和给定的圆形直径,判断是否需要缩放裁剪Bitmap对象
            if (bmp.getWidth() != radius || bmp.getHeight() != radius)
                sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);
            else
                sbmp = bmp;
            Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(),
                    Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
    
            final Paint paint = new Paint();
            final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight());
    
            paint.setAntiAlias(true);
            paint.setFilterBitmap(true);
            paint.setDither(true);
            canvas.drawARGB(0, 0, 0, 0);
            paint.setColor(Color.parseColor("#BAB399"));
            canvas.drawCircle(sbmp.getWidth() / 2 + 0.7f,
                    sbmp.getHeight() / 2 + 0.7f, sbmp.getWidth() / 2 + 0.1f, paint);
            //核心部分,设置两张图片的相交模式,在这里就是上面绘制的Circle和下面绘制的Bitmap
            paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
            canvas.drawBitmap(sbmp, rect, rect, paint);
    
            return output;
        }
    
    }
    View Code


    既然选择了,便不顾风雨兼程。Just follow yourself.
  • 相关阅读:
    oracle 与mysql 的当前时间比较
    easyui 时间定格为 时分
    date类型数据插入
    mac 获取idea&&datagrip激活码
    静态代码块
    nginx mac 下启动 停止 重启,查看安装位置
    定时任务的时间规则
    雅酷帮微信公众平台操作手册
    微信公众平台中通过网页增加好友
    微信公众平台消息接口开发之微信浏览器HTTP_USER_AGENT判断
  • 原文地址:https://www.cnblogs.com/Jason-Jan/p/7919311.html
Copyright © 2011-2022 走看看