如何在Jetpack Compose Material 3中实现折叠式TopAppBar
在Jetpack Compose Material 3中实现折叠式TopAppBar
核心思路是利用Material3的ExitUntilCollapsedScrollBehavior获取折叠进度(collapsedFraction),通过这个进度值动态过渡UI元素的颜色、尺寸属性,完全匹配你需要的折叠效果:
import androidx.compose.animation.core.animateColorAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Search import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @OptIn(ExperimentalMaterial3Api::class) @Composable fun CollapsibleWeatherTopAppBar() { // 初始化折叠滚动行为 val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior( rememberTopAppBarState(), canScroll = { true } ) // 获取折叠进度:0=完全展开,1=完全收起 val collapsedFraction = scrollBehavior.state.collapsedFraction // 标题/搜索图标颜色过渡:展开时用OnSurface,收起时切换为Primary val titleAndIconColor by animateColorAsState( targetValue = if (collapsedFraction >= 1f) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface, animationSpec = tween(300) ) // 温度文本尺寸过渡:展开48sp,收起24sp val temperatureTextSize by animateFloatAsState( targetValue = if (collapsedFraction >= 1f) 24f else 48f, animationSpec = tween(300) ) // 温度颜色过渡:展开时Primary,收起时OnSurface val temperatureColor by animateColorAsState( targetValue = if (collapsedFraction >= 1f) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.primary, animationSpec = tween(300) ) // Feels like文本颜色过渡:展开时OnSurfaceVariant,收起时OnSurface val feelsLikeColor by animateColorAsState( targetValue = if (collapsedFraction >= 1f) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.onSurfaceVariant, animationSpec = tween(300) ) Scaffold( topBar = { TopAppBar( title = { Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { // 城市标题区域 Row( modifier = Modifier.weight(1f), verticalAlignment = Alignment.CenterVertically ) { Column { Text( text = "Kharkive, Ukraine", color = titleAndIconColor, style = MaterialTheme.typography.titleLarge.copy( fontWeight = FontWeight.Medium ) ) Text( text = "Feels like -2°", color = feelsLikeColor, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.padding(top = 4.dp) ) } } // 温度与搜索图标区域 Row(verticalAlignment = Alignment.CenterVertically) { Text( text = "3°", color = temperatureColor, fontSize = temperatureTextSize.sp, fontWeight = FontWeight.Bold ) Spacer(modifier = Modifier.size(16.dp)) Icon( imageVector = Icons.Default.Search, contentDescription = "Search", tint = titleAndIconColor, modifier = Modifier.size(24.dp) ) } } }, scrollBehavior = scrollBehavior, colors = TopAppBarDefaults.topAppBarColors( containerColor = Color.Transparent, scrolledContainerColor = MaterialTheme.colorScheme.surface ) ) } ) { paddingValues -> // 可滚动内容,用于触发TopAppBar的折叠逻辑 LazyColumn(modifier = Modifier.padding(paddingValues)) { items(50) { index -> Text( text = "List item $index", modifier = Modifier .fillMaxWidth() .padding(16.dp) ) } } } }
关键实现说明
- 折叠进度控制:
collapsedFraction是核心变量,它反映了TopAppBar的折叠程度,所有UI变化都基于这个值触发 - 平滑过渡动画:使用
animateColorAsState和animateFloatAsState实现颜色、尺寸的无缝切换,避免生硬的视觉跳变 - 布局稳定性:标题和搜索图标的位置全程保持不变,仅通过颜色、尺寸的变化体现折叠状态,完全符合你的需求
内容的提问来源于stack exchange,提问作者Muhammad Ibrahim
相关产品推荐
相关产品推荐

