안드로이드 RecyclerView 빈공간 클릭 이벤트?

조회수 1379회

RecyclerView 아이템을 클릭했을때의 이벤트가 아닌

RecyclerView 의 빈공간을 클릭했을때 이벤트를 잡고 싶어서 (RecyclerView의 크기는 전체로 잡았습니다)

RecyclerView 에 setOnClickListener를 해봤지만 빈공간 클릭했을때 이벤트를 잡을수가 없네요

혹시 RecyclerView의 아이템이 아닌 빈공간을 클릭했을때 이벤트를 받을수 없을까요?

리니어레이아웃으로 감싸고 그 리니어레이아웃에서 setOnClickListener를 해봤지만 리니어레이아웃에서 클릭이벤트를 받을려면 리니어 안의 뷰가 없어야 된다고 하더라고요

아 참고로 RecyclerView 의 아이템 클릭 이벤트와 롱 클릭 이벤트도 받아서 처리 하고 있습니다

감사합니다^

  • (•́ ✖ •̀)
    알 수 없는 사용자

1 답변

  • 클릭 이벤트는 View 에서 지원하는 기본적인 기능으로써 생각 할 수 있습니다. RecyclerViewViewGroup 을 extend 하고, ViewGroupView 를 extend 합니다. 결론적으로, 클릭 이벤트가 View 클래스에서 처리되기 때문에 터치이벤트가 최상위 클래스인 View 까지 전달 되어야 클릭 이벤트를 사용할 수 있다 라고 정리 할 수 있습니다.

    RecyclerView 코드를 보면, 터치 이벤트를 처리하는 onInterceptTouchEventonTouchEvent 에서 scroll 에 대한 동작과 OnItemTouchListener 에 대한 동작을 처리하고 super 클래스의 메소드 호출은 하지 않고 있습니다. 따라서 클릭 이벤트 자체가 발생하지 않기 때문에 setOnClickListener 를 설정하여도 onClick 이 호출 되지 않습니다.

    RecyclerView 자체에 클릭 이벤트를 등록하는 것이 일반적인 경우는 아니지만, 아래와 같이 처리 할 수 있을 것 같습니다.

    class TestRecyclerView(context: Context?, attrs: AttributeSet?) : RecyclerView(context, attrs) {
    
        private var clickTriggerRunnable: ClickTriggerRunnable? = null
        private val touchSlop: Int = ViewConfiguration.get(context).scaledTouchSlop
        private var touchStartPointX = 0.0f
        private var touchStartPointY = 0.0f
    
        override fun onTouchEvent(e: MotionEvent?): Boolean {
            e?.run {
                when (action) {
                    MotionEvent.ACTION_DOWN -> {
                        touchStartPointX = x
                        touchStartPointY = y
    
                        //클릭 이벤트 처리를 위한 runnable 실행
                        clickTriggerRunnable = ClickTriggerRunnable()
                        handler.postDelayed(clickTriggerRunnable, ViewConfiguration.getTapTimeout().toLong())
                    }
                    MotionEvent.ACTION_MOVE -> {
                        val deltaX = Math.abs(touchStartPointX - x)
                        val deltaY = Math.abs(touchStartPointY - y)
    
                        //클릭에 대한 터치 영역을 벗어날 경우 callback 취소
                        clickTriggerRunnable?.let {
                            if (deltaX > touchSlop || deltaY > touchSlop) {
                                handler.removeCallbacks(clickTriggerRunnable)
                                clickTriggetRunnable = null
                            }
                        }
                    }
                    MotionEvent.ACTION_UP -> {
                        clickTriggerRunnable?.let {
                            val triggered = it.isClickTriggered
                            handler.removeCallbacks(it)
                            clickTriggerRunnable = null
    
                            return when {
                                triggered -> {
                                    //여기에 원하는 클릭 동작을 구현
                                    true
                                }
                                else -> super.onTouchEvent(this)
                            }
                        }
                    }
                    else -> super.onTouchEvent(e)
                }
            }
            return super.onTouchEvent(e)
        }
    
        inner class ClickTriggerRunnable : Runnable {
    
            var isClickTriggered = false
    
            override fun run() {
                isClickTriggered = true
            }
        }
    }
    
    • (•́ ✖ •̀)
      알 수 없는 사용자

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)