cheewr85 / Kotlin-Android-Basic

CodeLab 기반으로 기본기 다시보기
3 stars 0 forks source link

RecyclerView + ClickHandler #33

Closed cheewr85 closed 2 years ago

cheewr85 commented 2 years ago

[질문]

RecyclerView에서 ClickHandler를 위해 Listener 처리와 관련해서 정리

cheewr85 commented 2 years ago
// item click listener에 대한 클래스, 콜백을 인자로 넣음
class SleepNightListener(val clickListener: (sleepId: Long) -> Unit) {
    // 보여지는 list item을 클릭했을 때 onClick을 호출함, SleepNight의 타입 night를 넘김, 콜백으로 night의 id값을 넘김
    fun onClick(night: SleepNight) = clickListener(night.nightId)
}
<data>
        <variable
            name="sleep"
            type="com.example.android.trackmysleepquality.database.SleepNight" />

        <variable
            name="clickListener"
            type="com.example.android.trackmysleepquality.sleeptracker.SleepNightListener" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="@{() -> clickListener.onClick(sleep)}">
class SleepNightAdapter(val clickListener: SleepNightListener) : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        // data에서 position의 값을 가져왔으나 ListAdapter 및 DiffUtil 사용해서 item만을 쓰면 됨
        val item = getItem(position)
        // viewHolder inner class에 정의한 함수 활용해서 처리함
        holder.bind(getItem(position)!!,clickListener)

    }

....

// image, textview가 있는 해당 itemView에 대한 ViewHolder를 정의함
    class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root) {

        fun bind(
            item: SleepNight,
            clickListener: SleepNightListener,
        ) {
            // sleep에 item을 할당함(db에서 불러온 값)
            binding.sleep = item
            // 최적화를 위해 호출
            binding.executePendingBindings()
            // clicklistener를 할당해줌
            binding.clickListener = clickListener
        }
// 앞서 만든 Adapter 생성
        val adapter = SleepNightAdapter(SleepNightListener { nightId ->
//            Toast.makeText(context, "${nightId}", Toast.LENGTH_LONG).show()
            // viewModel에서 클릭 이벤트 리스너 등록함 리스너에서 받은 id를 넘김
            sleepTrackerViewModel.onSleepNightClicked(nightId)
        })
// Detail에 가기 위해 쓴 LiveData 변수
    private val _navigateToSleepDetail = MutableLiveData<Long>()
    val navigateToSleepDetail
      get() = _navigateToSleepDetail

    // id를 넘겨 Detail로 넘아가는 클릭 핸들러 함수
    fun onSleepNightClicked(id: Long) {
        _navigateToSleepDetail.value = id
    }

    // navigating이 끝나면 value를 초기화하는 함수
    fun onSleepDetailNavigated() {
        _navigateToSleepDetail.value = null
    }
        // 앞서 만든 Adapter 생성
        val adapter = SleepNightAdapter(SleepNightListener { nightId ->
//            Toast.makeText(context, "${nightId}", Toast.LENGTH_LONG).show()
            // viewModel에서 클릭 이벤트 리스너 등록함 리스너에서 받은 id를 넘김
            sleepTrackerViewModel.onSleepNightClicked(nightId)
        })

....

// 아이템이 클릭될 때 navigating을 위해 variable의 상태를 Observer하는 것을 추가함
        sleepTrackerViewModel.navigateToSleepDetail.observe(viewLifecycleOwner, Observer { night ->
                night?.let {
                    this.findNavController().navigate(SleepTrackerFragmentDirections.actionSleepTrackerFragmentToSleepDetailFragment(night))
                    sleepTrackerViewModel.onSleepDetailNavigated()
                }
        })