Blurring content layered behind a card using Jetpack Compose on Android - 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.

Related

Why the compose canvas draw things only show at preview function but not display on the running screen

Descript
I want to draw a line at the compose with the compose canvas inside a compose widget,but it's just show at the preview!
If just copy the canvas part code,it can Correct display!
The compose code
Card(
elevation = 6.dp,
shape = RoundedCornerShape(15.dp),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 12.dp, vertical = 8.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(color = backgroundColor),
) {
AsyncImage(modifier = Modifier
.height(180.dp)
.width(120.dp)
.padding(12.dp)
... )
Row(
modifier = Modifier.fillMaxSize()
) {
Column(
modifier = Modifier
.fillMaxHeight()
.weight(0.7f)
) {
...
}
Canvas(
modifier = Modifier
.weight(0.3f)
.fillMaxHeight()
.padding(start = 6.dp)
) {
// NOT SHOW !!!
drawLine(
color = Color.White,
start = Offset(0f, 0f),
end = Offset(0f, size.height),
strokeWidth = 2f,
pathEffect = PathEffect.dashPathEffect(floatArrayOf(20f, 20f), 0f),
)
}
}
}
}
SceenShot
It might be an issue related to size of Canvas. Check if it doesn't return width or height zero in your Composable.
In Jetpack Compose Canvas is nothing other than Spacer with Modifier.drawBehind{}
#Composable
fun Canvas(modifier: Modifier, onDraw: DrawScope.() -> Unit) =
Spacer(modifier.drawBehind(onDraw))
Which you can use Modifier.drawWithContent{} on your own Composable instead using Box and Canvas Composabble
you can use Modifier.drawWithContent for instance such as
Column {
val drawModifier = Modifier
.drawWithContent {
drawContent()
drawLine(
color = Color.White,
start = Offset(size.width*.8f, 0f),
end = Offset(size.width*.8f, size.height),
strokeWidth = 2f,
pathEffect = PathEffect.dashPathEffect(floatArrayOf(20f, 20f), 0f),
)
}
.width(200.dp)
.height(100.dp)
Box(modifier = drawModifier.background(Color.Red)) {
Text("Hello World")
}
}

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
)
}
}

Compose rounded Button with transparent background

I am trying to display a Button with rounded corners and a 50% transparent background. My current attempt looks like this:
MaterialTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = Color.Yellow
) {
Column(modifier = Modifier.padding(10.dp)) {
Button(
modifier = Modifier
.clip(CircleShape),
onClick = { },
colors = ButtonDefaults.buttonColors(backgroundColor = Color.White.copy(alpha = 0.5f))
) {
Text(
text = "My Button",
textAlign = TextAlign.Center
)
}
}
}
}
The result is not very pretty:
It looks like the issue is with with the shading, but I'm not sure how to remove it and just show the same color within the whole shape.
Turns out the shadow will disappear when the elevation is removed.
Button(
modifier = Modifier
.clip(CircleShape),
onClick = { },
elevation = null,
colors = ButtonDefaults.buttonColors(backgroundColor = Color.White.copy(alpha = 0.5f))
) { ... }
Button is just a Surface wrapping the content that you provide. You could check the source. So, I just tweaked it a little
#Composable
fun HollowButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
elevation: ButtonElevation? = ButtonDefaults.elevation(),
shape: Shape = MaterialTheme.shapes.small,
border: BorderStroke? = null,
colors: ButtonColors = ButtonDefaults.buttonColors(),
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
content: #Composable RowScope.() -> Unit
) {
val contentColor by colors.contentColor(enabled)
Surface(
modifier = modifier,
shape = shape,
color = colors.backgroundColor(enabled).value.copy(0.5f), //Basically I refactored the alpha modification to here
contentColor = contentColor.copy(alpha = 1f),
border = border,
elevation = elevation?.elevation(enabled, interactionSource)?.value ?: 0.dp,
onClick = onClick,
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
indication = rememberRipple()
) {
CompositionLocalProvider(LocalContentAlpha provides contentColor.alpha) {
ProvideTextStyle(
value = MaterialTheme.typography.button
) {
Row(
Modifier
.defaultMinSize(
minWidth = ButtonDefaults.MinWidth,
minHeight = ButtonDefaults.MinHeight
)
.padding(contentPadding),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content
)
}
}
}
}
Works like a charm.

Why jetpack compose elevation clip my shadow?

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

Jetpack compose ui : How to create cardview?

I want to create Cardview using jetpack compose but i am not able to find any
example.
You can use something like:
Card(
shape = RoundedCornerShape(8.dp),
backgroundColor = MaterialTheme.colors.surface,
) {
Column(
modifier = Modifier.height(200.dp).padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
){
Text(text = "This is a card view",
style = MaterialTheme.typography.h4)
}
}
With Material3 you can use:
Card(
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = /* ... */)
)
in v0.1.0-dev09 version, can be done like this, where the padding of Card sets the margin of the card, the padding of Box sets the padding inside the card.
Card(
shape = RoundedCornerShape(8.dp),
modifier = Modifier.padding(16.dp).fillMaxWidth()
) {
Box(modifier = Modifier.height(200.dp).padding(16.dp)) {
Text("This is a card view")
}
}
As the friends recommended, Card is a way of creating CardView but you can do that by surface too :
val shape = RoundedCornerShape(10.dp)
Surface(modifier = Modifier.size(250.dp, 70.dp), elevation = 8.dp, shape = shape) {
Text(text = "Sample text")
}
Note that Surface and Card cannot be used for positioning items so that if you wanna position that Text(text = "Sample text") , you should use one layout inside that Surface like this :
val shape = RoundedCornerShape(10.dp)
Surface(modifier = Modifier.size(250.dp, 70.dp), elevation = 8.dp, shape = shape) {
Box(modifier = Modifier.fillMaxSize()) {
Text(modifier = Modifier.align(Alignment.Center), text = "Sample text")
}
}
The appropriate way for creating CardView is this but if you wanna just create shadow for a view, you can use Modifier.shadow (Note that Modifier.shadow and Surface/Card are not the same):
Box(modifier = Modifier.size(250.dp, 70.dp).shadow(8.dp, RoundedCornerShape(10.dp)), contentAlignment = Alignment.Center) {
Text(text = "Sample Text")
}
Code:
class ImageCardActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val painter = painterResource(id = R.drawable.grogu)
val contentDescription = "Grogu says hi"
val title = "Force is strong with Grogu"
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier.fillMaxWidth(0.5f)
) {
ImageCard(
title = title,
contentDescription = contentDescription,
painter = painter
)
}
}
}
}
}
#Composable
fun ImageCard(
title: String,
contentDescription:String,
painter: Painter,
modifier:Modifier=Modifier
){
Card(
modifier = modifier.fillMaxWidth(),
shape = RoundedCornerShape(18.dp),
elevation = 5.dp
) {
Box(
modifier = Modifier.height(200.dp)
) {
// Image
Image(
painter = painter,
contentDescription = contentDescription,
contentScale = ContentScale.Crop
)
// Gradient
Box(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent, Color.Black
),
startY = 300f
)
)
)
// Title
Box(
modifier = Modifier
.fillMaxSize()
.padding(12.dp),
contentAlignment = Alignment.BottomStart
) {
Text(
text = title,
style = TextStyle(color = Color.White, fontSize = 12.sp)
)
}
}
}
}

Categories

Resources