How to apply translucent gradient on an Image in Android Jetpack Compose? - android

In Android Jetpack Compose, does anyone knows how to make an Image's left side slowly fading to transparent towards right side? Thanks!
Edit:
Sorry, I mean making an image fading like this in Compose, probably with blend mode? But not sure how to do that..
Expected outcome:

Just found an answer from How to add fading edge effect to Android Jetpack Compose Column or Row?
"Color.Black" means area that reveal the image.
Thanks guys!
Image(
painterResource(R.drawable.cat),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
// Workaround to enable alpha compositing
.graphicsLayer { alpha = 0.99f }
.drawWithContent {
val colors = listOf(
Color.Black,
Color.Transparent
)
drawContent()
drawRect(
brush = Brush.horizontalGradient(colors),
blendMode = BlendMode.DstIn
)
}
)

You could place a Box over the image and add a background gradient to the Box. You will have to set the size of the Box though to be the same as the image. In this example I don't bother setting the Box size correctly. I'll leave that up to you:
Here's the image I used:
https://adelaidevet.com.au/sites/default/files/archive/files/images/cat-ginger-eyes-closed_0.jpg
val screenWidth = LocalConfiguration.current.screenWidthDp
Box(modifier = Modifier.fillMaxWidth().wrapContentHeight()) {
Image(
painterResource(R.drawable.cat),
contentDescription = "",
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth()
)
Box(
modifier = Modifier
.requiredWidth(screenWidth.dp)
.requiredHeight(310.dp)
.background(
brush = Brush.horizontalGradient(
startX = 0f,
endX = 700f,
colors = listOf(
Color.Transparent,
Color(0xD7525252),
)
)
)
) {
}
}

Related

Change Circle shape of Thumb in Slider Jetpack compose

The Slider in Jetpack Compose allows changing the color of the thumb but not the shape.
I'm looking solution to change the shape of the thumb from circle to rectangle as represented in the attached image
I tried to add Slider.kt file to the project as mentioned here but, strangely, when I copy this code to the project I got a lot of errors, see attached screenshot
With M3 androidx.compose.material3.Slider you can use the thumb attribute to use a custom thumb.
You can use a simple Spacer or a Box to obtain a Rectangle:
var sliderPosition by remember { mutableStateOf(0f) }
val interactionSource = MutableInteractionSource()
Column {
Text(text = sliderPosition.toString())
Slider(
modifier = Modifier.semantics { contentDescription = "Localized Description" },
value = sliderPosition,
onValueChange = { sliderPosition = it },
valueRange = 0f..5f,
steps = 4,
interactionSource = interactionSource,
onValueChangeFinished = {
// launch some business logic update with the state you hold
},
thumb = {
val shape = RectangleShape
Spacer(
modifier = Modifier
.size(20.dp)
.indication(
interactionSource = interactionSource,
indication = rememberRipple(
bounded = false,
radius = 20.dp
)
)
.hoverable(interactionSource = interactionSource)
.shadow(if (enabled) 6.dp else 0.dp, shape, clip = false)
.background(Red, shape)
)
},
)
}
Note: it requires for material3 at least the version 1.0.0-beta03
Here is a source code for Slider composable.
You can copy it to your project, rename, and change the Thumb shape in the SliderThumb composable:
...
.shadow(if (enabled) elevation else 0.dp, CircleShape, clip = false)
.background(colors.thumbColor(enabled).value, CircleShape)
...

Compose: Create Text with Circle Background

Coming from SwiftUI, I wanted to create a view of a Text where it has a background of a Circle, where the circle's width/height grow as the text inside Text gets longer.
Since there's no Circle() in Compose like there is in SwifUI, I created just a Spacer instead and clipped it. The code below is using ConstraintLayout because I don't know how I would get the width of the Text in order to set the size of my Circle composable to be the same:
#Composable
fun CircleDemo() {
ConstraintLayout {
val (circle, text) = createRefs()
Spacer(
modifier = Modifier
.background(Color.Black)
.constrainAs(circle) {
centerTo(text)
}
)
Text(
text = "Hello",
color = Color.White,
modifier = Modifier
.constrainAs(text) {
centerTo(parent)
}
)
}
}
I can use a mutableStateOf { 0 } where I update that in an onGloballyPositioned modifier attached to the Text and then set that as the requiredSize for the Spacer, but 1. that seems stupid and 2. the Spacer now draws outside the boundaries of the ConstraintLayout.
Visually I want to achieve this:
How would I go about doing this? Thank you :)
It is also possible to use drawBehind from the modifier of the textView itself such as below:
Text(
modifier = Modifier
.padding(16.dp)
.drawBehind {
drawCircle(
color = red,
radius = this.size.maxDimension
)
},
text = "Hello",
)
of course, you can further customize the radius and other properties as you wish!
You have to calculate the dimension of the background circle depending on the dimension of the text.
You can use a custom modifier based on Modifier.layout:
fun Modifier.circleLayout() =
layout { measurable, constraints ->
// Measure the composable
val placeable = measurable.measure(constraints)
//get the current max dimension to assign width=height
val currentHeight = placeable.height
val currentWidth = placeable.width
val newDiameter = maxOf(currentHeight, currentWidth)
//assign the dimension and the center position
layout(newDiameter, newDiameter) {
// Where the composable gets placed
placeable.placeRelative((newDiameter-currentWidth)/2, (newDiameter-currentHeight)/2)
}
}
Then just just apply it the Text with a background with a CircleShape:
Text(
text = "Hello World",
textAlign = TextAlign.Center,
color = Color.White,
modifier = Modifier
.background(Color.Black, shape = CircleShape)
.circleLayout()
.padding(8.dp)
)
#Composable
fun Avatar(color: Color) {
Box(
modifier = Modifier
.size(size.Dp)
.clip(CircleShape)
.background(color = color),
contentAlignment = Alignment.Center
) {
Text(text = "Hello World")
}
}
Use a background drawable of a black circle inside a transparent color. The background drawable will stretch to fill the view, and circles should stretch well without artifacting.

