Search code examples
androidimageviewandroid-volleynetworkimageview

Android Circular Network Image View showing different sizes


Here is the code for implementing CircularNetworkImageView. I got what I wanted but the problem here is that the sizes of the circle images are not fixed. Some are either small or large. And depending on the size, the images are somewhat like jumping on different positions within the view layout. I have already set a fixed width and height on xml but the problem is still there. Please help me with this.

    public class CircularNetworkImageView extends NetworkImageView {
    Context mContext;

    public CircularNetworkImageView(Context context) {
        super(context);
        mContext = context;
    }

    public CircularNetworkImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        mContext = context;
    }

    public CircularNetworkImageView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        if(bm==null) return;
        setImageDrawable(new BitmapDrawable(mContext.getResources(),
                getCircularBitmap(bm)));
    }

    /**
     * Creates a circular bitmap and uses whichever dimension is smaller to determine the width
     * <br/>Also constrains the circle to the leftmost part of the image
     * 
     * @param bitmap
     * @return bitmap
     */
    public Bitmap getCircularBitmap(Bitmap bitmap) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        int width = bitmap.getWidth();
        if(bitmap.getWidth()>bitmap.getHeight())
            width = bitmap.getHeight();
        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, width, width);
        final RectF rectF = new RectF(rect);
        final float roundPx = width / 2;

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        return output;
    }

}

I got this code on this link here: CircularNetworkImageView.


Solution

  • I was also experiencing that issue before and luckily I found this one. Try this code instead:

        public class CircleImageView extends NetworkImageView {
    
        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 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 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 ColorFilter mColorFilter;
    
        private boolean mReady;
        private boolean mSetupPending;
        private boolean mBorderOverlay;
    
        public CircleImageView(Context context) {
            super(context);
    
            init();
        }
    
        public CircleImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        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);
    
            a.recycle();
    
            init();
        }
    
        private void init() {
            super.setScaleType(SCALE_TYPE);
            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
        public void setAdjustViewBounds(boolean adjustViewBounds) {
            if (adjustViewBounds) {
                throw new IllegalArgumentException("adjustViewBounds not supported.");
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            if (getDrawable() == null) {
                return;
            }
    
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
            if (mBorderWidth != 0) {
                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 void setBorderColorResource(@ColorRes int borderColorRes) {
            setBorderColor(getContext().getResources().getColor(borderColorRes));
        }
    
        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();
        }
    
        @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(@DrawableRes int resId) {
            super.setImageResource(resId);
            mBitmap = getBitmapFromDrawable(getDrawable());
            setup();
        }
    
        @Override
        public void setImageURI(Uri uri) {
            super.setImageURI(uri);
            mBitmap = getBitmapFromDrawable(getDrawable());
            setup();
        }
    
        @Override
        public void setColorFilter(ColorFilter cf) {
            if (cf == mColorFilter) {
                return;
            }
    
            mColorFilter = cf;
            mBitmapPaint.setColorFilter(mColorFilter);
            invalidate();
        }
    
        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(mBorderRect);
            if (!mBorderOverlay) {
                mDrawableRect.inset(mBorderWidth, 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() / (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);
        }
    
    }