2014-05-23 2 views
0

Android 캔버스와 GuestureDetector.SimpleOnGestureListener 사용자 지정 양방향 스크롤을 구현하려고하지만 몇 가지 문제가 있습니다. 첫 스크롤 이벤트는 항상 거대한 부정확 한 점프를 제공합니다.잘못된 값을 제공하는 Android onScroll 이벤트

scroll x: -352 scroll y: -373 
scroll x: -4 scroll y: 3 
scroll x -4 scroll y: 3 

스크롤의 첫 번째 값은 항상이다 : 나는 캔버스의 중앙에 클릭하고 작은 비트를 이동하면

는 예를 들어, 나는 (약간 둥근)이 같은 스크롤 이벤트를 볼 수 있습니다 거대한 점프 내가 원격으로 내 손가락으로 수행하는 아니에요 함께 스크롤. 캔버스의 한쪽 구석에서 손가락을 실제로 움직이는 것처럼 내 첫 스크롤 동작을 처리하는 것처럼 보입니다.

public class BoardScrollListener extends GestureDetector.SimpleOnGestureListener { 

    private GameService gameService = GameService.getInstance(); 
    private UiService uiService = UiService.getInstance(); 

    @Override 
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 

     Log.d("scroll", "scroll x: " + distanceX + " scroll y: " + distanceY); 
     if (distanceX > -150 && distanceY > -150) { 
      Game game = gameService.getGame(); 
      game.setxPixelOffset((int) (game.getxPixelOffset() - distanceX)); 
      game.setyPixelOffset((int) (game.getyPixelOffset() - distanceY)); 

      uiService.getGameboardActivity().getGameboard().invalidate(); 
     } 
     return true; 
    } 
    @Override 
    public boolean onDown(MotionEvent e) { 
     return true; 
    } 
} 

내가 체크 무슨 일이 있었는지 볼 경우에는 그것이에서 포장 시도, 그리고 실제로 대부분의 시간을이 문제를 해결하지만, 분명 진정한 해결책이 아니다 :

여기 내 실제 리스너입니다. 누구나 모션 이벤트가 왜 부정확한지, 그리고 정확하게 만들거나 스크롤의 첫 번째 모션 이벤트를 무시할 수있는 좋은 방법이라고 말할 수 있습니까?

v4 지원 활동 조각을 사용하고 있으므로 GestureDetectorCompat으로 전환을 시도했지만 아무런 변화가 없습니다. (KitKat 기기에 있습니다.)

+0

중복 질문 : HTTP : // 유래.com/questions/12465540/scroll-listener-first-distancey-always-negative-for-downward-scroll – Siva

답변

2

먼저 좌표가 ACTION_DOWN이 며 이후 거리가 표시됩니다. 나는 당신이 사건 행동에 대한 점검을해야한다고 생각한다.

@Override 
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 

    Log.d("scroll", "scroll x: " + distanceX + " scroll y: " + distanceY); 

    // ! CHECK FOR EVENT ACTION ! 
    if (e2.getAction() == MotionEvent.ACTION_MOVE) { 
     Game game = gameService.getGame(); 
     game.setxPixelOffset((int) (game.getxPixelOffset() - distanceX)); 
     game.setyPixelOffset((int) (game.getyPixelOffset() - distanceY)); 

     uiService.getGameboardActivity().getGameboard().invalidate(); 
    } 
    return true; 
} 
+0

e2가 내 로그 라인에'ACTION_MOVE '인지 여부에 대한 메시지를 추가했으며 항상'ACTION_MOVE '입니다. 내 문제는이 GestureListener를 사용자 정의보기 캔버스에 연결하는 것과 관련이 있어야합니다. – CorayThan

+0

그렇다면 IDK는 그렇지만 e1은 스크롤을 시작한 ACTION_DOWN 모션 이벤트이므로 onScroll의 첫 번째 호출에서 큰 값을 얻습니다. –

+0

e1은 항상 null입니다. 두 경우 모두 모든 상황에서 동일하게 나타납니다. 나는 단지 거리가 변하는 것을 본다. – CorayThan

0

나는이 문제를 일으키는 청취자 인 onTouch을 별도로 붙이고있었습니다. 해당 이벤트의 본문을 내 사용자 지정보기의 onTouchEvent 무시 이벤트 수신기로 가져 오면 문제가 해결됩니다.

1

