[Android] Adapter 내부에서 ClickListener 선언하기 + 개발일지

 

[개발 일지]

 

한 달 주기 일정 관리 앱을 개발 중이었다.

 

개발 기능!

 

1. Recycler View가 Init 될 때 캘린더의 현재 날짜 색상 변경 기능

2. 다른 날짜를 클릭 시 그 날짜의 색상 변경 기능

3. 한 번에 한 가지의 날짜만 선택 가능해야 한다.

 

우선 아래 블로그 글에서 큰 도움을 받아서 출처를 남긴다.

 

[Android] 아이템 하나만 선택 가능한 리사이클러뷰 만드는 법 + 데이터바인딩 적용 (tistory.com)

 

[Android] 아이템 하나만 선택 가능한 리사이클러뷰 만드는 법 + 데이터바인딩 적용

리사이클러뷰를 만들다 보면 한 아이템을 선택해서 배경색이나 글자색 등을 바꾼 뒤 다른 아이템을 누르면 이전에 선택했던 아이템을 원래대로 바꾸고 새로 선택한 아이템의 배경색 등을 바꾸

onlyfor-me-blog.tistory.com

 

캘린더를 CustomCalendar라는 class에서 제작을 한다.

for 문을 돌면서 날짜를 하나씩 추가하는 과정인데,

isToday 변수를 만들어서 오늘 날짜와 추가될 날짜와 달이 같다면 true가 저장된다.

isToday가 true일 경우 선택 될 변수를 뜻하는 isSelected를 true로, 

마지막으로 추가된 값의 인덱스를 todayIndex에 저장한다.

 

for (i in 1..calendar.getActualMaximum(Calendar.DATE)) {
    val isToday = (currentDay==i && currentMonth==dateMonth)
    dateList.add(DayData(i,
        isSelected = isToday,
        monthIndex = 0,
        null,
        null
    ))
    if(isToday){
        todayIndex = dateList.lastIndex
    }
}

 

앞에서 생성한 CustomCalendar은 mainViewModel이라는 ViewModel에서 관리된다.

 

lateinit var currentDate : CustomCalendar

 

viewModel에서 todayIndex를 받아오고,

 

val todayIndex = mainActivity.viewModel.currentDate.todayIndex

 

adapter를 생성할 때 넘겨준다.

 

adapter = CalendarListAdapter(mainActivity,mainActivity.viewModel.currentDate.dateList,todayIndex)

 

이제 현재 선택 된 selectedPosition으로 오늘의 index를 넣어준다.

 

private var selectedPosition = todayIndex

 

준비가 끝났으니 내부 코드를 작성한다.

 

우선 클릭 이벤트를 만들어준다.

 

interface OnItemClickListener{
    fun onItemClick(item : DayData,position: Int)
}
fun setOnItemClickListener(listener: OnItemClickListener){
    this.onItemClickListener = listener
}

 

Item을 클릭 했을 때 onItemClick 이벤트로 외부로 데이터를 전송해준다.

 

ItemHolder에서 dataSet을 처리해야 하므로 inner 클래스로 만들어 준 후에  bind 함수를 제작한다,

 

inner class CalendarListItemHolder(val binding: ItemCalendarHorizontalBinding) :
    RecyclerView.ViewHolder(binding.root) {
    fun bind(item: DayData) {
    
    }

 

bind 함수는 onBindViewHolder에서 사용되며 현재 관리할 데이터를 반환한다.

'

holder.bind(dataSet[position])

 

bind 함수를 만들어준 이유는 함수 내에서 절댓값 포지션인 absoluteAdapterPosition을 사용할 수 있어서다.

절댓값 포지션 (dataSet에 해당하는 진짜 position)을 통해서

item이 클릭 되었을 때와 클릭되지 않았을 때를 구분하기 위한 함수를 제작한다.

 

@SuppressLint("ResourceAsColor")
private fun ItemCalendarHorizontalBinding.setChecked() =
    itemBack.setBackgroundColor(ContextCompat.getColor(mainActivity, R.color.color_type1))

@SuppressLint("ResourceAsColor")
private fun ItemCalendarHorizontalBinding.setUnchecked() =
    itemBack.setBackgroundColor(ContextCompat.getColor(mainActivity, R.color.color_type3))

 

위의 함수를 통해서 클릭 되었을 경우 setChecked 함수로 색상 변경,

클릭되지 않았을 경우 setUnChecked 함수로 기존 색상으로 되돌리기를 적용한다.

 

이제 bind 함수 내부에서 선택된 포지션이 절댓값 포지션일 경우 색상을 변경한다.

처음으로 선택 될 데이터는 오늘 날짜를 표시하는 todayIndex이다.

 

fun bind(item: DayData) {
    if(selectedPosition==absoluteAdapterPosition){
        binding.setChecked()
    }else{
        binding.setUnchecked()
    }

 

이제 초기값을 설정했으니 데이터를 클릭했을 때 이벤트를 처리해야 한다.

 

이전에 만들어준 onItemClickListener가 초기화되었는지 확인한 후에 클릭 이벤트를 적용한다.

 

if(onItemClickListener!=null){
    binding.root.setOnClickListener {
        onItemClickListener?.onItemClick(item, position = absoluteAdapterPosition)
        if (selectedPosition!=absoluteAdapterPosition){
            binding.setChecked()
            notifyItemChanged(selectedPosition)
            selectedPosition = absoluteAdapterPosition
        }
    }
}

 

현재 포지션과 선택 된 포지션이 다를 경우는 새로운 데이터를 선택했다는 것이다.

현재 데이터의 색상을 변경해주고 - setChecked(),

이전 데이터의 변경 사항을 알리고 -  notifyItemChanged(),

선택된 포지션을 현재 포지션으로 변경한다. - selectedPosition = absoluteAdapterPosition

 

마지막으로 클릭 이벤트를 adapter에서 적용한다.

클릭 데이터에 대한 처리는 나중에 작성하고 우선 정확한 값이 찍히는지 Log로 확인하는 코드를 작성했다.

 

adapter = CalendarListAdapter(mainActivity,mainActivity.viewModel.currentDate.dateList,todayIndex).apply {
    setOnItemClickListener(object : CalendarListAdapter.OnItemClickListener {
        override fun onItemClick(item: DayData, position: Int) {
            Log.d("item",position.toString()+":"+item.day)
        }

    })
}

 

 

개발 기능이 잘 적용되었는지 테스트한다.

실행한 날인 2022년 12월 1일로 view가 이동한다.

 

29일을 클릭하자 29일로 데이터 색상이 변경되었다.

 

 

 

 

Log 값도 제대로 찍힌다. 

정확한 데이터가 잘 전달된 것 같다.