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

相关推荐
saoys12 小时前
Opencv 学习笔记:图像掩膜操作(精准提取指定区域像素)
笔记·opencv·学习
电子小白12313 小时前
第13期PCB layout工程师初级培训-1-EDA软件的通用设置
笔记·嵌入式硬件·学习·pcb·layout
贺biubiu15 小时前
2025 年终总结|总有那么一个人,会让你千里奔赴...
android·程序员·年终总结
xuekai2008090115 小时前
mysql-组复制 -8.4.7 主从搭建
android·adb
clorisqqq15 小时前
人工智能现代方法笔记 第1章 绪论(1/2)
人工智能·笔记
charlie11451419115 小时前
嵌入式现代C++教程: 构造函数优化:初始化列表 vs 成员赋值
开发语言·c++·笔记·学习·嵌入式·现代c++
nono牛16 小时前
ps -A|grep gate
android
wdfk_prog16 小时前
[Linux]学习笔记系列 -- [fs]seq_file
linux·笔记·学习
liuchangng16 小时前
Open-AutoGLM部署运行笔记
笔记
君心似砂16 小时前
很久没有写东西了
笔记