Search code examples
androidandroid-viewwear-os

CircledImageView always have rectangle image in front of the circle


I can get the CircledImageView to work, except that the image is always rectangle, and in front of the white circle (and cover the circle partially). Is this correct? My assumption is that I should see the image INSIDE the circle.

    <android.support.wearable.view.CircledImageView
    android:id="@+id/image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/kids"
    app:circle_radius="60dp"
    app:circle_color="@color/white" />

xmlns:app="http://schemas.android.com/apk/res-auto"

Thanks for any suggestions.

I have read this and it does not help: Android Wear CircledImageView (and DelayedConfirmationView) Always Square


Solution

  • you can create your own custom circular ImageView extending ImageView Class...

    i have created one.. may be you can use it..

    public class CircularImageView extends ImageView {
        private int borderWidth;
        private int canvasSize;
        private Bitmap image;
        private Paint paint;
        private Paint paintBorder;
    
        public CircularImageView(final Context context) {
            this(context, null);
        }
    
        public CircularImageView(Context context, AttributeSet attrs) {
            this(context, attrs, R.attr.circularImageViewStyle);
        }
    
        public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
    
            // init paint
            paint = new Paint();
            paint.setAntiAlias(true);
    
            paintBorder = new Paint();
            paintBorder.setAntiAlias(true);
    
            // load the styled attributes and set their properties
            TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CircularImageView, defStyle, 0);
    
            if(attributes.getBoolean(R.styleable.CircularImageView_border, true)) {
                int defaultBorderSize = (int) (4 * getContext().getResources().getDisplayMetrics().density + 0.5f);
                setBorderWidth(attributes.getDimensionPixelOffset(R.styleable.CircularImageView_border_width, defaultBorderSize));
                setBorderColor(attributes.getColor(R.styleable.CircularImageView_border_color, Color.WHITE));
            }
    
            if(attributes.getBoolean(R.styleable.CircularImageView_shadow, false))
                addShadow();
    
            attributes.recycle();
        }
    
        public void setBorderWidth(int borderWidth) {
            this.borderWidth = borderWidth;
            this.requestLayout();
            this.invalidate();
        }
    
        public void setBorderColor(int borderColor) {
            if (paintBorder != null)
                paintBorder.setColor(borderColor);
            this.invalidate();
        }
    
        public void addShadow() {
            setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
            paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
        }
    
        @SuppressLint("DrawAllocation")
        @Override
        public void onDraw(Canvas canvas) {
            // load the bitmap
            image = drawableToBitmap(getDrawable());
    
            // init shader
            if (image != null) {
    
                canvasSize = canvas.getWidth();
                if(canvas.getHeight()<canvasSize)
                    canvasSize = canvas.getHeight();
    
                BitmapShader shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvasSize, canvasSize, false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
                paint.setShader(shader);
    
                // circleCenter is the x or y of the view's center
                // radius is the radius in pixels of the cirle to be drawn
                // paint contains the shader that will texture the shape
                int circleCenter = (canvasSize - (borderWidth * 2)) / 2;
                canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) + borderWidth - 4.0f, paintBorder);
                canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) - 4.0f, paint);
            }
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int width = measureWidth(widthMeasureSpec);
            int height = measureHeight(heightMeasureSpec);
            setMeasuredDimension(width, height);
        }
    
        private int measureWidth(int measureSpec) {
            int result = 0;
            int specMode = MeasureSpec.getMode(measureSpec);
            int specSize = MeasureSpec.getSize(measureSpec);
    
            if (specMode == MeasureSpec.EXACTLY) {
                // The parent has determined an exact size for the child.
                result = specSize;
            } else if (specMode == MeasureSpec.AT_MOST) {
                // The child can be as large as it wants up to the specified size.
                result = specSize;
            } else {
                // The parent has not imposed any constraint on the child.
                result = canvasSize;
            }
    
            return result;
        }
    
        private int measureHeight(int measureSpecHeight) {
            int result = 0;
            int specMode = MeasureSpec.getMode(measureSpecHeight);
            int specSize = MeasureSpec.getSize(measureSpecHeight);
    
            if (specMode == MeasureSpec.EXACTLY) {
                // We were told how big to be
                result = specSize;
            } else if (specMode == MeasureSpec.AT_MOST) {
                // The child can be as large as it wants up to the specified size.
                result = specSize;
            } else {
                // Measure the text (beware: ascent is a negative number)
                result = canvasSize;
            }
    
            return (result + 2);
        }
    
        public Bitmap drawableToBitmap(Drawable drawable) {
            if (drawable == null) {
                return null;
            } else if (drawable instanceof BitmapDrawable) {
                return ((BitmapDrawable) drawable).getBitmap();
            }
    
            Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
                    drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
    
            return bitmap;
        }
    }
    

    Then in values/attrs file.. add the following lines..

    <declare-styleable name="CircularImageView">
            <attr name="border" format="boolean"></attr>
            <attr name="border_width" format="dimension"></attr>
            <attr name="border_color" format="color"></attr>
            <attr name="shadow" format="boolean"></attr>
        </declare-styleable>
        <declare-styleable name="Theme">
            <attr name="circularImageViewStyle" format="reference"></attr>
        </declare-styleable>
    

    And finally you can define this circular image view like this..

       <youpackage.name.CircularImageView
                    xmlns:app="http://schemas.android.com/apk/res/yourpackage.name"
                    android:id="@+id/imageView_Company_Logo"
                    android:layout_width="65dp"
                    android:layout_height="65dp"
                    app:border="true"
                    app:border_color="@color/App_Theme_Green"
                    app:border_width="4dp"
                    app:shadow="false"
                    android:src="@drawable/ic_launcher" />
    
    1. you can apply/remove border by setting true/false in app:border="true" and change border color and width with

      app:border_color="@color/App_Theme_Green" app:border_width="4dp"

    2. you can apply/remove shadow by setting true/false in app:border="true"

    Hope it helps..!!!