[안드로이드] onClick, onLongClick, onTouch 동시에 구현하기.

조회수 14041회

제가 안드로이드 스튜디오를 기본서를 가지고 공부를 하였는데 실질적으로 어플을 만들려고 하니 기본서 만으로는 모르는 것이 많아서 기초적인 어플 하나를 가지고 단계를 적용하여 만드는 연습을 하고 있습니다. 기초적인 어플로 단순한 메모장 어플을 만들고 있는데 여기서 listview를 사용하여 메모로 추가한 것을 보여주고 있습니다.

리스트 뷰의 내용은 LinearLayout 을 상속받는 item 클래스가 들어가게 됩니다. 이 아이템 클래스에 text 뷰 안에 메모 내용이 들어가고요.

여기서 제가 구현하고 싶은 것은 아이템 뷰(메모내용)을 클릭(onclick) 했을 때, 수정 창이 뜨게 하고, 길게 클릭했을 때나(onLongClick) 옆으로 슬라이드(onTouch)했을 때(스와이프) 했을 때 삭제 버튼이 나오게 하는 것을 구현하고 있습니다.

현재 onTouchEvent는 리니어 레이아웃을 상속한 item 클래스 안에 있고, onClick이나, onLongClick 은 listview를 가지고 있는 MainActivity에서 listview.setOnClickListener, listview.setOnLongClickListener로 구현을 하였습니다.

구글링을 어느정도 해본 결과, onTouchEvent에서 반환값을 [True로 하면 현재 이벤트에서 종료, False로 하면 현재 이벤트를 마무리하고 다음 이벤트로 넘어감] 이라는 것을 보고 이를 적용 시켜 봤는데, True로 설정할 경우 onTouch는 동작을 하는데 onClick이나 onLongClick이 동작하지 않고, False로 하면 onClick이나 onLongClick이 동작을 하고 onTouch가 동작을 하지 않습니다.

이게 터치, 클릭, 롱클릭을 따로 놔서 그런가요?

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

1 답변

  • 일단 onTouch이벤트에서 false를 리턴하는건 맞습니다. 제가 소스를 보지 못해서 정확한 답변은 드릴수 없지만 제 생각으로는

    터치, 클릭, 롱클릭 이벤트를 각각 처리해주셔서 다른 이벤트를 받지 못한것 같습니다.

    제가 작성한 코드를 바탕으로 설명드리겠습니다. 일단 터치 했을때 스와이프 처리를 위한 클래스를 작성합니다.

    package com.example.user.malendar;
    
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    public class SwipeDetector implements View.OnTouchListener {
        public final int HORIZONTAL_MIN_DISTANCE = 40; 
        public final int VERTICAL_MIN_DISTANCE = 80;
    
        public static enum Action {
            LR, // Left to Right
            RL, // Right to Left
            TB, // Top to bottom
            BT, // Bottom to Top
            None // when no action was detected
        }
    
        private static final String logTag = "SwipeDetector";
        private static final int MIN_DISTANCE = 100;
        private float downX, downY, upX, upY;
        private Action mSwipeDetected = Action.None;
    
        public boolean swipeDetected() {
            return mSwipeDetected != Action.None;
        }
    
        public Action getAction() {
            return mSwipeDetected;
        }
    
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    downX = event.getX();
                    downY = event.getY();
                    mSwipeDetected = Action.None;
                    return false; // allow other events like Click to be processed
                }
                case MotionEvent.ACTION_MOVE: {
                    upX = event.getX();
                    upY = event.getY();
    
                    float deltaX = downX - upX;
                    float deltaY = downY - upY;
    
                    // horizontal swipe detection
                    if (Math.abs(deltaX) > HORIZONTAL_MIN_DISTANCE) {
                        // left or right
                        if (deltaX < 0) {
                            Log.i(logTag, "Swipe Left to Right");
                            mSwipeDetected = Action.LR;
                            return true;
                        }
                        if (deltaX > 0) {
                            Log.i(logTag, "Swipe Right to Left");
                            mSwipeDetected = Action.RL;
                            return true;
                        }
                    } else
    
                        // vertical swipe detection
                        if (Math.abs(deltaY) > VERTICAL_MIN_DISTANCE) {
                            // top or down
                            if (deltaY < 0) {
                                Log.i(logTag, "Swipe Top to Bottom");
                                mSwipeDetected = Action.TB;
                                return false;
                            }
                            if (deltaY > 0) {
                                Log.i(logTag, "Swipe Bottom to Top");
                                mSwipeDetected = Action.BT;
                                return false;
                            }
                        }
                    return true;
                }
            }
            return false;
        }
    }
    

    안드로이드에서는 터치->클릭 순으로 이벤트를 먼저받으므로 단순 터치였을경우에는 클릭이벤트를 받을 수 있게끔 false를 리턴시켜줍니다. 그리고 좌우로 스와이프 했을때 어떠한 처리를 하려고 하였으니까 스와이프된 상황일때는 클릭을 처리할 필요가 없으므로 true를 리턴시켜줍니다.

    그리고 리스트뷰에 touch리스너를 등록하고 아이템 클릭 리스너와 아이템 롱클릭리스너를 등록합니다. 이때 아이템 클릭 리스너와 롱클릭 리스너에서 각각 터치 이벤트를 처리해주어야합니다.

    final SwipeDetector swipeDetector = new SwipeDetector();
    lv.setOnTouchListener(swipeDetector);
            lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    if (swipeDetector.swipeDetected()){
                        //스와이프 처리 
                    } else {
                        // 클릭 처리
                        Log.i("Swipe","SHOOOOOORT");
                    }
                }
            });
            lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {
                    if (swipeDetector.swipeDetected()){
                        // 스와이프 처리 
                    } else {
                        //롱클릭 처리 
                        Log.i("Swipe","LOOOONG");
                    }
                    return true;
                }
            });
        ```
    
    
    
    

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

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

(ಠ_ಠ)
(ಠ‿ಠ)