Jetpack Compose Button with Gradient Border

Jetpack Compose Button Gradient Border

This is an Android Jetpack Compose button with gradient border. There are a total of 3 buttons.

The first one displays the number of taps on it. When you click on it, the count will be incremented by 1 and displayed on the button text. I removed the ripple effect on it.

The second one is a round corner button. I set the corner radius to 50% using the RoundedCornerShape API. I have also applied clip to the same shape so that the ripple will be fit within the button.

The third one gets disabled when you tap on it. When disabled, the button style will be a color with light gray.

The Jetpack Compose gradient border button takes multiple parameters like context, padding values, colors for the style, etc… You can change them according to your requirement. The context is used to display the Toast message. The padding values are to add gap between the border and the text. The colors are the actual gradient colors.

All of these button styles are made with Box layout. The Box itself acts as the button background. Inside of it, there is a text. I applied all the styles like gradient border, padding, fillMaxWidth (about 60% of the device width) to the Box.

You need to download the latest version of Android Studio to use the code. The Jetpack Compose doesn’t work in the older versions.

Related:

Final output:

If the video isn’t working, watch it on the YouTube.

Helpful links to understand the code:

Here are the Gradle files used in the project.

Note: I’m using the Box layout to make these buttons. You can also use the OutlinedButton composable. But the problem is that they follow material guidelines. You can’t totally customize them to meet your needs. For example, you cannot remove the ripple effect.

Here is the source code:

MainActivity.kt:

import android.content.Context
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

/*
You can use the following code for commercial purposes with some restrictions.
Read the full license here: https://semicolonspace.com/semicolonspace-license/
For more designs with source code,
visit: https://semicolonspace.com/jetpack-compose-samples/
 */
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            YourProjectNameTheme(darkTheme = false) {

                val colors = listOf(Color(0xFFffe53b), Color(0xFFff2525))
                val context = LocalContext.current.applicationContext
                val paddingValues = PaddingValues(horizontal = 24.dp, vertical = 12.dp)
                val widthFraction = 0.68f

                Column(
                    modifier = Modifier.fillMaxSize(),
                    horizontalAlignment = Alignment.CenterHorizontally,
                    verticalArrangement = Arrangement.spacedBy(
                        space = 24.dp, // Gap between kids = 24 dp
                        alignment = Alignment.CenterVertically
                    )
                ) {
                    GradientBorderButtonClick(
                        colors = colors, paddingValues = paddingValues,
                        widthFraction = widthFraction
                    )
                    GradientBorderButtonRound(
                        colors = colors,
                        context = context,
                        paddingValues = paddingValues,
                        widthFraction = widthFraction
                    )
                    GradientBorderButtonDisable(
                        colors = colors,
                        widthFraction = widthFraction,
                        paddingValues = paddingValues
                    )
                }
            }
        }
    }
}

@Composable
fun GradientBorderButtonClick(colors: List<Color>, paddingValues: PaddingValues, widthFraction: Float) {

    var clickCount by remember {
        mutableStateOf(0)
    }

    // To disable ripple
    val interactionSource = remember {
        MutableInteractionSource()
    }

    Box(
        modifier = Modifier
            .fillMaxWidth(fraction = widthFraction)
            .border(
                width = 4.dp,
                brush = Brush.horizontalGradient(colors = colors),
                shape = RectangleShape
            )
            .clickable(
                interactionSource = interactionSource,
                indication = null // To disable ripple
            ) {
                clickCount++
            },
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = "Click $clickCount",
            fontSize = 26.sp,
            modifier = Modifier.padding(paddingValues),
            fontWeight = FontWeight.Medium
        )
    }
}

@Composable
fun GradientBorderButtonRound(
    colors: List<Color>,
    context: Context,
    paddingValues: PaddingValues,
    widthFraction: Float
) {
    Box(
        modifier = Modifier
            .fillMaxWidth(fraction = widthFraction)
            .border(
                width = 4.dp,
                brush = Brush.horizontalGradient(colors = colors),
                shape = RoundedCornerShape(percent = 50)
            )
            // To make the ripple round
            .clip(shape = RoundedCornerShape(percent = 50))
            .clickable {
                Toast
                    .makeText(context, "Round Button Click", Toast.LENGTH_SHORT)
                    .show()
            },
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = "Round Button",
            fontSize = 26.sp,
            modifier = Modifier.padding(paddingValues),
            fontWeight = FontWeight.Medium
        )
    }
}

@Composable
fun GradientBorderButtonDisable(
    colors: List<Color>,
    widthFraction: Float,
    paddingValues: PaddingValues,
    disabledColor: Color = Color.Gray.copy(alpha = 0.3f),
    disabledColors: List<Color> = listOf(disabledColor, disabledColor)
) {
    var enabled by remember {
        mutableStateOf(true)
    }

    Box(
        modifier = Modifier
            .fillMaxWidth(fraction = widthFraction)
            .border(
                width = 4.dp,
                brush = Brush.horizontalGradient(colors = if (enabled) colors else disabledColors),
                shape = RectangleShape
            )
            .clickable(enabled = enabled) {
                enabled = false
            },
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = if (enabled) "Disable Me" else "I'm Disabled",
            fontSize = 26.sp,
            modifier = Modifier.padding(paddingValues),
            fontWeight = FontWeight.Medium,
            color = if (enabled) Color.Black else disabledColor
        )
    }

}

Leave a Comment