ProgramingTip

onTouchEvent ()에서 이동과 클릭을 구별하는 방법은 무엇입니까?

bestdevel 2020. 11. 6. 19:01
반응형

onTouchEvent ()에서 이동과 클릭을 구별하는 방법은 무엇입니까?


내 응용 프로그램에서 이동 및 클릭 이벤트를 모두 처리해야합니다.

클릭은 하나의 ACTION_DOWN 작업, 여러 ACTION_MOVE 작업 및 하나의 ACTION_UP 작업의 시퀀스입니다. 이론적으로 ACTION_DOWN 이벤트가 발생하면 다음 ACTION_UP 이벤트가 발생하면 사용자가 방금보기를 클릭했음을 의미합니다.

그러나 실제로이 시퀀스는 일부 장치에서 작동하지 않습니다. 내 Samsung Galaxy Gio에서보기 : ACTION_DOWN, ACTION_MOVE, ACTION_UP을 여러 번 클릭하면 연속 시퀀스가 ​​나타납니다. 즉, ACTION_MOVE 액션 코드로 예상치 못한 OnTouchEvent가 발생합니다. ACTION_DOWN-> ACTION_UP 시퀀스를 전혀 (또는 거의 전혀)

또한 클릭 위치를 제공하지 않으므로 OnClickListener를 사용할 수 없습니다. 검색 클릭 이벤트를 감지하고 이동과 어떻게 다릅니 까?


여기에 매우 간단하고 손가락이 필요한 것에 대해 걱정할 필요가 없습니다. 클릭을 기반으로하는 경우 클릭과 긴 클릭을 어떻게 구별 할 수 있습니까?

여기에 더 많은 현명함을 포함해야하는 이동해야 할 거리를 포함 할 수 있고, 사용자가 200 밀리 초 안에 존재하는 거리가 클릭이 아닌 이동을 할 수있는 거리가 아직 만나지 않습니다.

setOnTouchListener(new OnTouchListener() {
    private static final int MAX_CLICK_DURATION = 200;
    private long startClickTime;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                startClickTime = Calendar.getInstance().getTimeInMillis();
                break;
            }
            case MotionEvent.ACTION_UP: {
                long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
                if(clickDuration < MAX_CLICK_DURATION) {
                    //click event has occurred
                }
            }
        }
        return true;
    }
});

다음을 고려하여 최상의 결과를 얻었습니다.

  1. 주로 이벤트 제공 이동 거리 입니다. 화면을 더 다른 잘 지원하기 위해 최대 허용 거리를 픽셀이 아닌 밀도 독립형 픽셀 로 지정하고 싶었습니다 . 예 : 15 DP .ACTION_DOWNACTION_UP
  2. 둘째, 이벤트 사이 기간 입니다. 1 초 는 최대로 보였습니다. (어떤 사람들은 아주 "엄청나게", 즉 천천히 "클릭"합니다. 저는 여전히 그것을 인식하고 싶습니다.)

예 :

/**
 * Max allowed duration for a "click", in milliseconds.
 */
private static final int MAX_CLICK_DURATION = 1000;

/**
 * Max allowed distance to move during a "click", in DP.
 */
private static final int MAX_CLICK_DISTANCE = 15;

private long pressStartTime;
private float pressedX;
private float pressedY;

@Override
public boolean onTouchEvent(MotionEvent e) {
     switch (e.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            pressStartTime = System.currentTimeMillis();                
            pressedX = e.getX();
            pressedY = e.getY();
            break;
        }
        case MotionEvent.ACTION_UP: {
            long pressDuration = System.currentTimeMillis() - pressStartTime;
            if (pressDuration < MAX_CLICK_DURATION && distance(pressedX, pressedY, e.getX(), e.getY()) < MAX_CLICK_DISTANCE) {
                // Click event has occurred
            }
        }     
    }
}

private static float distance(float x1, float y1, float x2, float y2) {
    float dx = x1 - x2;
    float dy = y1 - y2;
    float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);
    return pxToDp(distanceInPx);
}

private static float pxToDp(float px) {
    return px / getResources().getDisplayMetrics().density;
}

여기의 아이디어는 Gem의 솔루션 과 동일하지만 다음과 같은 차이점이 있습니다.

  • 두 점 사이 의 실제 유클리드 거리를 계산합니다 .
  • 이것은 px 대신 dp를 사용합니다.

