Programmatically create a button with a gradient stroke?

I am working on a creating a button with no fill, but a gradient stroke. For reference, here is the end result I am after:

enter image description here

I would like to know how to create such a button with a gradient stroke and no fill programmatically. I looked over GradientDrawable class and the setStroke() method in it. None seem to allow this. Is there any way to programmatically perform this or is it not possible at all?

2 answers

  • answered 2018-05-16 07:08 rafa

    I don't think we can set gradient for Stroke but we can hack for the same using layer list.

    you can create below drawable xml with the gradient you wanted

    <item>
        <shape android:shape="rectangle">
            <!-- gradient for the stroke is set below -->
            <gradient
                android:angle="180"
                android:startColor="#555994"
                android:endColor="#b5b6d2"
                android:type="linear" />
            <corners android:radius="4dp"></corners>
        </shape>
    
    </item>
    <!-- stroke width has to be adjusted by setting left, right , top and bottom -->
    <item android:left="4dp" android:right="4dp"
        android:top="4dp" android:bottom="4dp">
        <shape
            android:shape="rectangle">
            <solid android:color="@android:color/white"/>
        </shape>
    </item>
    

    you can set the above drawable in layout/programmatically

    button.setBackgroundResource(R.drawable.button_background);

  • answered 2018-05-16 08:35 Mohit

    I have tried something for you.. Use mRect.set to set path and mPath.addRoundRectadd rectangle.Use setShader for strock purpose link

    Drawable class:

    public class CustomDrawable extends Drawable {
    Paint mPaint;
    int startColor, endColor, mBorderWidth, mBorderRadius;
    RectF mRect;
    Path mPath;
    
    public CustomDrawable(int startColor, int endColor, int borderWidth, int borderRadius) {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.FILL);
    
        mPath = new Path();
        mPath.setFillType(Path.FillType.EVEN_ODD);
    
        mRect = new RectF();
        this.startColor = startColor;
        this.endColor = endColor;
    
        mBorderWidth = borderWidth;
        mBorderRadius = borderRadius;
    }
    
    @Override
    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);
        mPath.reset();
    
        // out rect
        mRect.set(bounds.left + mBorderWidth, bounds.top + mBorderWidth, bounds.right - mBorderWidth, bounds.bottom - mBorderWidth);
        mPath.addRoundRect(mRect, mBorderRadius, mBorderRadius, Path.Direction.CW);
    
        // inner rect
        mRect.set(bounds.left + 20, bounds.top + 20, bounds.right - 20, bounds.bottom - 20);
        mPath.addRoundRect(mRect, mBorderRadius, mBorderRadius, Path.Direction.CW);
    }
    
    @Override
    public void draw(@NonNull Canvas canvas) {
        // kind of strock 
        mPaint.setShader(new LinearGradient(0, 0, 0, 100, startColor, endColor, Shader.TileMode.MIRROR));
        canvas.drawPath(mPath, mPaint);
    }
    @Override
    public void setAlpha(int alpha) { mPaint.setAlpha(alpha);}
    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {mPaint.setColorFilter(colorFilter);}
    @Override
    public int getOpacity() {return PixelFormat.TRANSLUCENT;}
    }
    

    Main :

    Button but = ((Button)findViewById(R.id.but));
    but.setBackground(new CustomDrawable(Color.parseColor("#FD659B"),
           Color.parseColor("#F76E63"),
           but.getPaddingLeft(), 100));
    

    layout :

    <Button
        android:id="@+id/but"
        android:layout_width="300dp"
        android:layout_height="80dp"
        android:background="@android:color/transparent"
        android:layout_centerInParent="true"
        android:text="Signin"/>