2013-04-03 40 views
45

Hãy xem xét việc bỏ rơi xin vui lòng (để hiểu rõ hơn về vấn đề của tôi). enter image description hereMotionEvent.ACTION_UP không được gọi là

Như bạn thấy, tôi đang xem xét chế độ xem danh sách được bao quanh bởi đệm. Bây giờ, nếu người dùng nhấn một mục listview, như là hành động tôi đã cung cấp nó màu nền xanh nhạt. Bây giờ, ứng dụng của tôi đang đối phó với sự kiện onTouch bản thân để xác định hành động như

  • Bấm
  • Trái sang Phải Swipe
  • Quyền Left Swipe

Đây là mã của tôi.

public boolean onTouch(View v, MotionEvent event) { 
     if(v == null) 
     { 
      mSwipeDetected = Action.None; 
      return false; 
     } 
     switch (event.getActionMasked()) { 
     case MotionEvent.ACTION_DOWN: { 
      downX = event.getRawX(); 
      downY = event.getRawY(); 
      mSwipeDetected = Action.Start; 

     // Find the child view that was touched (perform a hit test) 
      Rect rect = new Rect(); 
      int childCount = listView.getChildCount(); 
      int[] listViewCoords = new int[2]; 
      listView.getLocationOnScreen(listViewCoords); 
      int x = (int) event.getRawX() - listViewCoords[0]; 
      int y = (int) event.getRawY() - listViewCoords[1]; 
      View child; 
      for (int i = 0; i < childCount; i++) { 
       child = listView.getChildAt(i); 
       child.getHitRect(rect); 
       if (rect.contains(x, y)) { 
        mDownView = child; 
        break; 
       } 
      } 


      return false; // allow other events like Click to be processed 
     } 
     case MotionEvent.ACTION_MOVE: { 
      upX = event.getRawX(); 
      upY = event.getRawY(); 
      float deltaX=0,deltaY=0; 
      deltaX = downX - upX; 
      deltaY = downY - upY; 

       if(deltaY < VERTICAL_MIN_DISTANCE) 
       { 
          setTranslationX(mDownView, -(deltaX)); 
          setAlpha(mDownView, Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX)/listView.getWidth()))); 
          return false; 
       } 
       else 
       { 
        forceBringBack(v); 
       } 

          return false;    

     } 
     case MotionEvent.ACTION_UP: 
     { 

      stopX = event.getX(); 
      float stopValueY = event.getRawY() - downY;    
      float stopValue = stopX - downX; 

      if(!mDownView.isPressed()) 
      { 
       forceBringBack(mDownView); 
       return false; 
      }    

      boolean dismiss = false; 
      boolean dismissRight = false; 


      if(Math.abs(stopValue)<10) 
      { 
       mSwipeDetected = Action.Start; 
      } 
      else 
      { 
       mSwipeDetected = Action.None; 

      } 
      String log = ""; 
      Log.d(log, "Here is Y" + Math.abs(stopValueY)); 
      Log.d(log, "First Comparison of Stop Value > with/4" + (Math.abs(stopValue) > (listView.getWidth() /4))); 
      Log.d(log, "Second Comparison " + (Math.abs(stopValueY)<VERTICAL_MIN_DISTANCE)); 
      Log.d(log, "Action Detected is " + mSwipeDetected + " with Stop Value " + stopValue); 

      if((Math.abs(stopValue) > (listView.getWidth() /4))&&(Math.abs(stopValueY)<VERTICAL_MIN_DISTANCE)) 
      { 
       dismiss = true; 
       dismissRight = stopValue > 0; 

       if(stopValue>0) 
       { 
       mSwipeDetected = Action.LR; 

       } 
       else 
        mSwipeDetected = Action.RL; 
      } 
      Log.d(log, "Action Detected is " + mSwipeDetected + " with Stop Value after dissmiss" + stopValue); 

      if(dismiss) 
      { 
       if(dismissRight) 
        mSwipeDetected = Action.LR; 
       else 
        mSwipeDetected = Action.RL; 
       animate(mDownView) 
       .translationX(dismissRight ? listView.getWidth() : - listView.getWidth()) 
       .alpha(0) 
       .setDuration(mAnimationTime) 
       .setListener(new AnimatorListenerAdapter() { 
        public void onAnimationEnd(Animator animation) 
        { 

        } 
       }); 
      } 
      else 
      { 
       animate(mDownView) 
       .translationX(0) 
       .alpha(1) 
       .setDuration(mAnimationTime) 
       .setListener(null); 
      } 


      break;   

     } 
     } 
     return false; 
    } 

Như bạn có thể thấy, tôi xác định hành động được thực hiện trong MotionEvent.ACTION_UP và đặt giá trị của Hành động Enum cho phù hợp. Logic này hoạt động như một nét duyên dáng nếu người dùng không vượt qua ranh giới xem danh sách.

Bây giờ, nếu người dùng, trong khi trượt (hoặc cụ thể), di chuyển ngón tay dọc theo mục danh sách di chuyển từ màu xanh sang màu cam, MotionEvent.ACTION_UP sẽ không được cung cấp cho chế độ xem danh sách, khiến mã của tôi không đưa ra quyết định và do phương thức translationX() và setAlpha(), vì không có Hành động nào được xác định trong trường hợp này, mục danh sách cụ thể đó sẽ trống.

