## 다이어리 프로젝트 with SandBurger
[Kotlin] CosmoCalendar library 사용하기 (tistory.com)
지난 포스팅에서 cosmocalendar 라이브러리를 사용하여 calendar를 커스텀하는 작업을 진행했습니다. 하지만 커스텀하는 과정에서 저희 프로젝트에서 원하는만큼의 커스텀이 어렵다고 판단하여 새로운 라이브러리를 찾게 되었고, 그 결과 kizitonwose CalendarView 라는 라이브러리를 사용하게 되었습니다.
완성된 화면은 아래와 같습니다
CalendarFragment.kt
class DayViewContainer(view : View) : ViewContainer(view) {
val textView = ItemCalendarDayBinding.bind(view).itemCalendarDayTv
val imageView = ItemCalendarDayBinding.bind(view).itemCalendarDayIv
lateinit var day : CalendarDay
init {
//날짜 click시 동작
view.setOnClickListener{
if (day.owner == DayOwner.THIS_MONTH){
val currentSelection = selectedDay
// 이미 선택한 날짜일 시 선택 취소
if(currentSelection == day.date){
selectedDay = null
binding.calendarCalendarCv.notifyDateChanged(currentSelection)
} else {
// 새로 선택한 날짜일 시 새로 선택한 날짜로 변경
selectedDay = day.date
binding.calendarCalendarCv.notifyDateChanged(day.date)
if (currentSelection != null){
binding.calendarCalendarCv.notifyDateChanged(currentSelection)
}
}
}
}
}
}
binding.calendarCalendarCv.dayBinder = object : DayBinder<DayViewContainer> {
override fun create(view: View) = DayViewContainer(view)
override fun bind(container: DayViewContainer, day: CalendarDay) {
container.day = day
container.textView.text = day.date.dayOfMonth.toString()
if(day.owner == DayOwner.THIS_MONTH){
when{
// 선택된 날짜는 백그라운드 이미지 보이게 설정
day.date == selectedDay -> {
container.imageView.visibility = View.VISIBLE
}
// 일요일 색깔 변경
day.date.dayOfWeek.value == 7 -> {
container.textView.setTextColor(ContextCompat
.getColor(requireContext(), R.color.error))
}
// 토요일 색깔 변경
day.date.dayOfWeek.value == 6 -> {
container.textView.setTextColor(ContextCompat
.getColor(requireContext(), R.color.saturday_blue))
}
else -> {
container.textView.setTextColor(ContextCompat
.getColor(requireContext(), R.color.line_black))
container.imageView.visibility = View.INVISIBLE
}
}
// 현재 선택된 월이 아니면 날짜 색깔을 회색으로 표시
} else {
container.textView.setTextColor(ContextCompat
.getColor(requireContext(),R.color.line_grey))
}
}
val daysOfWeek = arrayOf(
DayOfWeek.SUNDAY,
DayOfWeek.MONDAY,
DayOfWeek.TUESDAY,
DayOfWeek.WEDNESDAY,
DayOfWeek.THURSDAY,
DayOfWeek.FRIDAY,
DayOfWeek.SATURDAY
)
val currentMonth = YearMonth.now()
val firstMonth = currentMonth.minusMonths(10)
val lastMonth = currentMonth.plusMonths(10)
binding.calendarCalendarCv.setup(firstMonth, lastMonth, daysOfWeek.first())
binding.calendarCalendarCv.scrollToMonth(currentMonth)
}
FragmentCalendarDate.kt
class FragmentCalendarDate : Fragment() {
private var _binding: FragmentCalendarDateBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentCalendarDateBinding.inflate(inflater, container, false)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
fragment_calendar.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/backgroundColor"
tools:context=".ui.calendar.CalendarFragment">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/calendar_date_container"
android:layout_width="0dp"
android:layout_height="30dp"
android:name="com.example.sandiary.ui.calendar.FragmentCalendarDate"
app:layout_constraintTop_toBottomOf="@id/calendar_divider_iv"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<com.kizitonwose.calendarview.CalendarView
android:id="@+id/calendar_calendar_cv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cv_orientation="horizontal"
app:cv_inDateStyle="allMonths"
app:cv_outDateStyle="endOfRow"
app:cv_scrollMode="paged"
app:cv_hasBoundaries="true"
app:cv_dayViewResource="@layout/item_calendar_day"
app:layout_constraintTop_toBottomOf="@id/calendar_date_container"
app:layout_constraintStart_toStartOf="parent"/>
<ImageView
android:id="@+id/calendar_divider_iv"
android:layout_width="match_parent"
android:layout_height="80dp"
android:src="@color/brand_light"
android:layout_marginBottom="17dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
<TextView
android:id="@+id/see_all_date_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="@color/background_white"
android:fontFamily="@font/spoqa_han_sans_neo_medium"
android:text="5월 15일"
android:layout_marginTop="33dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<ImageView
android:id="@+id/calendar_plan_background_iv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:src="@color/background_white"
app:layout_constraintTop_toBottomOf="@id/calendar_calendar_cv"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/calendar_today_plan_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/today_plan"
android:textSize="14sp"
android:textColor="@color/font_black"
android:layout_marginTop="15dp"
android:layout_marginStart="15dp"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
app:layout_constraintTop_toTopOf="@id/calendar_plan_background_iv"
app:layout_constraintStart_toStartOf="parent"/>
<ImageView
android:id="@+id/calendar_plan_dot_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/grey_dot"
android:layout_marginTop="26dp"
app:layout_constraintTop_toBottomOf="@id/calendar_today_plan_tv"
app:layout_constraintStart_toStartOf="@id/calendar_today_plan_tv"/>
<ImageView
android:layout_width="2dp"
android:layout_height="0dp"
android:src="@color/cardview_grey"
app:layout_constraintTop_toBottomOf="@id/calendar_plan_dot_iv"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@id/calendar_plan_dot_iv"
app:layout_constraintEnd_toEndOf="@id/calendar_plan_dot_iv"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/calendar_floating_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
app:backgroundTint="@color/white"
android:src="@drawable/ic_plus"
app:layout_constraintTop_toBottomOf="@id/calendar_calendar_cv"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_calendar_date.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/tv_day_of_week_0"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textStyle="normal"
android:textColor="@color/error"
android:text="일"
android:textSize="12sp"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:gravity="center_horizontal"
android:paddingTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/tv_day_of_week_1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_day_of_week_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textStyle="normal"
android:textColor="@color/line_black"
android:text="월"
android:textSize="12sp"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:gravity="center_horizontal"
android:paddingTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/tv_day_of_week_2"
app:layout_constraintStart_toEndOf="@id/tv_day_of_week_0"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_day_of_week_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textStyle="normal"
android:textColor="@color/line_black"
android:text="@string/tuesday"
android:textSize="12sp"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:gravity="center_horizontal"
android:paddingTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/tv_day_of_week_3"
app:layout_constraintStart_toEndOf="@id/tv_day_of_week_1"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_day_of_week_3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textStyle="normal"
android:textColor="@color/line_black"
android:text="@string/wednesday"
android:textSize="12sp"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:gravity="center_horizontal"
android:paddingTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/tv_day_of_week_4"
app:layout_constraintStart_toEndOf="@id/tv_day_of_week_2"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_day_of_week_4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textStyle="normal"
android:textColor="@color/line_black"
android:text="@string/thursday"
android:textSize="12sp"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:gravity="center_horizontal"
android:paddingTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/tv_day_of_week_5"
app:layout_constraintStart_toEndOf="@id/tv_day_of_week_3"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_day_of_week_5"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textStyle="normal"
android:textColor="@color/line_black"
android:text="@string/friday"
android:textSize="12sp"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:gravity="center_horizontal"
android:paddingTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/tv_day_of_week_6"
app:layout_constraintStart_toEndOf="@id/tv_day_of_week_4"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_day_of_week_6"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textStyle="normal"
android:textColor="@color/saturday_blue"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:text="@string/saturday"
android:textSize="12sp"
android:gravity="center_horizontal"
android:paddingTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_day_of_week_5"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
item_calendar_day.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/item_calendar_day_iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginHorizontal="10dp"
android:layout_marginVertical="10dp"
android:visibility="invisible"
android:src="@drawable/ic_light_blue_dot"/>
<TextView
android:id="@+id/item_calendar_day_tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="14sp"
android:fontFamily="@font/spoqa_han_sans_neo_regular"
android:gravity="center"/>
</androidx.constraintlayout.widget.ConstraintLayout>
변경 후기
custom이 cosmocalendar에 비해 확실히 더 자유롭지만, 그만큼 사용하는데 직접 작성해야 할 코드가 상대적으로 많긴 합니다. RecyclerView를 기반으로 하고 있기 때문에 어느 정도 recyclerview를 사용해본 분들은 이해하기 쉬울 것이라 생각합니다.
+ 다른 사람들은 알고 있을 것 같지만 라이브러리를 사용하다 보면 생기는 이슈나 궁금점들이 stackoverflow나 구글링을 해도 나오지 않는 경우가 있는데, 해당 라이브러리의 github페이지에서 closed된 issue들을 보며 해결할 수 있었습니다. 앞으로도 비슷한 상황에서 이를 적극적으로 활용해야겠다는 생각이 들었습니다.
참고
'Kotlin_study' 카테고리의 다른 글
[HiStory 리팩토링] 2. 카카오 로그인 기능 적용 (0) | 2023.01.03 |
---|---|
[HiStory 리팩토링] 1. 리팩토링을 시작하다 (0) | 2022.12.28 |
[Kotlin] 동기와 비동기 살펴보기 (0) | 2022.07.04 |
[Kotlin] Android font 적용하기 (0) | 2022.07.01 |
[Kotlin] Custom Dialog 사용하기 (0) | 2022.06.30 |