Search code examples
androidandroid-layoutandroid-fragmentsandroid-linearlayoutandroid-canvas

How to draw a circle in center in android


I want the circular image to be in the centre.
How to have it in the centre of the device?

I don't want to use a relative layout. I have all ready tried that, but it needs a hard coded value for the circle; hence. it won't work on all the devices. I am trying to achieve it by LinearLayout (using android:layout_weight property) I have tried android:layout_gravity="center",android:gravity="center" but the circle still won't make it to the centre. I have attached the screen for reference

enter image description here

I want the circle to be in parent center

My xml is:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.example.dd"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/LinearLayout02"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
       android:layout_gravity="center"  
        android:orientation="horizontal" >

        <Button
            android:id="@+id/Button04"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="left1" >
        </Button>

        <com.example.dd.CircularImageView
            android:id="@+id/round"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@drawable/buttonarea"
            app:border="true"
            app:border_color="#323232"
            app:border_width="55dp"
            app:shadow="true" />

        <Button
            android:id="@+id/Button08"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="right" >
        </Button>
    </LinearLayout>

</LinearLayout>

My circular class is:

     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();
        }

        public void setBorderWidth(int borderWidth) {
            Log.d("TAG","::::::::::::borderWidth"+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);
    }

    @Override
    public void onDraw(Canvas canvas) {
        // load the bitmap
        image = drawableToBitmap(getDrawable());

        // init shader
        if (image != null) {

            canvasSize = canvas.getWidth();
            Log.d("TAG","::::::::::::canvasSize"+canvasSize);
            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;
            }

my attrs.xml goes in values:

<?xml version="1.0" encoding="utf-8"?>

    <resources>

        <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>

    </resources>

Solution

  • Use some fake layouts and set the visibility to invisible. This should do the trick.

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.example.dd"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:orientation="vertical" >
    
    <LinearLayout
        android:id="@+id/LinearLayout02"
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:orientation="horizontal" >
    
        <Button
            android:id="@+id/Button04"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="left1" >
        </Button>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="vertical" >
    
            <Button
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:orientation="vertical"
                android:text="dummy"
                android:visibility="invisible" >
            </Button>
    
            <Button
                android:id="@+id/round"
                android:layout_width="fill_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="@android:drawable/star_on"
                app:shadow="true" />
    
            <Button
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:orientation="vertical"
                android:text="dummy"
                android:visibility="invisible" >
            </Button>
        </LinearLayout>
    
        <Button
            android:id="@+id/Button08"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="right" >
        </Button>
     </LinearLayout>
    
    </LinearLayout>