Why jetpack compose elevation clip my shadow? - android

I have a problem with jetpack compose elevation render. I'm trying to add elevation on Surface but my UI seems to with clipped shadow. Also, how can I add a colorful shadow on my Surface?
See the below on the screenshot
#Composable
fun DiscoverItem() {
Surface(
contentColor = Color(0xFFFFFFFF),
modifier = Modifier.preferredWidthIn(min = 145.dp).preferredHeight(56.dp),
shape = CircleShape,
elevation = 8.dp,
) {
Row(
modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Surface(
modifier = Modifier.preferredSize(40.dp),
shape = CircleShape,
color = Color(0xFFFFC3D8)
) {
Image(
imageResource(R.drawable.pin_icon),
modifier = Modifier.size(width = 18.dp, height = 24.dp),
contentScale = ContentScale.Fit
)
}
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(
"YOUR AREA",
style = MaterialTheme.typography.body2,
color = Color(0xFFFC1055)
)
}
}
}
#Composable
#Preview
fun DiscoverItemPreview() {
DiscoverItem()
}

You don't have enough content on bottom of your layout. You can add spacer to view your shadow.
#Composable
#Preview
fun DiscoverItemPreview() {
Column{
DiscoverItem()
Spacer(modifier = Modifier.height(20.dp))
}
}
And about colorful shadow, compose min sdk is Android Lollpop and skia version for lollipop doesnot supports colorful shadow/elevation. Leland Richardson had talked about this issue in his youtube video on Compose dogfooding. here

I use surface to wrap the shadowed card and it gives me expected result.
Surface(
elevation = 4.dp,
color = MaterialTheme.colors.surface,
shape = Shapes.medium,
) {
Card(
modifier = Modifier
.fillMaxWidth()
.animateContentSize(
animationSpec = tween(
durationMillis = 300,
easing = LinearOutSlowInEasing
)
),
elevation = 8.dp,
shape = Shapes.medium,
onClick = {
isExpanded = !isExpanded
}
) {}}
enter image description here

Related

Jetpack compose: elevate card from bottom

I was implementing Card shape in Jetpack Compose while I ran into this problem.
What I wanted was to only elevate one end or bottom of the card but I didn't find any relevant documents supporting that.
I tried looking into the implementation code of Card to get an idea (following is the code of the implementation):
#Composable
fun Surface(
modifier: Modifier = Modifier,
shape: Shape = RectangleShape,
color: Color = MaterialTheme.colors.surface,
contentColor: Color = contentColorFor(color),
border: BorderStroke? = null,
elevation: Dp = 0.dp,
content: #Composable () -> Unit
) {
Surface(
modifier = modifier,
shape = shape,
color = color,
contentColor = contentColor,
border = border,
elevation = elevation,
content = content,
clickAndSemanticsModifier = Modifier
.semantics(mergeDescendants = false) {}
.pointerInput(Unit) { }
)
}
but here it is accepting elevation in Dp, which means it with elevate the whole Card.
So I don't know how to implement it in Jetpack Compose, can someone help me with the implementation?
Edit:
I created an issue for this question: https://issuetracker.google.com/issues/227767373
You can elevate just the whole bottom like this
#Composable
fun BottomWithShadow(
content: #Composable ColumnScope.() -> Unit
) {
Box {
Card(
shape = RoundedCornerShape(
topEnd = 0.dp,
topStart = 0.dp,
bottomEnd = 0.dp,
bottomStart = 0.dp),
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.align(Alignment.BottomCenter),
elevation = 10.dp
) {}
Column(
modifier = Modifier
.clip(
RoundedCornerShape(
topEnd = 0.dp,
topStart = 0.dp,
bottomEnd = 0.dp,
bottomStart = 0.dp)
)
.background(color = Color.White),
content = content
)
}
}

Blurring content layered behind a card using Jetpack Compose on Android

