Add year view with Hero Zoom transition
- CalendarViewModel: add isYearView, yearViewProgress, yearViewYear state with toggleYearView(), selectMonthFromYearView(), year navigation methods - YearGridView: new 4x3 month grid with year navigation header - MonthHeader: onClick now toggles year view, added "今天" button - CalendarMonthView: overlay year view with graphicsLayer anchor-based scale transition, hide BottomCard during year view
This commit is contained in:
parent
16b73c4373
commit
995693cb5d
154
shared/src/commonMain/kotlin/plus/rua/project/ui/YearGridView.kt
Normal file
154
shared/src/commonMain/kotlin/plus/rua/project/ui/YearGridView.kt
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
package plus.rua.project.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.drawBehind
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 年度网格视图,显示 4×3 月份网格,支持年份切换。
|
||||||
|
*
|
||||||
|
* @param year 显示的年份
|
||||||
|
* @param selectedMonth 当前选中月份(1-12)
|
||||||
|
* @param onMonthClick 月份点击回调
|
||||||
|
* @param onYearChange 年份切换回调
|
||||||
|
* @param modifier 外部布局修饰符
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun YearGridView(
|
||||||
|
year: Int,
|
||||||
|
selectedMonth: Int,
|
||||||
|
onMonthClick: (Int) -> Unit,
|
||||||
|
onYearChange: (Int) -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
// 年份导航行
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "‹",
|
||||||
|
fontSize = 24.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(CircleShape)
|
||||||
|
.clickable { onYearChange(year - 1) }
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Text(
|
||||||
|
text = "${year}年",
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Text(
|
||||||
|
text = "›",
|
||||||
|
fontSize = 24.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(CircleShape)
|
||||||
|
.clickable { onYearChange(year + 1) }
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4×3 月份网格
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f)
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
verticalArrangement = Arrangement.SpaceEvenly
|
||||||
|
) {
|
||||||
|
(0 until 4).forEach { row ->
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceEvenly
|
||||||
|
) {
|
||||||
|
(0 until 3).forEach { col ->
|
||||||
|
val month = row * 3 + col + 1
|
||||||
|
MonthCell(
|
||||||
|
month = month,
|
||||||
|
isSelected = month == selectedMonth,
|
||||||
|
onClick = { onMonthClick(month) },
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 年视图中的月份单元格。
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
private fun MonthCell(
|
||||||
|
month: Int,
|
||||||
|
isSelected: Boolean,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val contentColor = if (isSelected) {
|
||||||
|
MaterialTheme.colorScheme.onPrimary
|
||||||
|
} else {
|
||||||
|
MaterialTheme.colorScheme.onSurface
|
||||||
|
}
|
||||||
|
val bgColor = MaterialTheme.colorScheme.primary
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.padding(6.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.drawBehind {
|
||||||
|
if (isSelected) {
|
||||||
|
drawCircle(
|
||||||
|
color = bgColor,
|
||||||
|
radius = size.minDimension / 2f,
|
||||||
|
center = Offset(size.width / 2f, size.height / 2f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.clickable(onClick = onClick),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${month}月",
|
||||||
|
color = contentColor,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user