업데이트 (2015) : Gabriel의 미세 조정 된이 .


촬영 Jonik의 우위를 내가 손가락을 이동 한 후 놓아 전에 자리로 돌아갈 경우 클릭으로 등록하지 않는 약간의 더 미세 조정 버전을 내장 :

그래서 여기 내 해결책이 있습니다.

/**
 * Max allowed duration for a "click", in milliseconds.
 */
private static final int MAX_CLICK_DURATION = 1000;

/**
 * Max allowed distance to move during a "click", in DP.
 */
private static final int MAX_CLICK_DISTANCE = 15;

private long pressStartTime;
private float pressedX;
private float pressedY;
private boolean stayedWithinClickDistance;

@Override
public boolean onTouchEvent(MotionEvent e) {
     switch (e.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            pressStartTime = System.currentTimeMillis();                
            pressedX = e.getX();
            pressedY = e.getY();
            stayedWithinClickDistance = true;
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            if (stayedWithinClickDistance && distance(pressedX, pressedY, e.getX(), e.getY()) > MAX_CLICK_DISTANCE) {
                stayedWithinClickDistance = false;
            }
            break;
        }     
        case MotionEvent.ACTION_UP: {
            long pressDuration = System.currentTimeMillis() - pressStartTime;
            if (pressDuration < MAX_CLICK_DURATION && stayedWithinClickDistance) {
                // Click event has occurred
            }
        }     
    }
}

private static float distance(float x1, float y1, float x2, float y2) {
    float dx = x1 - x2;
    float dy = y1 - y2;
    float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);
    return pxToDp(distanceInPx);
}

private static float pxToDp(float px) {
    return px / getResources().getDisplayMetrics().density;
}

감지기를 사용하면 작동하며 드래그시 상승하지 않습니다.

들 :

private GestureDetector mTapDetector;

초기화 :

mTapDetector = new GestureDetector(context,new GestureTap());

이너 클래스 :

class GestureTap extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onDoubleTap(MotionEvent e) {

        return true;
    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        // TODO: handle tap here
        return true;
    }
}

onTouch :

@Override
public boolean onTouch(View v, MotionEvent event) {
    mTapDetector.onTouchEvent(event);
    return true;
}

즐겨 :)


클릭 이벤트 인식을 최적화 비용 다음 두 가지를 올립니다.

  1. ACTION_DOWN과 ACTION_UP 사이의 시차입니다.
  2. 사용자가 터치 할 때와 손가락을 떼었을 때의 x, y의 차이.

사실 저는 Stimsoni와 Neethirajan이 제시 한 논리를 결합합니다.

그래서 여기 내 해결책이 있습니다.

        view.setOnTouchListener(new OnTouchListener() {

        private final int MAX_CLICK_DURATION = 400;
        private final int MAX_CLICK_DISTANCE = 5;
        private long startClickTime;
        private float x1;
        private float y1;
        private float x2;
        private float y2;
        private float dx;
        private float dy;

        @Override
        public boolean onTouch(View view, MotionEvent event) {
            // TODO Auto-generated method stub

                    switch (event.getAction()) 
                    {
                        case MotionEvent.ACTION_DOWN: 
                        {
                            startClickTime = Calendar.getInstance().getTimeInMillis();
                            x1 = event.getX();
                            y1 = event.getY();
                            break;
                        }
                        case MotionEvent.ACTION_UP: 
                        {
                            long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
                            x2 = event.getX();
                            y2 = event.getY();
                            dx = x2-x1;
                            dy = y2-y1;

                            if(clickDuration < MAX_CLICK_DURATION && dx < MAX_CLICK_DISTANCE && dy < MAX_CLICK_DISTANCE) 
                                Log.v("","On Item Clicked:: ");

                        }
                    }

            return  false;
        }
    });