I am trying to achieve the blur effect like highlighted in this post:
I'm using Jetpack Compose:
#Composable
fun MainApp() {
val linearGradientBrush = Brush.linearGradient(
colors = listOf(
Color(0xFF5995EE),
Color(0xFFB226E1),
Color(0xFFE28548)
),
start = Offset(Float.POSITIVE_INFINITY, 0f),
end = Offset(0f, Float.POSITIVE_INFINITY),
)
val transparentGradientBrush = Brush.linearGradient(
colors = listOf(
Color(0x66FFFFFF),
Color(0x1AFFFFFF)
)
)
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Box() {
Card(
modifier = Modifier
.size(150.dp)
// .blur(10.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded)
.clip(shape = CircleShape)
.background(linearGradientBrush),
backgroundColor = Color.Transparent,
elevation = 0.dp,
) {
}
Card(
modifier = Modifier
.size(150.dp)
.offset(x = -75.dp, y = 40.dp)
.blur(5.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded)
.clip(RoundedCornerShape(30.dp))
.background(transparentGradientBrush),
backgroundColor = Color.Transparent,
elevation = 0.dp
) {
}
}
}
}
However, the output I get is this:
How do I achieve the effect from the tweet above the layer in front also blurs the layer behind? Is there a way to achieve this?
https://github.com/x3rocode/xblur-compose/tree/main
I made simple realtime compose blur!
try this.

No ripple effect in Jetpack Compose

There is no ripple effect when I click on MyBox() I've added MyTheme(){} to main #Composable screen but it doesn't work. Is something missing?
#Composable
private MyBox(onClickInvoked: () -> Unit) {
MyAppTheme(isSystemInDarkTheme()) {
Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.clip(RoundedCornerShape(10.dp))
.background(MaterialTheme.colors.onBackground)
.clickable(onClick = { onClickInvoked.invoke() })
.padding(horizontal = 10.dp, vertical = 15.dp)
) {
Text(
text = "My text",
modifier = Modifier
.align(Alignment.CenterStart)
.padding(end = 95.dp)
.wrapContentWidth()
.wrapContentHeight(),
color = MaterialTheme.colors.primary
)
Image(
painter = painterResource(R.drawable.icon),
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 20.dp)
.size(60.dp)
)
}
}
}
With compose 1.0.5, I see the default indication after set clickable is
LocalIndication.current. And LocalIndication.current is PlatformRipple. Therefore, after you set clickable to your Box, it will have ripple effect.
In your case, I think the ripple effect won't display because your Box background is too dark (normally MaterialTheme.colors.onBackground is black on Light theme)
I think you can change the ripple effect color to make it easy to see.
Surface(
onClick = { onClickInvoked.invoke() },
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(10.dp),
color = MaterialTheme.colors.onBackground, // normally it is black on Light theme
indication = rememberRipple(color = Color.White) // color for your ripple, you can use other suitable MaterialTheme.colors for your case to support Light/Dark mode
) {
Box(modifier = Modifier.padding(horizontal = 10.dp, vertical = 15.dp)) {
// your Box content
...
}
}
There is a Modifier.indication but after testing I see it not working with Modifier.clickable so I use Surface
I don't really know if there is a problem with your theme. I try to pass the material theme, and the ripples will display normally
MaterialTheme() {
Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.clip(RoundedCornerShape(10.dp))
.background(MaterialTheme.colors.secondary)
.clickable(onClick = { t = "My text" })
.padding(horizontal = 10.dp, vertical = 15.dp)
) {
Text(
text = t,
modifier = Modifier
.align(Alignment.CenterStart)
.padding(end = 95.dp)
.wrapContentWidth()
.wrapContentHeight(),
color = MaterialTheme.colors.primary
)
Image(
painter = painterResource(R.drawable.ic_launcher_foreground),
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 20.dp)
.size(60.dp),
contentDescription = ""
)
}
}

Gradient backround for FAB in Jetpack compose

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.

Android compose Card has a border when semi-transparent colors used

Android Jetpack compose Card draws a border around the card when background color has some transparency. This is how it looks in AS:
But this is how it looks in the app:
If I set background to a solid color it works, but by default backgroundColor is a surface color from material (in my app val white850 = Color(0xD9FFFFFF)) and it looks like on the picture above.
#Composable
fun TraitCard(trait: Trait) {
Card(
shape = MaterialTheme.shapes.small,
modifier = Modifier.size(width = 192.dp, height = 56.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start
) {
Icon(
imageVector = Icons.Rounded.ChildFriendly,
contentDescription = "",
modifier = Modifier
.fillMaxHeight()
.background(color = MaterialTheme.colors.background)
.aspectRatio(1f)
.padding(8.dp),
tint = MaterialTheme.colors.onBackground
)
Text(
text = trait.name,
style = MaterialTheme.typography.h3,
modifier = Modifier.padding(horizontal = 16.dp),
)
}
}
}
Does anyone have a clue why it's happening?
This is because of the elevation that Card has by default (and how shadows are drawn), if you remove the elevation this won't happen.
You can try to convert the semitransparent color to the non transparent one with something like:
backgroundColor = Color(0xD9FFFFFF).compositeOver(Color.White),

Categories

Resources