我的-页面顶部导航栏ui修改,增加下滑时顶部导航栏的变化效果以及壁纸头像大小修正
This commit is contained in:
@@ -7,6 +7,7 @@ import android.util.Log
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -100,6 +101,13 @@ import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import java.text.NumberFormat
|
||||
import java.util.Locale
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -134,7 +142,8 @@ fun ProfileV3(
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val navController = LocalNavController.current
|
||||
val bannerHeight = 400
|
||||
val bannerWidth = 402
|
||||
val bannerHeight = 206
|
||||
val pickBannerImageLauncher = pickupAndCompressLauncher(
|
||||
context,
|
||||
scope,
|
||||
@@ -156,12 +165,13 @@ fun ProfileV3(
|
||||
val gridState = rememberLazyGridState()
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
val toolbarAlpha by remember {
|
||||
// 计算导航栏背景透明度,根据滚动位置从0到1
|
||||
val toolbarBackgroundAlpha by remember {
|
||||
derivedStateOf {
|
||||
if (!isSelf) {
|
||||
1f
|
||||
} else {
|
||||
val maxScroll = 500f // 最大滚动距离,可调整
|
||||
val maxScroll = 600f // 增加最大滚动距离,让渐变更平缓
|
||||
val progress = (scrollState.value.coerceAtMost(maxScroll.toInt()) / maxScroll).coerceIn(0f, 1f)
|
||||
progress
|
||||
}
|
||||
@@ -308,12 +318,19 @@ fun ProfileV3(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(bannerHeight.dp)
|
||||
.background(AppColors.profileBackground)
|
||||
.background(AppColors.profileBackground),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(bannerHeight.dp - 24.dp)
|
||||
.width(bannerWidth.dp)
|
||||
.height(bannerHeight.dp)
|
||||
.clip(
|
||||
RoundedCornerShape(
|
||||
bottomStart = 32.dp,
|
||||
bottomEnd = 32.dp
|
||||
)
|
||||
)
|
||||
.let {
|
||||
if (isSelf && isMain) {
|
||||
it.noRippleClickable {
|
||||
@@ -326,13 +343,6 @@ fun ProfileV3(
|
||||
it
|
||||
}
|
||||
}
|
||||
.shadow(
|
||||
elevation = 6.dp,
|
||||
shape = RoundedCornerShape(
|
||||
bottomStart = 32.dp,
|
||||
bottomEnd = 32.dp
|
||||
),
|
||||
)
|
||||
) {
|
||||
CustomAsyncImage(
|
||||
LocalContext.current,
|
||||
@@ -347,6 +357,9 @@ fun ProfileV3(
|
||||
Spacer(modifier = Modifier.height(100.dp))
|
||||
}
|
||||
|
||||
// 壁纸下方间距
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 用户信息
|
||||
Box(
|
||||
modifier = Modifier
|
||||
@@ -478,6 +491,9 @@ fun ProfileV3(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 底部间距,增加滚动距离
|
||||
Spacer(modifier = Modifier.height(100.dp))
|
||||
}
|
||||
|
||||
// 顶部导航栏
|
||||
@@ -486,9 +502,13 @@ fun ProfileV3(
|
||||
isSelf = isSelf,
|
||||
profile = profile,
|
||||
navController = navController,
|
||||
alpha = toolbarAlpha,
|
||||
backgroundAlpha = toolbarBackgroundAlpha,
|
||||
interactionCount = moments.sumOf { it.likeCount }, // 计算总点赞数作为互动数据
|
||||
onMenuClick = {
|
||||
showOtherUserMenu = true
|
||||
},
|
||||
onShareClick = {
|
||||
// TODO: 实现分享功能
|
||||
}
|
||||
)
|
||||
|
||||
@@ -569,107 +589,264 @@ fun TopNavigationBar(
|
||||
isSelf: Boolean,
|
||||
profile: AccountProfileEntity?,
|
||||
navController: androidx.navigation.NavController,
|
||||
alpha: Float,
|
||||
onMenuClick: () -> Unit = {}
|
||||
backgroundAlpha: Float,
|
||||
interactionCount: Int = 0,
|
||||
onMenuClick: () -> Unit = {},
|
||||
onShareClick: () -> Unit = {}
|
||||
) {
|
||||
val appColors = LocalAppTheme.current
|
||||
val numberFormat = remember { NumberFormat.getNumberInstance(Locale.getDefault()) }
|
||||
|
||||
// 根据背景透明度决定图标颜色:透明度为1时变黑,否则为白色
|
||||
val iconColor = if (backgroundAlpha >= 1f) Color.Black else Color.White
|
||||
val cardBorderColor = if (backgroundAlpha >= 1f) Color.Black else Color.White
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.graphicsLayer { this.alpha = alpha }
|
||||
) {
|
||||
Column(
|
||||
val statusBarPadding = WindowInsets.systemBars.asPaddingValues()
|
||||
val statusBarHeight = statusBarPadding.calculateTopPadding()
|
||||
val navigationBarHeight = 56.dp // 增加导航栏高度,包括图标和额外空间
|
||||
|
||||
// 导航栏背景层,包括状态栏区域,根据滚动位置逐渐变白
|
||||
val totalHeight = statusBarHeight + navigationBarHeight
|
||||
val density = LocalDensity.current
|
||||
val totalHeightPx = with(density) { totalHeight.toPx() }
|
||||
|
||||
// 根据滚动位置计算基础颜色,从深色平滑过渡到白色,透明度从初始值逐渐减到0
|
||||
val baseColor = remember(backgroundAlpha) {
|
||||
val smoothProgress = backgroundAlpha.coerceIn(0f, 1f)
|
||||
|
||||
// 初始状态:半透明深色,让白色图标清晰可见
|
||||
val initialDarkAlpha = 0.12f
|
||||
|
||||
// 使用平滑的插值函数,让整个过渡更自然
|
||||
val easedProgress = smoothProgress * smoothProgress * (3f - 2f * smoothProgress) // smoothstep
|
||||
|
||||
// 颜色值:从黑色(0)平滑过渡到白色(1)
|
||||
val colorValue = easedProgress
|
||||
|
||||
// 透明度:从初始值(0.12f)逐渐减少到0
|
||||
// 当smoothProgress从0到1时,alpha从initialDarkAlpha减少到0
|
||||
val alpha = initialDarkAlpha * (1f - easedProgress)
|
||||
|
||||
Color(
|
||||
red = colorValue,
|
||||
green = colorValue,
|
||||
blue = colorValue,
|
||||
alpha = alpha.coerceIn(0f, initialDarkAlpha)
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(appColors.profileBackground)
|
||||
.height(totalHeight) // 状态栏高度 + 导航栏高度
|
||||
.align(Alignment.TopCenter)
|
||||
.background(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
baseColor, // 顶部保持基础颜色
|
||||
baseColor, // 中间保持基础颜色
|
||||
baseColor.copy(alpha = baseColor.alpha * 0.5f), // 底部过渡,逐渐变透明
|
||||
Color.Transparent // 最底部完全透明
|
||||
),
|
||||
startY = 0f,
|
||||
endY = totalHeightPx
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// 功能按钮区域,图标和文字根据背景透明度改变颜色
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp, bottom = 16.dp, end = 16.dp) // 增加上下内边距
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(top = statusBarHeight), // 从状态栏下方开始
|
||||
horizontalArrangement = Arrangement.End,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
StatusBarSpacer()
|
||||
// 左侧:互动数据卡片
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
.height(24.dp)
|
||||
.background(
|
||||
color = Color.White.copy(alpha = 0.52f),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
.border(
|
||||
width = 0.5.dp,
|
||||
color = cardBorderColor, // 根据背景透明度改变边框颜色
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
.padding(horizontal = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
// 互动图标
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.paip_coin_img),
|
||||
contentDescription = "互动",
|
||||
modifier = Modifier.size(24.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = numberFormat.format(interactionCount),
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.W500,
|
||||
color = Color.Black, // 文字始终为黑色
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
// 中间:分享图标
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.menu_icon),
|
||||
contentDescription = "分享",
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.noRippleClickable {
|
||||
onShareClick()
|
||||
},
|
||||
colorFilter = ColorFilter.tint(iconColor) // 根据背景透明度改变颜色
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
// 右侧:菜单图标
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.menu_ico),
|
||||
contentDescription = "菜单",
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.noRippleClickable {
|
||||
if (isSelf && isMain) {
|
||||
IndexViewModel.openDrawer = true
|
||||
} else {
|
||||
onMenuClick()
|
||||
}
|
||||
},
|
||||
colorFilter = ColorFilter.tint(iconColor) // 根据背景透明度改变颜色
|
||||
)
|
||||
}
|
||||
|
||||
// 如果不是主页面,显示返回按钮和用户信息
|
||||
if (!isMain) {
|
||||
val statusBarPadding = WindowInsets.systemBars.asPaddingValues()
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
.padding(top = statusBarPadding.calculateTopPadding()),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (!isMain) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.rider_pro_back_icon),
|
||||
contentDescription = "Back",
|
||||
modifier = Modifier
|
||||
.noRippleClickable {
|
||||
navController.navigateUp()
|
||||
}
|
||||
.size(24.dp),
|
||||
colorFilter = ColorFilter.tint(appColors.text)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
CustomAsyncImage(
|
||||
LocalContext.current,
|
||||
profile?.avatar,
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.clip(CircleShape),
|
||||
contentDescription = "",
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Text(
|
||||
text = profile?.nickName ?: "",
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W600,
|
||||
color = appColors.text
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
if (isSelf && isMain) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.padding(16.dp)
|
||||
)
|
||||
} else if (!isSelf) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.noRippleClickable {
|
||||
onMenuClick()
|
||||
}
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
||||
contentDescription = "菜单",
|
||||
tint = appColors.text,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
if (isSelf && isMain) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(top = 32.dp, end = 16.dp)
|
||||
.noRippleClickable {
|
||||
IndexViewModel.openDrawer = true
|
||||
}
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.padding(16.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
||||
contentDescription = "",
|
||||
tint = appColors.text
|
||||
)
|
||||
}
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.rider_pro_back_icon),
|
||||
contentDescription = "Back",
|
||||
modifier = Modifier
|
||||
.noRippleClickable {
|
||||
navController.navigateUp()
|
||||
}
|
||||
.size(24.dp),
|
||||
colorFilter = ColorFilter.tint(Color.White)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
CustomAsyncImage(
|
||||
LocalContext.current,
|
||||
profile?.avatar,
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.clip(CircleShape),
|
||||
contentDescription = "",
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Text(
|
||||
text = profile?.nickName ?: "",
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W600,
|
||||
color = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分享图标(向上箭头)
|
||||
@Composable
|
||||
fun ShareIcon(
|
||||
color: Color,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Canvas(modifier = modifier) {
|
||||
val strokeWidth = 2.dp.toPx()
|
||||
val centerX = size.width / 2
|
||||
val centerY = size.height / 2
|
||||
|
||||
// 绘制向上的箭头
|
||||
// 底部横线
|
||||
drawLine(
|
||||
color = color,
|
||||
start = Offset(centerX - 9.dp.toPx(), centerY + 6.dp.toPx()),
|
||||
end = Offset(centerX + 9.dp.toPx(), centerY + 6.dp.toPx()),
|
||||
strokeWidth = strokeWidth
|
||||
)
|
||||
// 顶部横线
|
||||
drawLine(
|
||||
color = color,
|
||||
start = Offset(centerX - 5.dp.toPx(), centerY - 6.5.dp.toPx()),
|
||||
end = Offset(centerX + 5.dp.toPx(), centerY - 6.5.dp.toPx()),
|
||||
strokeWidth = strokeWidth
|
||||
)
|
||||
// 中间竖线
|
||||
drawLine(
|
||||
color = color,
|
||||
start = Offset(centerX, centerY - 3.dp.toPx()),
|
||||
end = Offset(centerX, centerY + 6.dp.toPx()),
|
||||
strokeWidth = strokeWidth
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 菜单图标(三条横线)
|
||||
@Composable
|
||||
fun MenuIcon(
|
||||
color: Color,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Canvas(modifier = modifier) {
|
||||
val strokeWidth = 2.dp.toPx()
|
||||
val centerX = size.width / 2
|
||||
val centerY = size.height / 2
|
||||
val lineLength = 16.dp.toPx()
|
||||
val spacing = 6.dp.toPx()
|
||||
|
||||
// 绘制三条横线
|
||||
drawLine(
|
||||
color = color,
|
||||
start = Offset(centerX - lineLength / 2, centerY - spacing),
|
||||
end = Offset(centerX + lineLength / 2, centerY - spacing),
|
||||
strokeWidth = strokeWidth
|
||||
)
|
||||
drawLine(
|
||||
color = color,
|
||||
start = Offset(centerX - lineLength / 2, centerY),
|
||||
end = Offset(centerX + lineLength / 2, centerY),
|
||||
strokeWidth = strokeWidth
|
||||
)
|
||||
drawLine(
|
||||
color = color,
|
||||
start = Offset(centerX - lineLength / 2, centerY + spacing),
|
||||
end = Offset(centerX + lineLength / 2, centerY + spacing),
|
||||
strokeWidth = strokeWidth
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Agent菜单弹窗
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user