I am working on ripple effect in jetpack compose. I provide my color and after clicking on view it show some time after that different type of color showing like dark grey on press state.
binding.itemComposable.setContent {
Column(modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(12.dp)) {
val options = getOptions()
options.forEachIndexed { _, optionText ->
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
val backgroundColor = if (isPressed) DuckEggBlue else OffWhite
val textColor = if (isPressed) TealBlue else Slate
val borderWidth = if (isPressed) 1.dp else 0.dp
val borderColor = if (isPressed) Aqua else OffWhite
Surface(
onClick = {
logE("Item Click")
},
shape = RoundedCornerShape(4.dp),
border = BorderStroke(borderWidth, borderColor),
interactionSource = interactionSource
) {
Text(
modifier = Modifier
.fillMaxWidth()
.background(backgroundColor)
.padding(16.dp),
text = optionText,
style = Typography.h3,
fontWeight = FontWeight.Medium,
color = textColor
)
}
}
}
}
Expected Output
Above image is see clearly ripple effect.
Actual output
I cannot add image, instead i added my youtube video. Please have a look.
val DuckEggBlue = Color(0xFFF0FCFC)
This is my color which I am using.
Can anyone guide me what is wrong here.
UPDATE
I tried from this doc
#Immutable
private object SecondaryRippleTheme : RippleTheme {
#Composable
override fun defaultColor() = RippleTheme.defaultRippleColor(
contentColor = DuckEggBlue,
lightTheme = true
)
#Composable
override fun rippleAlpha() = RippleTheme.defaultRippleAlpha(
contentColor = DuckEggBlue,
lightTheme = true
)
}
In my code
CompositionLocalProvider(LocalRippleTheme provides SecondaryRippleTheme) {
Text(
modifier = Modifier
.fillMaxWidth()
.background(OffWhite)
.padding(16.dp),
text = optionText,
style = Typography.h3,
fontWeight = FontWeight.Medium,
color = textColor
)
}
but nothing works. It still grey ripple effect.
I tried many options Box, Surface, using PointerInput to delay but maybe visually it doesn't work when you change background color with same ripple
Surface(
modifier = Modifier
.indication(
interactionSource = interactionSource,
rememberRipple(
color = Color.Cyan
)
)
,
shape = RoundedCornerShape(4.dp),
contentColor = backgroundColor,
border = BorderStroke(borderWidth, borderColor),
onClick = {},
interactionSource = interactionSource
) {
Text(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
text = optionText,
fontWeight = FontWeight.Medium,
color = textColor
)
}
With Color.Cyan
If you don't change color when pressed ripple is more apparent but your color is too light to apply for ripple as i tested with other colors.
with PointerInput I tried by changing is pressed to Boolean with initial false value
Modifier.pointerInput(Unit) {
detectTapGestures(onPress = { offset ->
isPressed = true
val press = PressInteraction.Press(offset)
// delay(50)
interactionSource.emit(press)
tryAwaitRelease()
interactionSource.emit(PressInteraction.Release(press))
isPressed = false
})
}
Related
How to set Background Color for Material3 Card in Android Compose?
Piggy backing fro this question. The answers tells how to set a background color.
When material3 card is pressed, it changes color with a ripple effect.
But how can I change the effect color when it is pressed?
CardDefaults.cardColors(....) doesn't do it
The Card with the onClick variant uses internally an indication = rememberRipple(). This creates and remembers a Ripple using values provided by RippleTheme.
You can provide a custom LocalRippleTheme to override the default behaviour:
CompositionLocalProvider(LocalRippleTheme provides GreenRippleTheme) {
Card(
onClick = { /* Do something */ },
modifier = Modifier.size(width = 180.dp, height = 100.dp)
) {
//Card content
}
}
with:
private object GreenRippleTheme : RippleTheme {
#Composable
override fun defaultColor() = Color.Green
#Composable
override fun rippleAlpha(): RippleAlpha = RippleTheme.defaultRippleAlpha(
Color.Green,
lightTheme = true
)
}
Otherwise you can use the clickable modifier:
val interactionSource = remember { MutableInteractionSource() }
Card(
modifier = Modifier
.size(width = 180.dp, height = 100.dp)
.clickable (
onClick = { /* Do something */ },
interactionSource = interactionSource,
indication = rememberRipple(color = Green )
)
) {
//Card content
}
Finally if you want to modify the background color when the Card is pressed (not the ripple effect) you can use:
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
val backgroundColor = if (isPressed) Yellow else MaterialTheme.colorScheme.surfaceVariant
Card(
interactionSource = interactionSource,
onClick = { /* Do something */ },
modifier = Modifier
.size(width = 180.dp, height = 100.dp),
colors = CardDefaults.cardColors(
containerColor = backgroundColor
)
) {
//Card content
}
You can use the "onClick" property of the Card component to change the color when it is pressed. To do this, you can define a state variable to track the current color of the card and toggle it on click. For example:
var cardColor by remember { mutableStateOf(Color.White) }
Card(
color = cardColor,
onClick = {
cardColor = if (cardColor == Color.White) Color.Green else Color.White
}
...
)
Alternatively, you can define the ripple color in the Modifier property of the Card component. For example:
Card(
color = Color.White,
modifier = Modifier.clickable(onClick = {
// logic to change color
}).ripple(color = Color.Green),
...
)
Hey guys I am using RoundedCornerShape(4.dp) to my Surface which looks fine. When I tried to click on the item it not showing me 4dp corner in Surface. I tried this stack overflow 1 and stack overflow 2 but nothing works.
binding.itemComposable.setContent {
Column(modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(12.dp)) {
val options = getOptions()
options.forEachIndexed { _, optionText ->
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
val backgroundColor = if (isPressed) DuckEggBlue else OffWhite
val textColor = if (isPressed) TealBlue else Slate
val borderWidth = if (isPressed) 1.dp else 0.dp
val borderColor = if (isPressed) Aqua else OffWhite
val clickable = Modifier.clickable(
interactionSource = interactionSource,
indication = rememberRipple(true)
) {
println("Item Click")
}
Surface(
modifier = Modifier
.then(clickable)
.border(borderWidth, borderColor),
shape = RoundedCornerShape(4.dp)
) {
Text(
modifier = Modifier
.fillMaxWidth()
.background(backgroundColor)
.padding(16.dp),
text = optionText,
style = Typography.h3,
fontWeight = FontWeight.Medium,
color = textColor
)
}
}
}
}
Without click on item corner is 4 dp
When I click it's not changing corner
If you want to handle the click on a Surface you have to use the function that accepts an onClick():
Surface(
onClick = {},
shape = RoundedCornerShape(4.dp),
border = BorderStroke(borderWidth,borderColor),
interactionSource = interactionSource
)
Create a variable for shape
val shape = RoundedCornerShape(4.dp)
Use it in Modifier.clip() and Modifier.border() like this,
Surface(
modifier = Modifier
.clip(shape)
.border(
width = borderWidth,
color = borderColor,
shape = shape,
)
.then(clickable),
// shape = shape,
)
shape in border() specifies the shape of the border which by default is RectangleShape. Hence, you are seeing the rectangle border.
shape in clip() changes the shape of the composable before the click action is added. This is to make the ripple effect appear only on the given shape.
Note: Order of modifiers are important.
The shape in the Surface may not be needed after these changes.
If youre using Surface to wrapping the content, try to add a container inside the content for example Box or Column. Then use your Surface only as a shape mask, the background and other content will be flexible as you want.
This is the example
Surface(
modifier = Modifier
.then(clickable)
.border(borderWidth, borderColor),
shape = RoundedCornerShape(4.dp)
) {
Box(modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.background(Color.Green)){
Text(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
text = optionText,
style = Typography.h3,
fontWeight = FontWeight.Medium,
color = textColor
)
}
}
I am currently trying to make it so that when the user has clicked the chip it still retains it's initial form/shape, in this case round. How can I achieve this?
This is how it operates currently: https://gyazo.com/bdbe867adb5c9e75381f7ac923134709
The Chip code:
#Composable
fun TextChip(
isSelected: Boolean,
text: String,
onChecked: (Boolean) -> Unit,
selectedColor: Color = DarkGray,
shape: Shapes,
) {
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.wrapContentSize()
.border(
width = 1.dp,
color = if (isSelected) selectedColor else LightGray,
shape = RoundedCornerShape(20.dp)
)
.background(
color = if (isSelected) selectedColor else Transparent,
)
.clickable {
onChecked(!isSelected)
}
.padding(top = 3.dp, bottom = 3.dp, start = 17.dp, end = 17.dp)
) {
Text(
text = text,
fontSize = 21.sp,
fontWeight = FontWeight.Bold,
color = if (isSelected) Color.White else Unspecified, // Text inside, when clicked, gives color to the text!
)
}
}
#Composable
fun FirstChip() {
// Chip View
val textChipRememberOneState = remember { mutableStateOf(false) }
TextChip(
isSelected = textChipRememberOneState.value,
shape = Shapes(medium = RoundedCornerShape(15.dp)),
text = "Action",
selectedColor = LightGreen,
onChecked = {
textChipRememberOneState.value = it
},
)
}
You should set the shape for your Modifier.background(color, shape) but it won't clip your click ripple and it will be as in gif with a Rectangle shape. You can use Modifier.clip() to clip background and ripple as
modifier = Modifier
.wrapContentSize()
.border(
width = 1.dp,
color = if (isSelected) selectedColor else LightGray,
shape = RoundedCornerShape(20.dp)
)
.clip(RoundedCornerShape(20.dp))
.background(
color = if (isSelected) selectedColor else Transparent,
)
.clickable {
onChecked(!isSelected)
}
.padding(top = 3.dp, bottom = 3.dp, start = 17.dp, end = 17.dp)
You should use existing chip #Composable function. There are 4 chip types - Assist chip, filter chip, input chip, suggestion chip. FilterChip is best for you to use. You can simply call FilterChip function:
#Composable
fun FirstChip() {
// Chip View
val textChipRememberOneState = remember { mutableStateOf(false) }
FilterChip(
selected = textChipRememberOneState.value,
onClick = { textChipRememberOneState.value = ! textChipRememberOneState.value},
label = { Text("Action") }
)
}
I created custom button and when I apply elevation with disable state it has because of shadow some small box in middle and it looks like this. Here is also my code:
#Composable
fun PrimaryButton(
modifier: Modifier = Modifier,
enabled: Boolean = false,
text: String,
onClick: () -> Unit,
) {
Button(
onClick = onClick,
Modifier
.height(44.dp)
.shadow(
elevation = 4.dp,
shape = RoundedCornerShape(22.dp),
)
.then(modifier),
colors = ButtonDefaults.buttonColors(
backgroundColor = Style.colors.buttonPrimary,
disabledBackgroundColor = Style.colors.buttonPrimary.copy(0.4f),
),
shape = RoundedCornerShape(22.dp),
enabled = enabled,
) {
Text(
text = text,
style = Style.typography.phoenixTitle,
color = Color.White
)
}
}
fun ButtonSelectedCount(
modifier: Modifier = Modifier,
text: String,
enable: Boolean,
onClick: () -> Unit
) {
Surface(
shape = RoundedCornerShape(8.dp),
modifier = modifier,
elevation = if (enable) 9.dp else 0.dp
) {
Text(
modifier = Modifier
.fillMaxSize()
.background(color = if (enable) Color.Red else Color.Red.copy(alpha = 0.1f))
.clickable(enable) {
onClick()
}
.wrapContentHeight(),
text = text,
style = Typography.button.copy(color = Color.White),
textAlign = TextAlign.Center
)
}
}
I Think, This is what you are looking for. Wish you early success
I want to add a Floating Action Button with a gradient background in Jetpack Compose. I have the following snippet to do so:
FloatingActionButton(
onClick = {
coroutineScope.safeLaunch {
navController.navigate("AddTodoPage") {
launchSingleTop = true
}
}
},
shape = RoundedCornerShape(14.dp),
backgroundColor = Color.Transparent,
modifier = Modifier
.constrainAs(addFab) {
bottom.linkTo(parent.bottom)
end.linkTo(parent.end)
}
.offset(x = (-16).dp, y = (-24).dp)
.background(
brush = Brush.verticalGradient(
colors = BluePinkGradient()
),
shape = RoundedCornerShape(14.dp)
)
) {
Icon(
painter = painterResource(id = R.drawable.ic_add),
contentDescription = "Add icon",
tint = Color.White
)
}
fun BluePinkGradient(inverse: Boolean = false) = when (inverse) {
true -> listOf(
MutedBlue,
MutedPink
)
false -> listOf(
MutedPink,
MutedBlue
)
}
val MutedBlue = Color(0xFF26A69A)
val MutedPink = Color(0xFFEC407A)
But from the image below, the button has a "Whitish" shade on the plus icon. How can I remove that shade or a better way to set the FAB background to a gradient?
Fab Image
'"Whitish" shade on the plus icon' is the result of elevation parameter. You can zero it, but it doesn't looks like you need FAB in the first place.
As you need to custom the button that much, you can use IconButton instead:
IconButton(
onClick = {
},
modifier = Modifier
.background(
brush = Brush.verticalGradient(
colors = BluePinkGradient()
),
shape = RoundedCornerShape(14.dp)
)
) {
Icon(
painter = painterResource(id = R.drawable.ic_undo),
contentDescription = "Add icon",
tint = Color.White
)
}
FloatingActionButton is only applying some Material defaults to the content, it doesn't make it really floating, it has to be done with the container.
I have developed the following solution, which I have confirmed as working:
#OptIn(ExperimentalMaterialApi::class)
#Composable
fun CrazyFloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
gradient: List<Color>,
contentColor: Color = contentColorFor(gradient[0]),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
content: #Composable () -> Unit
) {
Surface(
modifier = modifier,
shape = shape,
contentColor = contentColor,
elevation = elevation.elevation(interactionSource).value,
onClick = onClick,
role = Role.Button,
interactionSource = interactionSource,
indication = rememberRipple()
) {
CompositionLocalProvider(LocalContentAlpha provides contentColor.alpha) {
ProvideTextStyle(MaterialTheme.typography.button) {
Box(
modifier = Modifier
.defaultMinSize(minWidth = 56.dp, minHeight = 56.dp)
.background(brush = Brush.verticalGradient(gradient)),
contentAlignment = Alignment.Center
) { content() }
}
}
}
}
Just prepend Crazy to your Composable and you should be good to go.