package com.example.mywhaleai.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.BitmapShader;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.ColorFilter;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.RectF;import android.graphics.Shader;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.ColorDrawable;import android.graphics.drawable.Drawable;import android.net.Uri;import android.util.AttributeSet;import android.widget.ImageView;import androidx.annotation.ColorInt;import androidx.annotation.ColorRes;import androidx.annotation.DrawableRes;import com.example.mywhaleai.R;public class CircleImageView extends ImageView {    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 = 2;    /*默认参数*/    private static final int DEFAULT_BORDER_WIDTH = 0;    private static final int DEFAULT_BORDER_COLOR = Color.BLACK;    private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;    private static final boolean DEFAULT_BORDER_OVERLAY = false;    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 final Paint mFillPaint = new Paint();    private int mBorderColor = DEFAULT_BORDER_COLOR;    private int mBorderWidth = DEFAULT_BORDER_WIDTH;    private int mFillColor = DEFAULT_FILL_COLOR;    private Bitmap mBitmap;    private BitmapShader mBitmapShader;    private int mBitmapWidth;    private int mBitmapHeight;    private float mDrawableRadius;    private float mBorderRadius;    private ColorFilter mColorFilter;    private boolean mReady;    private boolean mSetupPending;    private boolean mBorderOverlay;    private boolean mDisableCircularTransformation;    public CircleImageView(Context context) {        super(context);        init();    }    /*构造函数*/    public CircleImageView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    /*构造函数,从xml中获取参数自定义的参数信息*/    public CircleImageView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);        mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);        mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);        mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);//        mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);        mFillColor=a.getColor(R.styleable.CircleImageView_civ_border_color,DEFAULT_FILL_COLOR);        a.recycle();        init();    }    /*初始化*/    private void init() {        super.setScaleType(SCALE_TYPE);        mReady = true;        if (mSetupPending) {            setup();            mSetupPending = false;        }    }    @Override    public ScaleType getScaleType() {        return SCALE_TYPE;    }    /*非SCALE_TYPE就报错*/    @Override    public void setScaleType(ScaleType scaleType) {        if (scaleType != SCALE_TYPE) {            throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));        }    }    @Override    public void setAdjustViewBounds(boolean adjustViewBounds) {        if (adjustViewBounds) {            throw new IllegalArgumentException("adjustViewBounds not supported.");        }    }    @Override    protected void onDraw(Canvas canvas) {        if (mDisableCircularTransformation) {            super.onDraw(canvas);            return;        }        if (mBitmap == null) {            return;        }        if (mFillColor != Color.TRANSPARENT) {            canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mFillPaint);//底色 mFillColor --> 画笔 mFillPaint        }        canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint); //画圆形图片        if (mBorderWidth > 0) {            canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint);//画边框,如果边框的宽度大于0才走进这里面        }    }    @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(@ColorInt int borderColor) {        if (borderColor == mBorderColor) {            return;        }        mBorderColor = borderColor;        mBorderPaint.setColor(mBorderColor);        invalidate();    }    /**     * @deprecated Use {@link #setBorderColor(int)} instead     */    @Deprecated    public void setBorderColorResource(@ColorRes int borderColorRes) {        setBorderColor(getContext().getResources().getColor(borderColorRes));    }    /**     * Return the color drawn behind the circle-shaped drawable.     *     * @return The color drawn behind the drawable     *     * @deprecated Fill color support is going to be removed in the future     */    @Deprecated    public int getFillColor() {        return mFillColor;    }    /**     * Set a color to be drawn behind the circle-shaped drawable. Note that     * this has no effect if the drawable is opaque or no drawable is set.     *     * @param fillColor The color to be drawn behind the drawable     *     * @deprecated Fill color support is going to be removed in the future     */    @Deprecated    public void setFillColor(@ColorInt int fillColor) {        if (fillColor == mFillColor) {            return;        }        mFillColor = fillColor;        mFillPaint.setColor(fillColor);        invalidate();    }    /**     * Set a color to be drawn behind the circle-shaped drawable. Note that     * this has no effect if the drawable is opaque or no drawable is set.     *     * @param fillColorRes The color resource to be resolved to a color and     *                     drawn behind the drawable     *     * @deprecated Fill color support is going to be removed in the future     */    @Deprecated    public void setFillColorResource(@ColorRes int fillColorRes) {        setFillColor(getContext().getResources().getColor(fillColorRes));    }    public int getBorderWidth() {        return mBorderWidth;    }    public void setBorderWidth(int borderWidth) {        if (borderWidth == mBorderWidth) {            return;        }        mBorderWidth = borderWidth;        setup();    }    public boolean isBorderOverlay() {        return mBorderOverlay;    }    public void setBorderOverlay(boolean borderOverlay) {        if (borderOverlay == mBorderOverlay) {            return;        }        mBorderOverlay = borderOverlay;        setup();    }    public boolean isDisableCircularTransformation() {        return mDisableCircularTransformation;    }    public void setDisableCircularTransformation(boolean disableCircularTransformation) {        if (mDisableCircularTransformation == disableCircularTransformation) {            return;        }        mDisableCircularTransformation = disableCircularTransformation;        initializeBitmap();    }    @Override    public void setImageBitmap(Bitmap bm) {        super.setImageBitmap(bm);        initializeBitmap();    }    @Override    public void setImageDrawable(Drawable drawable) {        super.setImageDrawable(drawable);        initializeBitmap();    }    @Override    public void setImageResource(@DrawableRes int resId) {        super.setImageResource(resId);        initializeBitmap();    }    @Override    public void setImageURI(Uri uri) {        super.setImageURI(uri);        initializeBitmap();    }    @Override    public void setColorFilter(ColorFilter cf) {        if (cf == mColorFilter) {            return;        }        mColorFilter = cf;        applyColorFilter();        invalidate();    }    @Override    public ColorFilter getColorFilter() {        return mColorFilter;    }    private void applyColorFilter() {        if (mBitmapPaint != null) {            mBitmapPaint.setColorFilter(mColorFilter);        }    }    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 (Exception e) {            e.printStackTrace();            return null;        }    }    private void initializeBitmap() {        if (mDisableCircularTransformation) {            mBitmap = null;        } else {            mBitmap = getBitmapFromDrawable(getDrawable());        }        setup();    }    /*这是个非常关键的方法,每次重绘都需要调用setup,需要在这里面转换bitmap计算圆形的半径和边框的半径长度,调用invalidate 重绘。*/    private void setup() {        if (!mReady) {            mSetupPending = true;            return;        }        if (getWidth() == 0 && getHeight() == 0) {            return;        }        if (mBitmap == null) {            invalidate();            return;        }        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);// 这里就把我们设置下去的图片放到了mBitmapShader当中,在ondraw里面直接drawcircle是就已经带图片的圆形了        mBitmapPaint.setAntiAlias(true);        mBitmapPaint.setShader(mBitmapShader);  //设置shader 给mBitmapPaint        mBorderPaint.setStyle(Paint.Style.STROKE);        mBorderPaint.setAntiAlias(true);        mBorderPaint.setColor(mBorderColor);        mBorderPaint.setStrokeWidth(mBorderWidth);        mFillPaint.setStyle(Paint.Style.FILL);        mFillPaint.setAntiAlias(true);        mFillPaint.setColor(mFillColor);        mBitmapHeight = mBitmap.getHeight();        mBitmapWidth = mBitmap.getWidth();        mBorderRect.set(calculateBounds());        mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);        mDrawableRect.set(mBorderRect);        if (!mBorderOverlay && mBorderWidth > 0) {            mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f);        }        mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);        applyColorFilter();        updateShaderMatrix();        invalidate();    }    private RectF calculateBounds() {        int availableWidth  = getWidth() - getPaddingLeft() - getPaddingRight();        int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();        int sideLength = Math.min(availableWidth, availableHeight);        float left = getPaddingLeft() + (availableWidth - sideLength) / 2f;        float top = getPaddingTop() + (availableHeight - sideLength) / 2f;        return new RectF(left, top, left + sideLength, top + sideLength);    }    private void updateShaderMatrix() {        float scale;        float dx = 0;        float dy = 0;        mShaderMatrix.set(null);        if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {            scale = mDrawableRect.height() / (float) mBitmapHeight;            dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;        } else {            scale = mDrawableRect.width() / (float) mBitmapWidth;            dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;        }        mShaderMatrix.setScale(scale, scale);        mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);        mBitmapShader.setLocalMatrix(mShaderMatrix);    }}

 

更多相关文章

  1. android中,显示圆形图片
  2. android DialogFragment使用 附例子
  3. Android(安卓)-- DiskLruCache
  4. 再也不信网上流传的方法了!!android创建组件的真正写法!
  5. Android屏幕解锁和点亮
  6. Retrofit2 ,Dagger2等常用框架注解功能介绍
  7. android 纯代码 详细编写布局文件
  8. android绑定点击事件的四种方法
  9. android ueventd 本地native部分源码分析

随机推荐

  1. React Native之如何在Android上添加阴影
  2. 十分钟让你了解Android触摸事件原理(Input
  3. app在android studio的构建过程
  4. Android是否可以实现静默安装模式
  5. android插件开发机制研究
  6. Android(安卓)React Native使用原生模块
  7. Android中广播的使用
  8. 关于Android高德地图4.12无法显示地图只
  9. android关于第3方包的问题
  10. Android高仿QQ下拉刷新