A composable Calendar.
![default](https://private-user-images.githubusercontent.com/7933189/336353506-3c78bbbd-7283-4066-8206-6c494a87f716.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkwOTYwNzQsIm5iZiI6MTczOTA5NTc3NCwicGF0aCI6Ii83OTMzMTg5LzMzNjM1MzUwNi0zYzc4YmJiZC03MjgzLTQwNjYtODIwNi02YzQ5NGE4N2Y3MTYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTAwOTM0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OWE5ZDhiYThlNGNjODYwYTUzODdjNmFlOThlYWQxMTJlNjBkODM1ZmY4MjQwY2JiZjQ5NzQ4ZjkwZGMyNDg3NCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.E7fLJWu8Jw7fhlxAz36Tvf_c63EWDniv1JwJ_SF2hQQ)
![default](https://private-user-images.githubusercontent.com/7933189/336353050-f96b275b-2ba1-40b3-895e-0026c5267460.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkwOTYwNzQsIm5iZiI6MTczOTA5NTc3NCwicGF0aCI6Ii83OTMzMTg5LzMzNjM1MzA1MC1mOTZiMjc1Yi0yYmExLTQwYjMtODk1ZS0wMDI2YzUyNjc0NjAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTAwOTM0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9M2Y5MDI2MWUyNDQyYmRiOGQ5OWJhMjU3N2VkNDA2NWEzN2NiZmU3MjU1MWI0ODMyMjI3MTNkNzgyMTI3MDMxZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.rUX7_rPhCfm8sr9fYeBNZ_Txk6at5Ey4HblsXdYgj78)
![default](https://private-user-images.githubusercontent.com/7933189/335029683-c3f2d0ab-ed8a-429c-82ba-d672e9d65324.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkwOTYwNzQsIm5iZiI6MTczOTA5NTc3NCwicGF0aCI6Ii83OTMzMTg5LzMzNTAyOTY4My1jM2YyZDBhYi1lZDhhLTQyOWMtODJiYS1kNjcyZTlkNjUzMjQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTAwOTM0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZDMyOGNlNTEyNjE3MTJiZDY4ODZkMjZjNTczMGZiMDRmMzUzOWE4NDQ3NmNiYWNhNGUwZmViZTllMDZiOWM5YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.G5TPMuVn2F-QLNUc9332UgrQQI6Gxr659t4-_icqhNY)
-
Add it in your root build.gradle at the end of repositories:
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { mavenCentral() maven { url 'https://jitpack.io' } } }
-
Add the dependency
dependencies { implementation 'com.github.dyguests:LinCalendar:0.4.0' }
val state = rememberLinCalendarState()
LinCalendar(
state = state,
)
fun rememberLinCalendarState(
initialDate: LocalDate = LocalDate.now(),
startDate: LocalDate = LocalDate.of(1900, 1, 1),
endDate: LocalDate = LocalDate.of(2099, 12, 31),
initialDisplayMode: LinCalendar.DisplayMode = LinCalendar.DisplayMode.MONTHLY,
option: LinCalendar.Option = LinCalendarDefaults.option(),
): LinCalendarState
enum class DisplayMode {
MONTHLY,
WEEKLY, // todo impl
}
data class Option(
val headerHeight: Dp = 32.dp,
val rowHeight: Dp = 36.dp,
val firstDayOfWeek: DayOfWeek = DayOfWeek.MONDAY,
val weekDisplayMode: WeekDisplayMode = WeekDisplayMode.FIXED_HEIGHT,
val locale: Locale = Locale.getDefault(),
)
Consider of WeekDisplayMode
, the height of Calendar in different months may be different.
Therefore, you cannot set the height of Calendar directly, but use headerHeight
and rowHeight
.
enum class WeekDisplayMode {
// Fixed height, leaving the fifth week empty
FIXED_HEIGHT,
// Fixed height, equally dividing height by weeks
EQUAL_HEIGHT, // todo impl
// Dynamic height, adapting to the number of weeks in the month
DYNAMIC_HEIGHT // todo impl
}
Each part of LinCalendar is composable, so you can customize each part yourself.
LinCalendar
monthsField
monthFiled
weekHeaderField
dayHeaderField
weekField
dayField
Add a highlighted background to today's day of the calendar.
Step 1
Add LinCalendar
val state = rememberLinCalendarState()
LinCalendar(
state = state,
)
Step 2
If you look at the source code, you can see that the above code is equivalent to:
LinCalendar(
state = state,
monthsField = LinCalendarDefaults.monthsField(
state = state,
monthFiled = LinCalendarDefaults.monthField(
state = state,
),
),
)
...
equivalent to:
LinCalendar(
state = state,
monthsField = LinCalendarDefaults.monthsField(
state = state,
monthFiled = LinCalendarDefaults.monthField(
state = state,
weekField = LinCalendarDefaults.weekField(
state = state,
dayField = LinCalendarDefaults.dayField(
state = state,
)
),
),
),
)
To highlighted background to today's day, You need to custom dayField
, change code to this:
val dayField = LinCalendarDefaults.dayField(
state = state,
)
LinCalendar(
// ...
dayField = dayField
// ...
)
Now we focus on dayField
Step 3
Inline the function LinCalendarDefaults.dayField
.(You can also copy the source code of LinCalendarDefaults.dayField
)
val dayField: @Composable RowScope.(YearMonth, LocalDate) -> Unit = { yearMonth: YearMonth, localDate: LocalDate ->
val now = remember { LocalDate.now() }
Box(
modifier = Modifier
.height(state.option.rowHeight)
.weight(1f)
.then(Modifier),
contentAlignment = Alignment.Center,
) {
Text(
text = localDate.dayOfMonth.toString(),
style = TextStyle(
color = if (localDate == now) MaterialTheme.colorScheme.primary
else MaterialTheme.colorScheme.onSurface,
fontWeight = if (localDate == now) FontWeight.Bold
else if (yearMonth.month == localDate.month) FontWeight.Normal
else FontWeight.Light,
),
)
}
}
Now you can add a highlighted background to today.
val dayField: @Composable RowScope.(YearMonth, LocalDate) -> Unit = { yearMonth: YearMonth, localDate: LocalDate ->
// ...
Box(
// ...
) {
if (localDate == now) {
Box(
modifier = Modifier
.size(32.dp)
.background(Color.Red, CircleShape)
)
}
Text(
// ...
style = TextStyle(
color = if (localDate == now) Color.White
// ...
),
)
}
}
![default](https://private-user-images.githubusercontent.com/7933189/336364971-0769bdb9-a2d1-426d-9d55-47d039c45e2a.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkwOTYwNzQsIm5iZiI6MTczOTA5NTc3NCwicGF0aCI6Ii83OTMzMTg5LzMzNjM2NDk3MS0wNzY5YmRiOS1hMmQxLTQyNmQtOWQ1NS00N2QwMzljNDVlMmEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDlUMTAwOTM0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YTBmNDY5MTIxNGEzYjNkZTBhZDgzNTljYzA0NGNlNzRjYmQ0MjdhZGY4ODBiNmYwNDUxMWU2MWRiMTI3OWUzOSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.R6qowjSvkQWWFaEWVyd8FNbKPlLg1O1o2EI6NZPW7uw)
That's it.
- 隐藏无关细节。比如monthFiled中的计算逻辑