[Android] Recycler View item 클릭 이벤트 적용 , adapter 외부에서 클릭 이벤트 적용하기

 

[개발 일지]

 

kotlin으로 일정 관리 앱을 개발 중이였다.

일정 관리 앱에서 커스텀으로 제작한 캘린더를 사용하는데(리싸이클러뷰 사용) ,

각 날짜를 클릭하면 이전에 포스팅한 Sliding Up Panel Layout이 나오게 하려했다.

해당 Layout은 adapter 내부에서 나타나는 것이 아닌 전체 fragment에서 나타나도록 동작하는게 필요했다.

 

일반적으로 adapter 내부의  item은 view를 감싸는 holder로 click 이벤트가 동작하도록 한다.

 

override fun onBindViewHolder(holder: CalenderItemHolder, position: Int) {
    holder.binding.root.setOnClickListener {

    }
    ......
}

 

item을 클릭하면 위와 같은 방식으로 setOnClickListener 내부 코드가 동작한다.

하지만 adapter 내부가 아닌 외부 fragment에서 Sliding Layout이 나타나게 하려면 외부에서 item 클릭 이벤트가 필요했다.

 

[addOnItemTouchListener 사용하기]

 

addOnItemTouchListener

 

만들어둔 adapter를 recycler VIew에 연결할때 apply를 사용한다.

여기서 adapter를 연결해주는 코드 밑에 addOnItemTouchListener를 추가하고,

object로 RecyclerView.OnItemTouchListener를 작성한다.

 

        binding.fragCalenderRecycler.apply {
            adapter = calendarAdapter

            addOnItemTouchListener(object :RecyclerView.OnItemTouchListener{
                override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
                    //터치 동작을 가로챔

                }

                override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}
                override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
            })
        }

 

Object is not abstract and does not implement abstract member public abstract fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean defined in androidx.recyclerview.widget.RecyclerView.OnItemTouchListener

 

위와 같은 메시지가 나오는데,  implement members를 해야한다.

관련 개발 가이드 : RecyclerView.OnItemTouchListener  |  Android Developers

 

RecyclerView.OnItemTouchListener  |  Android Developers

androidx.car.app.managers

developer.android.com

 

3가지 메서드를 implement해주어야 하는데 그 중에서 onInterceptTouchEvent를 사용한다.

터치 이벤트가 발생하면 중간에서 처리 방식을 가로채는 메서드이다.

 

override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
    //터치 동작을 가로챔
    val child = rv.findChildViewUnder(e.x,e.y)
    if (child!=null){
        val position = rv.getChildAdapterPosition(child)
        val view = rv.layoutManager?.findViewByPosition(position)
        view?.setOnClickListener {
            if(state==SlidingUpPanelLayout.PanelState.COLLAPSED){ //열기
                binding.slideFrame.panelState = SlidingUpPanelLayout.PanelState.ANCHORED
            }else if (state == SlidingUpPanelLayout.PanelState.EXPANDED) { //닫기
                binding.slideFrame.panelState = SlidingUpPanelLayout.PanelState.COLLAPSED
            }
        }
    }
    return false
}

 

터치 동작을 가로채서 child 변수를 선언한다.

child 변수는 리싸이클러뷰의 좌표를 나타내고 position을 통해서 해당 item의 index에 접근한다.

이후에는 view를 클릭 시 slidingUpPanelLayout이 열리거나 닫히도록 동작하게 했다.

중요한 점은 false를 반드시 return 해주어야 한다.

 

override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}

 

사용하지 않는 메서드는 닫아준다.

 

item 클릭 시 슬라이딩 layout 나타남

 

해굘