年视图支持左右滑动切换年份

使用 HorizontalPager 包裹年视图,支持手势滑动切年。
‹ › 按钮改为 animateScrollToPage,与滑动行为一致。
This commit is contained in:
meyou 2026-05-16 16:43:32 +08:00
parent 502f1efc0a
commit 8dad07c0a0
2 changed files with 61 additions and 23 deletions

View File

@ -71,7 +71,7 @@ class CalendarViewModel(
@Suppress("DEPRECATION") // monthNumber 无替代 API
var yearViewYear by mutableStateOf(today.year)
private set
internal set
/**
* 选中指定日期

View File

@ -7,6 +7,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerDefaults
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -16,6 +18,7 @@ import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
@ -65,6 +68,32 @@ fun CalendarMonthView(
val pagerState = rememberPagerState(initialPage = START_PAGE, pageCount = { Int.MAX_VALUE })
// 年视图分页器
val yearPagerState = rememberPagerState(
initialPage = START_PAGE,
pageCount = { Int.MAX_VALUE }
)
// 进入年视图时同步 yearPagerState 到当前年
LaunchedEffect(viewModel.isYearView) {
if (viewModel.isYearView) {
if (yearPagerState.currentPage != START_PAGE) {
yearPagerState.scrollToPage(START_PAGE)
}
}
}
// 年视图翻页时同步 yearViewYear
LaunchedEffect(yearPagerState) {
snapshotFlow { yearPagerState.settledPage }.collect { page ->
val offset = page - START_PAGE
val targetYear = viewModel.selectedDate.year + offset
if (targetYear != viewModel.yearViewYear) {
viewModel.yearViewYear = targetYear
}
}
}
// 折叠态 WeekPager 切月时,持续同步 CalendarPager 的 pagerState
LaunchedEffect(viewModel.selectedDate) {
@Suppress("DEPRECATION") // monthNumber 无替代 API
@ -241,28 +270,12 @@ fun CalendarMonthView(
}
}
// 年视图层
// 年视图层HorizontalPager 支持左右滑动切年
if (viewModel.isYearView || yearProgress > 0.01f) {
YearGridView(
year = viewModel.yearViewYear,
selectedMonth = if (viewModel.yearViewYear == currentYear) currentMonth else 0,
today = today,
onMonthClick = { month ->
viewModel.selectMonthFromYearView(month)
// 同步 CalendarPager 到目标月份
@Suppress("DEPRECATION") // monthNumber 无替代 API
val targetPage = yearMonthToPage(
viewModel.yearViewYear, month,
today.year, today.month.number
)
if (targetPage != pagerState.currentPage) {
coroutineScope.launch { pagerState.scrollToPage(targetPage) }
}
},
onYearChange = { newYear ->
if (newYear > viewModel.yearViewYear) viewModel.incrementYear()
else viewModel.decrementYear()
},
HorizontalPager(
state = yearPagerState,
beyondViewportPageCount = 1,
flingBehavior = PagerDefaults.flingBehavior(state = yearPagerState),
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
@ -272,7 +285,32 @@ fun CalendarMonthView(
transformOrigin = TransformOrigin(anchorPivotX, anchorPivotY)
}
.padding(horizontal = HORIZONTAL_PADDING_DP.dp)
)
) { page ->
val pageYear = viewModel.selectedDate.year + (page - START_PAGE)
YearGridView(
year = pageYear,
selectedMonth = if (pageYear == currentYear) currentMonth else 0,
today = today,
onMonthClick = { month ->
viewModel.selectMonthFromYearView(month)
@Suppress("DEPRECATION") // monthNumber 无替代 API
val targetPage = yearMonthToPage(
viewModel.yearViewYear, month,
today.year, today.month.number
)
if (targetPage != pagerState.currentPage) {
coroutineScope.launch { pagerState.scrollToPage(targetPage) }
}
},
onYearChange = { newYear ->
val offset = newYear - pageYear
val targetPage = yearPagerState.currentPage + offset
if (targetPage != yearPagerState.currentPage) {
coroutineScope.launch { yearPagerState.animateScrollToPage(targetPage) }
}
}
)
}
}
// BottomCard年视图时隐藏