Shimmering is present in almost all applications that have networking. When the task of making it on compose came up, given that the latter simplifies the work with the view, I did not find a solution. All options were reduced to downloading fairly heavy libraries or writing a lot of code. However, I managed to find a solution, which allows me to make a shimmering on compose in a few lines of code.
I am first attaching the full code of the ShimmeringActivity. You can copy it into your project and run it:
As a result, you should have the following animation:
Don't be intimidated by the orange and blue shimmering colors. I did this on purpose so that they would be easily distinguishable. The color can be changed to white, as it should be in your project.
Let's go through the code. Let's start with an easy one:
ShimmeringCompose(
modifier = Modifier
.width(300.dp)
.height(150.dp),
cornerRadius = 16.dp
)
width, height, cornerRadius - the width, height and radius of the circle, as in any other compose view.
val screenWidth = LocalConfiguration.current.screenWidthDp.dp
screenWidth - the found screen width. This is necessary to make the animation for all elements work synchronously. Otherwise, if there are several rectangles with different widths on the same screen, the shimmering for them will be out of sync, because the animation will run different distances at the same time.
val translateAnim by rememberInfiniteTransition().animateFloat(
initialValue = 0f,
targetValue = screenWidth.px,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 1500, easing = FastOutSlowInEasing)
)
)
rememberInfiniteTransition().animateFloat(), infiniteRepeatable() - methods for creating infinite animation.
initialValue, targetValue - start and end value of the animation.
tween() - method for configuring the animation.
durationMillis - animation time.
easing - interpolation of the animation.
The value of translateAnim will change over time from initialValue to targetValue. The translateAnim change logs:
D: ShimmeringCompose: 1.2176096
D: ShimmeringCompose: 2.7215502
D: ShimmeringCompose: 7.4594655
D: ShimmeringCompose: 11.377052
D: ShimmeringCompose: 21.533459
D: ShimmeringCompose: 27.730642
D: ShimmeringCompose: 34.646053
D: ShimmeringCompose: 53.458187
D: ShimmeringCompose: 64.20549
D: ShimmeringCompose: 91.909676
D: ShimmeringCompose: 107.303856
val shimmerColorShades = listOf(Color(0xFFF37F19), Color(0xFF007CFF), Color(0xFFF37F19))
With this list the colors are set: blue in the center and orange on the edges.
val brush = Brush.linearGradient(
colors = shimmerColorShades,
start = Offset(translateAnim, translateAnim),
end = Offset(translateAnim + 70.dp.px, translateAnim + 35.dp.px)
)
Brush.linearGradient() is a method for creating a gradient.
In colors we assign the sheet of colors created above.
Offset() is a shell class for assigning x and y coordinates
The values 70 and 35 are chosen depending on the shimmering design in Figma.
Box(modifier = modifier.background(brush = brush, shape = RoundedCornerShape(cornerRadius)))
Create a Box object and assign to it in background() the values of brush and RoundedCornerShape to create rounded corners.
You will also need a utility method to translate dp to px:
val Dp.px: Float
@Composable
get() = with(LocalDensity.current) { [email protected]() }
As a result, we get animation, as in the gif-picture at the beginning of the article.
To understand how Brush.linearGradient() works, change the code in the ShimmeringActivity to the following:
val brush = Brush.linearGradient(
colors = shimmerColorShades,
start = Offset(0f, 0f),
end = Offset(0f, 100f)
)
You will end up with the following picture:
If you set x_start = x_end, the shimmer bar will be parallel to the x-axis. The thickness will be y_end - y_start, in this case 100f. Now insert the following code:
val brush = Brush.linearGradient(
colors = shimmerColorShades,
start = Offset(0f, 0f),
end = Offset(100f, 0f)
)
You will get this picture:
If you set the y_start = y_end coordinates, the shimmer bar will be parallel to the y-axis. The thickness will be x_end - x_start, in this case 100f.
Thus, by manipulating the start and end coordinates, you can achieve the desired result.
As you can see, creating shimmering took about 25 lines of code, not including the ShimmeringActivity code and the utility method for translating to px. From my point of view, pulling in an additional library to create the shimmering makes no sense. Yes, my example isn't exactly clean from a code point of view: some variables aren't moved here and critical situations aren't handled. But it can be easily modified to the needs of your project.