[Android] CosmoCalendar/캘린더뷰 커스텀 (feat. umc 해커톤)

구민지·2022년 7월 14일
0
post-thumbnail

이번 7/1-7/2에 진행된 umc 해커톤에서 우리 팀 어플의 핵심기능 중 하나인 ✨범위 형태로 날짜를 선택 후 리사이클러뷰로 출력✨을 맡아 구현하게 되었다.

덕분에 여러가지 커스텀된 캘린더뷰를 직접 사용해보고 연습해 볼 수 있었고, 캘린더뷰에 대해 공부를 정말 깊게 했다. 그리고 내가 원하는 형태로 커스텀된 캘린더도 찾을 수 있었다!

내가 원하던 형태로 커스텀 되어있는 CosmoCalendar를 사용했다 🙌

📌 깃허브
https://github.com/koominji/CustomCalendar_umc_hackathon

💖 시연영상

velog는 동영상 첨부가 안되나..;?

해커톤 목표

  1. 일정조율생성 화면 만들기
  2. 캘린더 화면에서 범위 형태로 날짜를 선택
  3. 선택된 날짜들을 recyclerView에 월, 일, 요일이 출력되도록 하기

💖 CosmoCalendar

range 형태로 날짜를 선택할 수 있는 CosmoCalendar를 사용했다.

1. build.gradle(모듈단위) >> dependencies 에 추가


    // cosmoCalendar
    implementation 'com.github.applikeysolutions:cosmocalendar:1.0.4'

2. cosmoCalendar 부분 코드 (xml)

<!-- cosmo calendar -->
            <com.applikeysolutions.cosmocalendar.view.CalendarView
                android:id="@+id/calendar_view"
                android:layout_width="match_parent"
                android:layout_height="500dp"
                app:connectedDayIconPosition="top"
                app:currentDayIconRes="@drawable/round_shape_img"
                app:currentDaySelectedIconRes="@drawable/border_top_bottom"
                app:currentDayTextColor="@color/appMainColor"
                app:firstDayOfTheWeek="sunday"
                app:layout_constraintTop_toTopOf="parent"
                app:orientation="horizontal"
                app:selectedDayBackgroundColor="@color/appMainColor"
                app:selectedDayBackgroundEndColor="@color/appMainColor"
                app:selectedDayBackgroundStartColor="@color/appMainColor"
                app:selectedDayTextColor="#FFFFFF"
                app:selectionType="range"
                app:weekendDayTextColor="#ef4550" />

여기서 중요한건 ✨selectionType✨
CosmoCalendar 여기서도 확인가능하지만,

  • single
  • multiple
  • range

등등 다양한 형태로 선택이 가능하다

3. 선택된 날짜 Log로 확인 (kt)

        
        binding.calendarView.isShowDaysOfWeekTitle = false
        binding.calendarView.selectionManager = RangeSelectionManager(OnDaySelectedListener {
            if (binding.calendarView.selectedDates.size <= 0) return@OnDaySelectedListener
            Log.d("selected dates", "${binding.calendarView.selectedDays}")
        })

4. RVAdapter _ 해커톤ver



class SelectedDatesRVAdapter(val dates:List<Day>) : RecyclerView.Adapter<SelectedDatesRVAdapter.ViewHolder>() {

    inner class ViewHolder(val binding: CreateSelectedDateRvItemBinding):RecyclerView.ViewHolder(binding.root){

        fun bind(dates: Day){
            var temp=dates.toString()
            
            Log.d("selectedDate",temp)
            
            binding.selectedDateMonth.text= temp.slice(11..14) //월
            binding.selectedDateDay.text= temp.slice(15..17) //일
            binding.selectedDateDayOfWeek.text= temp.slice(8..11) //요일
        }
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
        val binding:CreateSelectedDateRvItemBinding= CreateSelectedDateRvItemBinding.inflate(LayoutInflater.from(viewGroup.context),viewGroup,false)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val binding = (holder as SelectedDatesRVAdapter.ViewHolder).binding
        holder.bind(dates[position])
        binding.selectedDateRvRoot.setOnClickListener {
            Log.d("clicked","${position}")
        }
    }

    override fun getItemCount(): Int = dates.size
}

허허........

   fun bind(dates: Day){
            var temp=dates.toString()
            
            Log.d("selectedDate",temp)
            
            binding.selectedDateMonth.text= temp.slice(11..14) //월
            binding.selectedDateDay.text= temp.slice(15..17) //일
            binding.selectedDateDayOfWeek.text= temp.slice(8..11) //요일
        }

음 이건 뭐냐면,,선택된 날짜를 Log로 보니 이런 모습이길래 👇

