Compose笔记(五十八)--LinearOutSlowInEasing

这一节主要了解一下LinearOutSlowInEasing,在Jetpack Compose中,LinearOutSlowInEasing是一个预定义的缓动函数,用于控制动画的速度变化曲线,使动画看起来更自然、流畅以符合特定交互预期,简单总结如下:

API

Kotlin 复制代码
val LinearOutSlowInEasing: Easing = CubicBezierEasing(0.0f, 0.0f, 0.2f, 1.0f)

本质是三次贝塞尔曲线实现的缓动函数,参数(0f,0f,0.2f,1f)定义了速率变化轨迹:

动画前半段:速率接近匀速(Linear Out);

动画后半段:速率逐渐降低(Slow In),结束时平滑停止。

场景:

1 抽屉式导航栏、底部弹窗、列表项展开/折叠。

2 按钮点击反馈、图片浏览器的缩略图展开、卡片选中效果。

3 按钮状态切换(启用/禁用)、页面背景渐变、通知栏淡入淡出。

栗子:

Kotlin 复制代码
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.LinearOutSlowInEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.size
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch

@Composable
fun ProgressBarDemo() {
    val progress = remember { Animatable(0f) }
    val coroutineScope = rememberCoroutineScope()

    
    LaunchedEffect(Unit) {
        coroutineScope.launch {
            progress.animateTo(
                targetValue = 1f,
                animationSpec = tween(
                    durationMillis = 1500,
                    easing = LinearOutSlowInEasing
                )
            )
        }
    }

    Canvas(modifier = Modifier.size(100.dp)) {
        
        drawCircle(
            color = Color.LightGray,
            radius = size.minDimension / 2 - 4.dp.toPx(),
            style = Stroke(width = 8.dp.toPx())
        )
       
        drawArc(
            color = Color.Blue,
            startAngle = -90f,
            sweepAngle = progress.value * 360f,
            useCenter = false,
            style = Stroke(width = 8.dp.toPx(), cap = StrokeCap.Round)
        )
    }
}
Kotlin 复制代码
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Menu
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.scale
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DrawerSidebarDemo() {
    var isDrawerOpen by remember { mutableStateOf(false) }

    
    val drawerOffset by animateDpAsState(
        targetValue = if (isDrawerOpen) 0.dp else -280.dp,
        animationSpec = tween(
            durationMillis = 400,
            easing = LinearOutSlowInEasing
        )
    )

    
    val contentScale by animateFloatAsState(
        targetValue = if (isDrawerOpen) 0.95f else 1f,
        animationSpec = tween(
            durationMillis = 400,
            easing = LinearOutSlowInEasing
        )
    )
    val contentAlpha by animateFloatAsState(
        targetValue = if (isDrawerOpen) 0.7f else 1f,
        animationSpec = tween(
            durationMillis = 400,
            easing = LinearOutSlowInEasing
        )
    )
    val contentShadow by animateDpAsState(
        targetValue = if (isDrawerOpen) 10.dp else 0.dp,
        animationSpec = tween(
            durationMillis = 400,
            easing = LinearOutSlowInEasing
        )
    )

    Box(modifier = Modifier.fillMaxSize()) {
        
        Column(
            modifier = Modifier
                .width(280.dp)
                .fillMaxHeight()
                .offset(x = drawerOffset)
                .background(MaterialTheme.colorScheme.primaryContainer)
                .padding(20.dp)
        ) {
            Text("侧边菜单", style = MaterialTheme.typography.headlineSmall)
            Spacer(modifier = Modifier.height(30.dp))
            listOf("首页", "消息", "设置", "关于").forEach { item ->
                Text(
                    text = item,
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(12.dp),
                    style = MaterialTheme.typography.bodyLarge
                )
            }
        }

        
        Column(
            modifier = Modifier
                .fillMaxSize()
                .scale(contentScale)
                .alpha(contentAlpha)
                .shadow(contentShadow)
                .background(MaterialTheme.colorScheme.surface)
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            TopAppBar(
                title = { Text("主页面") },
                navigationIcon = {
                    IconButton(onClick = { isDrawerOpen = !isDrawerOpen }) {
                        Icon(Icons.Outlined.Menu, contentDescription = "菜单")
                    }
                }
            )
            Spacer(modifier = Modifier.height(50.dp))
            Text(
                text = if (isDrawerOpen) "抽屉已打开" else "点击左上角菜单打开抽屉",
                style = MaterialTheme.typography.bodyLarge
            )
        }
    }
}

注意:

1 避免与过短的动画时长搭配,LinearOutSlowInEasing的"慢入"阶段需要一定时间才能体现缓冲效果。

2 避免过度使用,在复杂列表或高频触发动画的场景,过多动画可能引发性能问题。

相关推荐
qqVHU8 小时前
kafka笔记
笔记·分布式·kafka
晓梦林8 小时前
stitch靶场学习笔记
笔记·学习
prog_61038 小时前
【笔记】用cursor手搓cursor(六)deepseek v4
人工智能·笔记·agent·deepseek·claude code
ouliten8 小时前
[Triton笔记4]低内存 Dropout
笔记·triton
凌波粒8 小时前
深度学习入门(鱼书)第2章笔记——感知机
人工智能·笔记·深度学习
lvronglee8 小时前
【数字图传第四步】Android App查看图传视频
android·音视频
90后的晨仔9 小时前
Android 程序入口与核心组件详解
android
90后的晨仔9 小时前
Kotlin 简介与开发环境搭建
android
RainCityLucky9 小时前
Java Swing 自定义组件库分享(七)
java·笔记·后端
清平乐的技术专栏9 小时前
【Kafka笔记】(一)认识 Kafka
笔记·分布式·kafka