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 避免过度使用,在复杂列表或高频触发动画的场景,过多动画可能引发性能问题。

相关推荐
滕州市燕猫虎计算机科技工作室个体工商户4 小时前
《Rust程序设计》学习笔记八:结构体
笔记·学习·rust·rust程序设计
志尊宝5 小时前
Vue3 零基础每日笔记(082):文件上传实战——el-upload 校验、自定义上传、头像预览
前端·javascript·vue.js·笔记·#javascript·#vue.js
后季暖6 小时前
电商问数笔记(2)
笔记
xier_ran6 小时前
【infra之路】AI 编译器学习笔记(二):重拾 C++——移动语义与 LLVM 风格的类型转换
人工智能·笔记·学习
geovindu7 小时前
sql:Search-Optimized SQL Queries using mysql 9.0
android·数据库·sql·mysql·数据库开发·数据库架构
星恒随风8 小时前
Linux库的底层原理:ELF文件格式、静态链接、程序加载、虚拟地址空间与GOT/PLT详解
linux·运维·笔记·学习·状态模式
罗西的思考9 小时前
[Agent Memory / 强化学习] MemPO源码学习笔记 — (7)— 混合机制
笔记·学习
知之则吱吱9 小时前
Android 开发者验证机制迎来新变化:核心要求、实施时间与开发者应对指南
android·google
ClinicTech10 小时前
婴儿培养箱技术笔记:温控、报警与数据记录的三层架构
笔记
xiaominngtongxue10 小时前
从一次接触网实训课看中职实训教学的组织逻辑
笔记