아래 코드는 문제를 해결하는 것입니다


    @ 우세하다
        public boolean onTouchEvent (MotionEvent 이벤트) {
            switch (event.getAction ()) {
                case (MotionEvent.ACTION_DOWN) :
                    x1 = event.getX ();
                    y1 = event.getY ();
                    단절;
                case (MotionEvent.ACTION_UP) : {
                    x2 = event.getX ();
                    y2 = event.getY ();
                    dx = x2-x1;
                    dy = y2-y1;

                if (Math.abs (dx)> Math.abs (dy)) 
                {
                    (dx> 0) 이동 (1); // 권리
                    이름은 (dx == 0) move (5); // 딸깍하는 소리
                    개체는 move (2); // 왼쪽
                } 
                그밖에 
                {
                    (dy> 0) 이동 (3); // 아래로
                    개체는 (dy == 0) move (5); // 딸깍하는 소리
                    개체는 move (4); //쪽으로
                }
                }
            }
            참을 반환하십시오.
        }


ACTION_MOVE가 발생하지 않고 ACTION_DOWN이 발생하는 것은 매우 어렵습니다. 첫 번째 터치가 위치와 다른 지점에서 화면에서 손가락을 조금만 움직이면 MOVE 이벤트가 트리거됩니다. 또한 MOVE 이벤트를 유발할 생각합니다. Action_Move 메소드에서 문을 사용하여 원래 DOWN 동작이 이동이 거리를 확인합니다. 이동이 일정 반경 밖에서 발생하면 MOVE 동작이 발생합니다. 아마도 최선의 자원 수단은 작동해야합니다.


클릭만으로 광고 다음을 사용하십시오.

if (event.getAction() == MotionEvent.ACTION_UP) {

}

위의 답변에 추가하면 onClick 및 Drag 작업을 모두 구현 후 코드를 사용할 수 있습니다. @Stimsoni의 도움을십시오.

     // assumed all the variables are declared globally; 

    public boolean onTouch(View view, MotionEvent event) {

      int MAX_CLICK_DURATION = 400;
      int MAX_CLICK_DISTANCE = 5;


        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN: {
                long clickDuration1 = Calendar.getInstance().getTimeInMillis() - startClickTime;


                    startClickTime = Calendar.getInstance().getTimeInMillis();
                    x1 = event.getX();
                    y1 = event.getY();


                    break;

            }
            case MotionEvent.ACTION_UP:
            {
                long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
                x2 = event.getX();
                y2 = event.getY();
                dx = x2-x1;
                dy = y2-y1;

                if(clickDuration < MAX_CLICK_DURATION && dx < MAX_CLICK_DISTANCE && dy < MAX_CLICK_DISTANCE) {
                    Toast.makeText(getApplicationContext(), "item clicked", Toast.LENGTH_SHORT).show();
                    Log.d("clicked", "On Item Clicked:: ");

               //    imageClickAction((ImageView) view,rl);
                }

            }
            case MotionEvent.ACTION_MOVE:

                long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
                x2 = event.getX();
                y2 = event.getY();
                dx = x2-x1;
                dy = y2-y1;

                if(clickDuration < MAX_CLICK_DURATION && dx < MAX_CLICK_DISTANCE && dy < MAX_CLICK_DISTANCE) {
                    //Toast.makeText(getApplicationContext(), "item clicked", Toast.LENGTH_SHORT).show();
                  //  Log.d("clicked", "On Item Clicked:: ");

                    //    imageClickAction((ImageView) view,rl);
                }
                else {
                    ClipData clipData = ClipData.newPlainText("", "");
                    View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);

                    //Toast.makeText(getApplicationContext(), "item dragged", Toast.LENGTH_SHORT).show();
                    view.startDrag(clipData, shadowBuilder, view, 0);
                }
                break;
        }

        return  false;
    }

길 SH 응답을 사용하여, 나는 구현하여 개선 onSingleTapUp()보다는 onSingleTapConfirmed(). 훨씬 더 빠르며 드래그 / 이동하면보기를 클릭하지 않습니다.

GestureTap :

public class GestureTap extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        button.performClick();
        return true;
    }
}

다음과 같이 사용하십시오.

final GestureDetector gestureDetector = new GestureDetector(getApplicationContext(), new GestureTap());
button.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        gestureDetector.onTouchEvent(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                return true;
            case MotionEvent.ACTION_UP:
                return true;
            case MotionEvent.ACTION_MOVE:
                return true;
        }
        return false;
    }
});

참고 URL : https://stackoverflow.com/questions/9965695/how-to-distinguish-between-move-and-click-in-ontouchevent

반응형