使用 Jetpack Compose 在 Android 中制作微光动画
先决条件:
- Kotlin 基础知识
- Jetpack Compose 基础知识
Shimmer Animation 是由 Facebook 创建的,用于在从服务器获取图像时显示加载屏幕。现在我们在很多地方看到了微光动画。在本文中,我们将看看使用全新的 Jetpack Compose 实现微光动画。下面给出了一个示例 GIF,以了解我们将在本文中做什么。
分步实施
步骤 1:创建一个新项目(或在现有 Compose 项目中使用它)
要在 Android Studio Canary 版本中创建新项目,请参阅文章如何使用 Jetpack Compose 在 Android Studio Canary 版本中创建新项目。
第 2 步:添加颜色
在开始编写动画之前,添加微光动画所需的颜色。打开Colors.kt (存在于 ui/theme/Colors.kt)
val ShimmerColorShades = listOf(
Color.LightGray.copy(0.9f),
Color.LightGray.copy(0.2f),
Color.LightGray.copy(0.9f)
)
这是将要动画化的可堆肥的背景颜色列表,注意索引 1 处的颜色,这部分将改变其位置,从而产生微光效果。
步骤 3:使用 MainActivity.kt 文件
创建一个可组合的函数,动画将在其上发生
Kotlin
@Composable
fun ShimmerItem(
brush: Brush
) {
// Column composable comtaining spacer shaped like a rectangle,
// set the [background]'s [brush] with the brush receiving from [ShimmerAnimation]
// Composable which is the Animation you are gonna create.
Column(modifier = Modifier.padding(16.dp)) {
Spacer(
modifier = Modifier
.fillMaxWidth()
.size(250.dp)
.background(brush = brush)
)
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(30.dp)
.padding(vertical = 8.dp)
.background(brush = brush)
)
}
}
Kotlin
@Composable
fun ShimmerAnimation(
) {
/*
Create InfiniteTransition
which holds child animation like [Transition]
animations start running as soon as they enter
the composition and do not stop unless they are removed
*/
val transition = rememberInfiniteTransition()
val translateAnim by transition.animateFloat(
/*
Specify animation positions,
initial Values 0F means it
starts from 0 position
*/
initialValue = 0f,
targetValue = 1000f,
animationSpec = infiniteRepeatable(
// Tween Animates between values over specified [durationMillis]
tween(durationMillis = 1200, easing = FastOutSlowInEasing),
RepeatMode.Reverse
)
)
/*
Create a gradient using the list of colors
Use Linear Gradient for animating in any direction according to requirement
start=specifies the position to start with in cartesian like system Offset(10f,10f) means x(10,0) , y(0,10)
end = Animate the end position to give the shimmer effect using the transition created above
*/
val brush = Brush.linearGradient(
colors = ShimmerColorShades,
start = Offset(10f, 10f),
end = Offset(translateAnim, translateAnim)
)
ShimmerItem(brush = brush)
}
Kotlin
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ShimmerAnimationTheme(darkTheme = false) {
Surface(color = MaterialTheme.colors.background) {
/*
Lazy column as I am adding multiple items for display purpose
create you UI according to requirement
*/
LazyColumn {
/*
Lay down the Shimmer Animated item 5 time
[repeat] is like a loop which executes the body
according to the number specified
*/
repeat(5) {
item {
ShimmerAnimation()
}
}
}
}
}
}
}
}
Kotlin
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.shimmeranimation.ui.theme.ShimmerAnimationTheme
import com.example.shimmeranimation.ui.theme.ShimmerColorShades
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ShimmerAnimationTheme(darkTheme = false) {
Surface(color = MaterialTheme.colors.background) {
/*
Lazy column as I am adding multiple items for display purpose
create you UI according to requirement
*/
LazyColumn {
/**
Lay down the Shimmer Animated item 5 time
[repeat] is like a loop which executes the body
according to the number specified
*/
repeat(5) {
item {
ShimmerAnimation()
}
}
}
}
}
}
}
}
@Composable
fun ShimmerAnimation(
) {
/*
Create InfiniteTransition
which holds child animation like [Transition]
animations start running as soon as they enter
the composition and do not stop unless they are removed
*/
val transition = rememberInfiniteTransition()
val translateAnim by transition.animateFloat(
/*
Specify animation positions,
initial Values 0F means it starts from 0 position
*/
initialValue = 0f,
targetValue = 1000f,
animationSpec = infiniteRepeatable(
/*
Tween Animates between values over specified [durationMillis]
*/
tween(durationMillis = 1200, easing = FastOutSlowInEasing),
RepeatMode.Reverse
)
)
/*
Create a gradient using the list of colors
Use Linear Gradient for animating in any direction according to requirement
start=specifies the position to start with in cartesian like system Offset(10f,10f) means x(10,0) , y(0,10)
end= Animate the end position to give the shimmer effect using the transition created above
*/
val brush = Brush.linearGradient(
colors = ShimmerColorShades,
start = Offset(10f, 10f),
end = Offset(translateAnim, translateAnim)
)
ShimmerItem(brush = brush)
}
@Composable
fun ShimmerItem(
brush: Brush
) {
/*
Column composable shaped like a rectangle,
set the [background]'s [brush] with the
brush receiving from [ShimmerAnimation]
which will get animated.
Add few more Composable to test
*/
Column(modifier = Modifier.padding(16.dp)) {
Spacer(
modifier = Modifier
.fillMaxWidth()
.size(250.dp)
.background(brush = brush)
)
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(30.dp)
.padding(vertical = 8.dp)
.background(brush = brush)
)
}
}
让我们创建动画。创建一个新的可组合函数。
科特林
@Composable
fun ShimmerAnimation(
) {
/*
Create InfiniteTransition
which holds child animation like [Transition]
animations start running as soon as they enter
the composition and do not stop unless they are removed
*/
val transition = rememberInfiniteTransition()
val translateAnim by transition.animateFloat(
/*
Specify animation positions,
initial Values 0F means it
starts from 0 position
*/
initialValue = 0f,
targetValue = 1000f,
animationSpec = infiniteRepeatable(
// Tween Animates between values over specified [durationMillis]
tween(durationMillis = 1200, easing = FastOutSlowInEasing),
RepeatMode.Reverse
)
)
/*
Create a gradient using the list of colors
Use Linear Gradient for animating in any direction according to requirement
start=specifies the position to start with in cartesian like system Offset(10f,10f) means x(10,0) , y(0,10)
end = Animate the end position to give the shimmer effect using the transition created above
*/
val brush = Brush.linearGradient(
colors = ShimmerColorShades,
start = Offset(10f, 10f),
end = Offset(translateAnim, translateAnim)
)
ShimmerItem(brush = brush)
}
调用要设置动画的 ShimmerItem,并传递 Brush 对象,
第 4 步:将动画 ShimmerItem 放在屏幕上
在类 MainActivity
科特林
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ShimmerAnimationTheme(darkTheme = false) {
Surface(color = MaterialTheme.colors.background) {
/*
Lazy column as I am adding multiple items for display purpose
create you UI according to requirement
*/
LazyColumn {
/*
Lay down the Shimmer Animated item 5 time
[repeat] is like a loop which executes the body
according to the number specified
*/
repeat(5) {
item {
ShimmerAnimation()
}
}
}
}
}
}
}
}
我们已经完成了。这是MainActivity.kt文件的最终代码。
科特林
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.shimmeranimation.ui.theme.ShimmerAnimationTheme
import com.example.shimmeranimation.ui.theme.ShimmerColorShades
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ShimmerAnimationTheme(darkTheme = false) {
Surface(color = MaterialTheme.colors.background) {
/*
Lazy column as I am adding multiple items for display purpose
create you UI according to requirement
*/
LazyColumn {
/**
Lay down the Shimmer Animated item 5 time
[repeat] is like a loop which executes the body
according to the number specified
*/
repeat(5) {
item {
ShimmerAnimation()
}
}
}
}
}
}
}
}
@Composable
fun ShimmerAnimation(
) {
/*
Create InfiniteTransition
which holds child animation like [Transition]
animations start running as soon as they enter
the composition and do not stop unless they are removed
*/
val transition = rememberInfiniteTransition()
val translateAnim by transition.animateFloat(
/*
Specify animation positions,
initial Values 0F means it starts from 0 position
*/
initialValue = 0f,
targetValue = 1000f,
animationSpec = infiniteRepeatable(
/*
Tween Animates between values over specified [durationMillis]
*/
tween(durationMillis = 1200, easing = FastOutSlowInEasing),
RepeatMode.Reverse
)
)
/*
Create a gradient using the list of colors
Use Linear Gradient for animating in any direction according to requirement
start=specifies the position to start with in cartesian like system Offset(10f,10f) means x(10,0) , y(0,10)
end= Animate the end position to give the shimmer effect using the transition created above
*/
val brush = Brush.linearGradient(
colors = ShimmerColorShades,
start = Offset(10f, 10f),
end = Offset(translateAnim, translateAnim)
)
ShimmerItem(brush = brush)
}
@Composable
fun ShimmerItem(
brush: Brush
) {
/*
Column composable shaped like a rectangle,
set the [background]'s [brush] with the
brush receiving from [ShimmerAnimation]
which will get animated.
Add few more Composable to test
*/
Column(modifier = Modifier.padding(16.dp)) {
Spacer(
modifier = Modifier
.fillMaxWidth()
.size(250.dp)
.background(brush = brush)
)
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(30.dp)
.padding(vertical = 8.dp)
.background(brush = brush)
)
}
}
输出:
获取完整的项目。