How to make a circular drawable with stroke, programmatically?

11,046

You can do this programmatically as
In YourActivity.XMl, Set-up an ImageView as usual.

<ImageView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:id="@+id/id1"
            android:src="@mipmap/ic_launcher_round"                                
            android:padding="15dp"/>

And in your MainActivity.java

    ImageView iV = (ImageView) findViewById(R.id.id1);
    int strokeWidth = 5;
    int strokeColor = Color.parseColor("#03dc13");
    int fillColor = Color.parseColor("#ff0000");
    GradientDrawable gD = new GradientDrawable();
    gD.setColor(fillColor);
    gD.setShape(GradientDrawable.OVAL);
    gD.setStroke(strokeWidth, strokeColor);
    iV.setBackground(gD);

setColor here sets the background color and setStroke sets the stroke width and stroke color.
I have created some local variables for color, width etc to make it more easy to understand.
Result
enter image description here
More you increase the padding, more will the size of circle increase.

Share:
11,046

Related videos on Youtube

android developer
Author by

android developer

Really like to develop Android apps &amp; libraries on my spare time. Github website: https://github.com/AndroidDeveloperLB/ My spare time apps: https://play.google.com/store/apps/developer?id=AndroidDeveloperLB

Updated on June 04, 2022

Comments

  • android developer
    android developer almost 2 years

    Background

    I'm trying to have a filled circle, with a stroke of certain color and width, and an image inside.

    This can easily be done in XML, as such (this is just a sample) :

    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item>
            <shape android:shape="oval">
                <size
                    android:width="120dp" android:height="120dp"/>
                <solid android:color="#ffff0000"/>
                <stroke
                    android:width="3dp" android:color="#ff00ff00"/>
            </shape>
        </item>
        <item
            android:width="60dp" android:height="60dp" android:drawable="@android:drawable/btn_star"
            android:gravity="center"/>
    </layer-list>
    

    enter image description here

    The problem

    I need to have certain properties of the above to change programmatically, so I can't use the XML file, but the idea is still the same.

    Thing is, I can't find an easy way to put a stroke on an OvalShape drawable, as done in XML. I can't find the function to do it.

    What I tried

    There are solutions out there here on StackOverflow, but I couldn't find one that works well. Only one I've found is here, but its stroke line is being cut .

    I have, however, partially succeeded in one way to solve this, by using an XML just for the stroke itself:

    stroke_drawable.xml

    <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
        <stroke
            android:width="4dp" android:color="@android:color/white"/>
    </shape>
    

    code:

        final int strokeDrawableResId = R.drawable.stroke_drawable;
        Drawable innerDrawable = ResourcesCompat.getDrawable(getResources(), ..., null);
        final Drawable strokeDrawable = ResourcesCompat.getDrawable(getResources(), strokeDrawableResId, null);
        ShapeDrawable biggerCircle = new ShapeDrawable(new OvalShape());
        int size = ...;
        biggerCircle.setIntrinsicHeight(size);
        biggerCircle.setIntrinsicWidth(size);
        biggerCircle.getPaint().setColor(0xffff0000);
        biggerCircle.setBounds(new Rect(0, 0, size, size));
        LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{biggerCircle, strokeDrawable, innerDrawable});
    
        ImageView imageView = findViewById(R.id.imageView);
        imageView.setImageDrawable(layerDrawable);
    

    It works, but it's not fully programmatically (stroke is defined in XML).

    The question

    How to change the code to be fully programmatic ?


    EDIT: I tried what was suggested here, yet instead of an additional drawable for a background, since I needed it all in one drawable, I used LayerDrawable:

        Drawable innerDrawable = ResourcesCompat.getDrawable(getResources(), android.R.drawable.btn_star, null);
        int strokeWidth = 5;
        int strokeColor = Color.parseColor("#ff0000ff");
        int fillColor = Color.parseColor("#ffff0000");
        GradientDrawable gD = new GradientDrawable();
        gD.setColor(fillColor);
        gD.setShape(GradientDrawable.OVAL);
        gD.setStroke(strokeWidth, strokeColor);
        LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{gD, innerDrawable});
        ImageView imageView = findViewById(R.id.imageView);
        imageView.setImageDrawable(layerDrawable);
    

    This works, but for some reason the drawable inside (the star) is being stretched:

    enter image description here

  • TacB0sS
    TacB0sS over 6 years
    best answer I've seen all day... Thanks