Sự cố không dừng lại ở đây, vì tôi không tăng lượt xem mỗi lần, cùng một dòng dịch() được tăng cao mỗi lần dẫn đến nhiều lần xảy ra mục danh sách trống/trắng.

Có bất kỳ điều gì có thể thực hiện được mà ngay cả khi tôi không gặp phải MotionEvent.ACTION_UP, tôi vẫn có thể thực hiện một số quyết định không?

Cảm ơn.

+0

xem nếu điều này giải quyết câu hỏi của bạn: http://stackoverflow.com/questions/13283827/onintercepttouchevent-only-gets-action-down – user123321

Trả lời

142

Bạn nên return true; trong case MotionEvent.ACTION_DOWN:, vì vậy, MotionEvent.ACTION_UP sẽ được xử lý.


Như đã giải thích trên View.OnTouchListener:

Returns:

True nếu người nghe đã tiêu thụ sự kiện này, false.

MotionEvent.ACTION_UP sẽ không được gọi cho đến khi MotionEvent.ACTION_DOWN xảy ra, một lời giải thích hợp lý cho việc này là nó không thể đối với một ACTION_UP xảy ra nếu một ACTION_DOWN không bao giờ xảy ra trước đó.

Logic này cho phép nhà phát triển chặn các sự kiện khác sau ACTION_DOWN.

+5

Tôi đã luôn luôn bị nhầm lẫn là tại sao điều này là đúng. Có một lời giải thích của logic bất cứ nơi nào? –

+2

@Turbo Đã thêm một giải thích hợp lý, Tuy nhiên tôi nghĩ Android nên giải thích tốt hơn hoặc khắc phục hành vi hợp lý hơn. – Danpe

+1

Tôi nghĩ 'đã tiêu thụ 'có nghĩa là sự kiện sẽ không được chuyển sang lớp giao diện người dùng bên dưới người tiêu dùng. Tôi vẫn có thể muốn nhận thức được những chạm nhưng vẫn vượt qua chúng. Sẽ trở về đúng ngăn chặn từ thấp hơn để các thành phần lớp từ nhận được sự kiện liên lạc? –

0

Danpe explained in his concise answer - Tôi phải thêm mã ACTION_DOWN để ACTION_UP được nhận dạng.

  case MotionEvent.ACTION_DOWN: 

       return true; 

      case MotionEvent.ACTION_UP: 

       XyPos xyPos = new XyPos(); 
       xyPos.x = last_x; 
       xyPos.y = last_y; 
       handleViewElementPositionUpdate(xyPos); 

       break; 

Tôi đã có toàn bộ phương thức onTouch (..) trả về true, vì vậy tôi không chắc tại sao điều đó không đủ ... nhưng rất vui khi có giải pháp nhanh này.)

4

Tôi không nghĩ rằng thêm return true; vào trường hợp MotionEvent.ACTION_DOWN: cuối cùng sẽ giải quyết được sự cố. Nó chỉ phức tạp trong tình huống mà return false có thể thực hiện công việc như một sự quyến rũ.

gì cần ghi nhận là: MotionEvent.ACTION_DOWN: /*something*/ return true; sẽ chặn bất kỳ callbacks Listener khác có sẵn cho xem, thậm chí onClickListenerm, trong khi đúng return false trong MotionEvent.ACTION_UP: có thể giúp MotionEvent được tuyên truyền đến đích đúng đắn.

tham khảo mã sourse ban đầu của mình: https://github.com/romannurik/android-swipetodismiss

+0

Tôi cũng đã khởi chạy một dự án Roman Nurik, và nó đã hoạt động. Khi tôi cố gắng áp dụng mã cho chế độ xem của mình, nó không hoạt động. Khi tôi thay đổi 'return false;' thành 'return true;' nó đã giúp. – CoolMind

13

Cũng lưu ý rằng trong những trường hợp nhất định, cử chỉ có thể bị hủy bỏ, trong trường hợp một MotionEvent.ACTION_UP sẽ KHÔNG được gửi (ví dụ như phép quay màn hình.). Thay vào đó, thay vào đó, MotionEvent.ACTION_CANCEL được gửi. Vì vậy một câu lệnh switch hoạt động bình thường nên tìm một cái gì đó như thế này:

switch (event.getActionMasked()) { 
    case MotionEvent.ACTION_DOWN: 
     // check if we want to handle touch events, return true 
     // else don't handle further touch events, return false 

    case MotionEvent.ACTION_UP: 
    case MotionEvent.ACTION_CANCEL: 
     // finish handling touch events 
     // note that these methods won't be called if 'false' was returned 
     // from any previous events related to the gesture 
} 
+1

Không chắc chắn lý do tại sao nhưng vì một lý do nào đó tôi phải thêm hủy để bắt kịp. – Rarw

+0

Bạn vừa mới cứu tôi rất nhiều rắc rối .. cảm ơn rất nhiều :) –

+0

chỉ cả hai giải pháp hoạt động tốt. – Eugen

Các vấn đề liên quan