같은 문제가 발생했습니다. 내 경우에는 onInterceptTouchEvent()를 사용하고있는 것이 사실이라는 것을 알았습니다. ACTION_DOWN 이벤트는 내 뷰 그룹의 하위에서 처리해야하기 때문에이 필요합니다. 그러나 ACTION_MOVE 이벤트를 가로 채서 GestureDetector에 공급하면 ACTION_MOVE 앞의 MOTION_DOWN 이벤트가 보내지지 않습니다. GestureListener의 onScroll()에서 e1은 항상 null입니다.

onScroll()에서 첫 번째 distanceX는 e1의 positionX를 기준으로 계산됩니다. 그 후 이전 e2의 positionX가 사용됩니다. e1이없는 경우 onScroll()은 0 또는 이전 스크롤의 ACTION_UP이 발생한 위치를 사용합니다 (존재하는 경우).

어쨌든 긴 이야기가 짧습니다. 작동 시키려면 onScroll()에서 첫 번째 ACTION_MOVE를 무시하기로 결정했습니다. 내가 사용한 코드는 아래를 참조하십시오.

@Override 
public boolean onInterceptTouchEvent(MotionEvent event) { 

    final int action = MotionEventCompat.getActionMasked(event); 

    // always handel touch event completion 
    if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 
     //Log.i("Intercept Up: ", "END GESTURE"); 
     mIsScrolling = false; 
     return false; 
    } 

    switch (action) { 
     case MotionEvent.ACTION_DOWN: { 
      // Record position 
      mDownX = event.getX(); 
      // let the child handel the event 
      return false; 
     } 
     case MotionEvent.ACTION_MOVE: { 
      if (mIsScrolling) { 
       // we are currently scrolling, so intercept the event 
       return true; 
      } 
      float dx = event.getX() - mDownX; 
      if (Math.abs(dx) > mTouchSlop) { 
       // We met the motion threshold; Intercept the event to initiate scrolling 
       mIsScrolling = true; 
       return true; 
      } 
      // Not scrolling and threshold not met 
      return false; 
     } 
     default: { 
      // other motion events will not be intercepted 
      return false; 
     } 
    } 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 

    final int action = MotionEventCompat.getActionMasked(event); 

    // always handel touch event completion 
    if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 
     mIsScrolling = false; 
     // Used to ignore the first scroll event with bad distanceX 
     mIsFirstScrollEvent = true; 
     return true; 
    } 
    // Use GestureDetector to detect event type 
    mGestureDetector.onTouchEvent(event); 
    return true; 
} 


private final GestureDetector.OnGestureListener mGestureListener = 
     new GestureDetector.SimpleOnGestureListener() { 

    @Override 
    public boolean onScroll (MotionEvent e1, MotionEvent e2, 
          float distanceX, float distanceY) { 

     // First scroll event should be ignored because of bad distanceX 
     if (mIsFirstScrollEvent) { 
      mIsFirstScrollEvent = false; 
      return true; 
     } 

     // Do the scroll stuff here 

     return true; 
    } 
}; 
0

나는 동일한 문제가 있습니다.

하지만 내 경우에는 onInterceptTouchEvent (...) 및 onTouchEvent (...) 메서드에 대해 서로 다른 OnGestureListener-s를 사용합니다.

그러므로 난 그냥 실제 터치 이벤트 리스너

private class GestureInterceptListener extends GestureDetector.SimpleOnGestureListener { 

    @Override 
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 
     final boolean shouldIntercept = ...; // here we decide should we intercept this event, or should it be passed further 
     if (shouldIntercept) { 
      mGestureProcessListener.setFirstScrollEventIgnored(true); 
     } 
     return shouldIntercept; 
    } 

} 


private class GestureProcessListener extends GestureDetector.SimpleOnGestureListener { 

    private boolean ignoreFirstBuggyScrollEvent = false; 

    /** 
    * For some reason first scroll event on half-visible settings list gets strange incorrect negative values 
    * @param isIgnored - should next scroll event be ignored? value resets to false afterwards 
    */ 
    public void setFirstScrollEventIgnored(boolean isIgnored) { 
     ignoreFirstBuggyScrollEvent = isIgnored; 
    } 

    @Override 
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 
     if (ignoreFirstBuggyScrollEvent) { 
      ignoreFirstBuggyScrollEvent = false; 
      return true; 
     } 
     ... // process scroll event here 
     return true; 
    } 

} 

작품에 전달 된 첫 번째 스크롤 이벤트를 무시하고 차단 청취자의 플래그를 설정 나

관련 문제