필요한 월, 일, 요일 부분만 무식하게 슬라이싱했다 ㅎㅋㅎㅋ😅 하면서도 절대 좋은 방법은 아니라는 생각이 들었다,,, 그냥 임시방편,,ㅋㅅㅋ 일단 해커톤에서는 시간이 없으니 이렇게 했는데
(안드 개발하면서 동시에 pm이여서 진짜 너무 정신없엇다,,)
앞으로 이 부분에서 서버랑 협업도 해야하고 다른 기능 구현할것도 고려해서
👉 이 부분은 해커톤 이후에 !!!!꼭!!!! 바꿔야지 생각했음 👈

4-2. 📌 RVAdapter _ 해커톤 이후 수정한ver 📌


class SelectedDatesRVAdapter(val dates:List<Day>) : RecyclerView.Adapter<SelectedDatesRVAdapter.ViewHolder>() {

    inner class ViewHolder(val binding: CreateSelectedDateRvItemBinding):RecyclerView.ViewHolder(binding.root){

        fun bind(dates: Day){

            val year = dates.calendar.get(YEAR)
            val month = dates.calendar.get(MONTH)+1
            val day = dates.calendar.get(DAY_OF_MONTH)
            val dayOfWeek = dates.calendar.getDisplayName(DAY_OF_WEEK, LONG_FORMAT, Locale.KOREAN)

            binding.selectedDateMonth.text= month.toString()+"월" //월
            binding.selectedDateDay.text= day.toString() //일
            binding.selectedDateDayOfWeek.text= dayOfWeek //요일
        }
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
        val binding:CreateSelectedDateRvItemBinding= CreateSelectedDateRvItemBinding.inflate(LayoutInflater.from(viewGroup.context),viewGroup,false)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val binding = (holder as SelectedDatesRVAdapter.ViewHolder).binding
        holder.bind(dates[position])
        binding.selectedDateRvRoot.setOnClickListener {
            Log.d("clicked","${position}")
        }
    }

    override fun getItemCount(): Int = dates.size
}

이렇게 수정했다 👇🤩

  fun bind(dates: Day){

            val year = dates.calendar.get(YEAR)
            val month = dates.calendar.get(MONTH)+1
            val day = dates.calendar.get(DAY_OF_MONTH)
            val dayOfWeek = dates.calendar.getDisplayName(DAY_OF_WEEK, LONG_FORMAT, Locale.KOREAN)

            binding.selectedDateMonth.text= month.toString()+"월" //월
            binding.selectedDateDay.text= day.toString() //일
            binding.selectedDateDayOfWeek.text= dayOfWeek //요일
        }

Log.d("dayOfWeek",dates.calendar.get(DAY_OF_WEEK).toString()) 로 확인해보면

월요일 : 1
화요일 : 2
수요일 : 3
목요일 : 4
금요일 : 5
토요일 : 6
일요일 : 7

DAY_OF_WEEK 는 요일별로 int 형으로 return 되는데
🤔 이걸 바로 요일로 출력할수는 없나..? 🤔 싶어 찾아보니

dates.calendar.getDisplayName(DAY_OF_WEEK, LONG_FORMAT, Locale.KOREAN)
👉 getDisplayName 을 사용하면 바로 요일을 출력할 수 있다 👍

5. RVAdapter연결, 선택된 날짜들로 recyclerView 구성 (kt)


    lateinit var dates: List<Day>
    
    
    override fun onCreate(savedInstanceState: Bundle?) {
    
    		// (중략)
            
             // 선택된 dates
            dates = binding.calendarView.selectedDays

            // 선택된 날짜 recyclerview
            val selectedDatesRVAdapter = SelectedDatesRVAdapter(dates)
            binding.createSelectedDateRv.adapter = selectedDatesRVAdapter

            val selectedDatesLayoutManager = LinearLayoutManager(this)
            selectedDatesLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
            binding.createSelectedDateRv.layoutManager = selectedDatesLayoutManager
            
            
    		// (중략)

        }
    

calendarView.selectedDays 로 선택된 날짜를 받아온다

👉 선택된 모든 날짜가 List<Day> 형태로 return 된다

그렇기 때문에 선택된 날짜를 넣을 lateinit var dates: List<Day> 또한 List<Day> 형태로 선언한다

cf. RVAdapter 에서도 class SelectedDatesRVAdapter(val dates:List<Day>) : ....

🤔 평소에 arrayList,mutableListOf 만 주로 사용했는데 List는 좀 낯설었다

이번 해커톤으로

캘린더에 대해 정말정말정말 많이 공부했고 역시 프로젝트하면서 제일 많이 배우고 빠르게 성장한다고 생각했다 .......... ! 👩‍💻


벨로그에 글 처음쓰는데 이런거 써놓으면 누군가에게 도움이 되려나 ㅎㅅㅎ 암튼 끝!

0개의 댓글