android MaterialCalendarView 커스텀

🔥🔥🔥·2024년 11월 17일
post-thumbnail

원하는 디자인은 다음과 같다

  • title을 yyyy년 mm월 형식으로 변경
  • 오늘 날짜의 색상 변경
  • 선택한 날짜는 특정 drawable 표시
  • 선택 가능 날짜는 다음날부터 7일까지 가능(오늘 제외)
  • 선택 불가능한 날짜 text 색상 및 그 외 요소 별 text, size 등 적용

이정도인것 같다

1. title을 yyyy년 mm월 형식으로 변경, 스타일 변경

커스텀


    /**
     * CalendarView Custom : 년월 타이틀 형식 변경
     */
    inner class CustomTitleFormatter : TitleFormatter {
        override fun format(day: CalendarDay?): CharSequence {
            val simpleDateFormat =
                SimpleDateFormat("yyyy년 MM월"), Locale.KOREA)

            return simpleDateFormat.format(Calendar.getInstance().time)
        }

    }

스타일 변경

    <style name="CalendarWidgetHeader">
        <item name="android:textSize">18sp</item>
        <item name="android:textColor">@color/원하는 색상</item>
        <item name="android:textFontWeight">600</item>
    </style>

적용

with(binding.calendarView) {
	setHeaderTextAppearance(R.style.CalendarWidgetHeader)
	setTitleFormatter(CustomTitleFormatter())
}

2.오늘 날짜의 색상 변경

커스텀

    /**
     * CalendarView Custom : 오늘 날짜의 색상 설정
     */
    private class TodayDecorator(context: Context) : DayViewDecorator {
        private var date = CalendarDay.today()
        private val color = ContextCompat.getColor(context,R.color.원하는 색상)

        override fun shouldDecorate(day: CalendarDay): Boolean {
            return day.equals(date)
        }

        override fun decorate(view: DayViewFacade) {
            view.addSpan(object: ForegroundColorSpan(color){})
        }
    }

적용

val todayDecorator = TodayDecorator(context)
binding.calendarView.addDecorators(todayDecorator)

3.선택한 날짜는 특정 drawable 표시

커스텀


    /**
     * CalendarView Custom : 선택한 날짜 drawable 설정
     */
    private inner class DayDecorator(context: Context, private val selectedDate: CalendarDay) : DayViewDecorator {
        private val drawable = ContextCompat.getDrawable(context,R.drawable.ic_calendar_selector) // 원하는 이미지를 여기에 작성

        override fun shouldDecorate(day: CalendarDay): Boolean {
            return day.equals(selectedDate)
        }

        override fun decorate(view: DayViewFacade) {
            view.setSelectionDrawable(drawable!!)
        }
    }

DayDecorator는 선택한 날짜가 변경될때마다 반영해주어야한다. 이 말은 setOnDateChangedListener 내부에 기존 decorator는 삭제해주는 코드들과 함께 + addDecorators 를 작성해주어야한다는 뜻이다.

이때 주의해야할건 함께 적용해주어야 하는 다른 decorator들도 갖고 있다면, Listener 내부에 addDecorators 에 작성할때 같이 작성해주어야 날짜가 변경되어도 기존 decorator 가 사라지지 않는다.

나같은 경우는 todayDecorator 도 갖고 있어서 이걸 함께 작성해주었다.


        with(binding.calendarView){
            
            val todayDecorator = TodayDecorator(context)
            // 내일날짜를 기본값으로 선택해주고 있으므로, drawable을 내일날짜에 적용할 수 있도록 했다.
            addDecorators(todayDecorator,
                DayDecorator(context, tomorrow))
                
            // 선택된 날짜 변경 시, Listener
            setOnDateChangedListener { widget, date, selected ->
            
                // decorator 초기화
                removeDecorators() // Remove all decorators
                invalidateDecorators() // Invalidate decorators after one has changed internally.

                // dayDecorator 재생성 및 적용. todayDecorator도 다시 작성해주었다. 
                val dayDecorator = DayDecorator(context, date)
                addDecorators(todayDecorator, dayDecorator)
            }
         }

4.선택 가능 날짜는 다음날부터 7일까지 가능(오늘 제외)


            // 선택 가능한 날짜 범위: from
            val tomorrow = CalendarDay.from(LocalDate.now().plusDays(1)) // 내일부터이므로 1을 더해줌

            // 선택 가능한 날짜 범위: to
            val maxCalendar = Calendar.getInstance()
            maxCalendar.add(Calendar.DAY_OF_YEAR, 7)

            state().edit()
                .setMinimumDate(
                    CalendarDay.from(
                        tomorrow.year,
                        tomorrow.month,
                        tomorrow.day
                    )
                ).setMaximumDate(
                    CalendarDay.from(
                        maxCalendar.get(Calendar.YEAR),
                        maxCalendar.get(Calendar.MONTH) + 1,
                        maxCalendar.get(Calendar.DAY_OF_MONTH)
                    )
                )
                .setCalendarDisplayMode(CalendarMode.MONTHS)
                .commit()

5.선택 불가능한 날짜 text 색상 및 그 외 요소 별 text, size 등 적용

이부분은 아래 참조 사이트 중 https://develop-oj.tistory.com/74 님께서 작성을 상세하게 해주셔서 큰 도움이 되었다. 나는 range 형식의 달력이 아니라, 필요한 부분만 사용했다.

color/calendar_text_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 선택 불가능한 영역 -->
    <item
        android:state_activated="false" android:state_enabled="false"
        android:color="@color/light_gray" />
    <!-- 선택된 경우-->
    <item
        android:state_checked="true"
        android:color="@color/fa" />

    <!-- 선택되지 않은 경우-->
    <item
        android:state_checked="false"
        android:color="@color/title" />

</selector>
themes.xml

    <style name="CalenderViewCustom" parent="Theme.AppCompat">
        <item name="android:textColor">@color/calendar_text_color</item>
    </style>
view 적용
                    <com.prolificinteractive.materialcalendarview.MaterialCalendarView
                        android:id="@+id/calendar_view"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        app:mcv_selectionMode="single"
                        app:mcv_firstDayOfWeek="monday"
                        app:mcv_showOtherDates="all"
                        android:theme="@style/CalenderViewCustom"
                        app:mcv_dateTextAppearance="@style/CalenderViewDateCustomText"
                        app:mcv_weekDayTextAppearance="@style/CalenderViewWeekCustomText"
                        app:mcv_selectionColor="@color/clear_blue" />

참조 사이트
https://github.com/prolificinteractive/material-calendarview
https://develop-oj.tistory.com/74
https://devgeek.tistory.com/75

0개의 댓글