How to make a surface background half transparent in jetpack compose, but not the content?

I want to achieve this layout:
In XML I would add an image in a relative layout with match_parent attributes, then a view with a black half-transparent background set to match_parent as well, then the content.
In compose I made this composeable:
#Composable
fun ImageCover(resourceId: Int, alpha: Float = 0.5f, content: #Composable () -> Unit) {
Box(modifier = Modifier.fillMaxSize()) {
Image(
painter = painterResource(id = resourceId),
contentDescription = null,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop
)
Surface(
color = Color.Black, modifier = Modifier
.fillMaxSize()
.alpha(alpha)
) {
content()
}
}
}
But the problem is alpha is applied to the surface and its content. So no matter what I put in the content, even if it's another surface with a background, will also be half transparent. Here, for example, the two sentences and two components at the bottom will be half transparent as well.
The background color of the Surface is based on the color attribute.
Apply the alpha to the color property instead of the Modifier.
Something like:
Surface(
color = Color.Black.copy(alpha = 0.6f),
modifier = Modifier.fillMaxSize()
){
//....
}

How to draw a circular image in Android Jetpack Compose?

Let's say I have a rectangular avatar image like the one below, how can I force it to be drawn as a circle in Jetpack Compose?
There's a clip modifier which can be applied to any composable as well as the Image, just pass a CircleShape into it:
Image(
painter = painterResource(R.drawable.sample_avatar),
contentDescription = "avatar",
contentScale = ContentScale.Crop, // crop the image if it's not a square
modifier = Modifier
.size(64.dp)
.clip(CircleShape) // clip to the circle shape
.border(2.dp, Color.Gray, CircleShape) // add a border (optional)
)
You can use any other shape to clip the image, for example CircleShape it's just RoundedCornerShape(percent = 50). Let's try RoundedCornerShape(percent = 10):
Also, you may try a
implementation "com.github.skydoves:landscapist-glide:1.3.6"
By using Modifier.clip(CircleShape)
GlideImage(
modifier = Modifier
.width(50.dp)
.height(50.dp)
.clip(CircleShape)
.clickable(enabled = true, onClick = onClick),
imageModel = "https://avatars.githubusercontent.com/u/27887884?v=4",
// Crop, Fit, Inside, FillHeight, FillWidth, None
contentScale = ContentScale.Crop,
// shows an image with a circular revealed animation.
circularReveal = CircularReveal(duration = 250),
// shows a placeholder ImageBitmap when loading.
placeHolder = ImageBitmap.imageResource(R.drawable.avater),
// shows an error ImageBitmap when the request failed.
error = ImageBitmap.imageResource(id = R.drawable.avater)
)
For more components visit LandScapist
For those who wonder how to make an image squared (or round) without explicitly setting its sizes, there is Modifier.aspectRatio(1f)
We can achieve this using the background field in a modifier.
Image(
painter = painterResource(id = R.drawable.ic_arrow_right),
contentDescription = "",
modifier = Modifier
.padding(4.dp, 4.dp).background(colorResource(id = R.color.greenColor), CircleShape)
.clip(CircleShape),
colorFilter = ColorFilter.tint(colorResource(id = R.color.white)),
contentScale = ContentScale.Crop,
)

How to show a rectangular image in Circle view?

I am trying to show a rectangle image with android compose in a circle shape but the edges don't stretch to fill the whole.
In other words I don't want the black background shown in the image below to appear and the flag to stretch to cover it even if I have to crop from the vertical edges
The code used to produce the image
Image(
imageVector = vectorResource(id = R.drawable.flag_cn),
modifier = Modifier.matchParentSize().clip(CircleShape)
.background(shape = CircleShape, color = Color.Black))
Update: I tried to set the content scale option in Image Compose to crop
Image(
imageVector = vectorResource(id = flagID),
modifier = Modifier
.fillMaxSize(0.4f)
.background(shape = CircleShape, color = Color.Black)
.align(Alignment.BottomEnd)
.clip(CircleShape),
contentScale = ContentScale.Crop
)
Maybe something like this?
val imageVector = vectorResource(id = R.drawable.flag_cn)
Surface(
modifier = Modifier.preferredSize(200.dp),
shape = CircleShape,
) {
Image(imageVector, modifier = Modifier.size(300.dp))
}
You can use scale type option available for scaling the bounds of an image to the bounds of its view. This option is available for ImageView.
You can choose
android:scaleType="centerCrop"
Reference:
ImageView ScaleType
Apply the clip Modifier using a CircleShape:
Image(
painter = painterResource(R.drawable.xxx),
contentDescription = "xxxx",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(64.dp)
.clip(CircleShape)
)

Categories

Resources