2013-07-26 40 views
5

Tôi có một ứng dụng sử dụng SimpleOnScaleGestureListener và SimpleOnGestureListener cùng nhau. Bất cứ khi nào tôi làm một zoom pinch tôi nhận được onScale dự kiến, nhưng khi tôi nhấc ra tôi thấy một onScroll kỳ lạ mà có một vị trí bắt đầu từ đầu của pinch zoom và một vị trí kết thúc từ cuối của pinch zoom. Câu hỏi của tôi là, tôi có thể ngăn chặn onogroll không có thật không?Sự kiện Weird onScroll được kích hoạt sau sự kiện onScale

Dưới đây là các mã:

@Override 
public boolean onTouchEvent(MotionEvent event) { 

    // Log every event. 
    Log.d(TAG, Here.at() + String.format("Event: %d, Time: %d X: %f, Y: %f", 
      event.getAction(), 
      event.getEventTime(), 
      event.getX(), 
      event.getY() 
      )); 

    boolean handled = mScaleDetector.onTouchEvent(event); // This appears to ALWAYS return true (online reference indicated that's what the Android code does). 

    handled |= mDetector.onTouchEvent(event); 

    handled |= super.onTouchEvent(event); 

    return handled; 
} 

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 

    @Override 
    public boolean onScaleBegin(ScaleGestureDetector detector) { 
     // This is required. If absent, the scale gesture never starts. 
     Log.d(TAG, "In onScaleBegin"); 
     mIgnoreNextDrag = true; 
     return true; 
    } 

    @Override 
    public boolean onScale(ScaleGestureDetector detector) { 
     Log.d(TAG, "In onScale"); 
     mTimeScale.doScale(detector.getScaleFactor(), detector.getFocusY()); 
     invalidate(); 
     return true; 
    } 

    @Override 
    public void onScaleEnd(ScaleGestureDetector detector) { 
     Log.d(TAG, "In onScaleEnd"); 
    } 

} 

private class GestureListener extends GestureDetector.SimpleOnGestureListener { 

    @Override 
    public boolean onScroll(MotionEvent me1, MotionEvent me2, float distanceX, float distanceY) { 

     Log.d(TAG, String.format("Motion Event 1: %d, Time: %d X: %f, Y: %f", 
       me1.getAction(), 
       me1.getEventTime(), 
       me1.getX(), 
       me1.getY() 
       )); 

     Log.d(TAG, String.format("Event 2: %d, Time: %d X: %f, Y: %f", 
       me2.getAction(), 
       me2.getEventTime(), 
       me2.getX(), 
       me2.getY() 
       )); 


     return true; 

    } 

    @Override 
    public boolean onSingleTapConfirmed(MotionEvent me) { 
     // Do tap processing. 
     return true; 
    } 

    @Override 
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 
     // TODO: Future feature. 
     return true; 
    } 

    @Override 
    public boolean onDown(MotionEvent e) { 
     // This is required. If absent, the scroll gesture never starts. 
     return true; 
    } 

} 

Dưới đây là các LogCat:

13:06:05.885: D/my-tag(4140): In View.onTouchEvent, Event: 0, Time: 183279420 X: 171.761444, Y: 918.160767 
13:06:05.895: D/my-tag(4140): In View.onTouchEvent, Event: 261, Time: 183279420 X: 171.761444, Y: 918.160767 
13:06:05.895: D/my-tag(4140): In onScaleBegin 
13:06:05.895: I/ScaleGestureDetector(4140): TwScaleGestureDetector 
13:06:05.915: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279458 X: 171.761444, Y: 908.474365 
13:06:05.915: D/my-tag(4140): In onScale 
13:06:06.015: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279542 X: 174.964783, Y: 857.584717 
13:06:06.015: D/my-tag(4140): In onScale 
13:06:06.105: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279641 X: 232.242096, Y: 731.365662 
13:06:06.105: D/my-tag(4140): In onScale 
13:06:06.215: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279740 X: 313.564514, Y: 595.412964 
13:06:06.215: D/my-tag(4140): In onScale 
13:06:06.225: D/my-tag(4140): In View.onTouchEvent, Event: 6, Time: 183279751 X: 313.564514, Y: 595.412964 
13:06:06.225: D/my-tag(4140): In onScaleEnd 
13:06:06.245: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279774 X: 333.316528, Y: 487.607422 
13:06:06.245: D/my-tag(4140): In onScroll, me1: 0, Time: 183279420 X: 171.761444, Y: 918.160767 
13:06:06.245: D/my-tag(4140): In onScroll, me2 2: 2, Time: 183279774 X: 333.316528, Y: 487.607422 
13:06:06.255: D/my-tag(4140): In View.onTouchEvent, Event: 2, Time: 183279784 X: 331.539551, Y: 488.496460 
13:06:06.265: D/my-tag(4140): In onScroll, me1: 0, Time: 183279420 X: 171.761444, Y: 918.160767 
13:06:06.265: D/my-tag(4140): In onScroll, me2 2: 2, Time: 183279784 X: 331.539551, Y: 488.496460 
13:06:06.275: D/my-tag(4140): In View.onTouchEvent, Event: 1, Time: 183279794 X: 331.539551, Y: 488.496460 

Bạn có thể thấy rằng sự kiện đầu tiên là ngón tay đầu tiên xuống (0 = ACTION_DOWN), sau đó ngón tay thứ hai xuống (261 = ACTION_POINTER_2_DOWN). Sau đó, chúng ta thấy mục nhật ký từ cuộc gọi onScaleBegin và nhật ký từ chính trình dò ​​cử chỉ tỷ lệ (không phải từ mã của tôi). Tại thời điểm này tôi nghĩ rằng tôi có thể giả định một cách an toàn cử chỉ quy mô đã được bắt đầu. Điều này là chính xác như mong đợi.

Tiếp theo là bốn sự kiện di chuyển (2 = ACTION_MOVE), mỗi sự kiện được theo sau bởi mục nhập nhật ký từ onScale. Điều này vẫn như mong đợi.

Sau đó, chúng ta sẽ thấy sự kiện trỏ lên (6 = ACTION_POINTER_UP) theo sau là mục nhập nhật ký từ onScaleEnd, vẫn còn AOK! (Lưu ý rằng đó là một 6 và không phải là 262 vì tôi nâng ngón tay của tôi theo thứ tự mà tôi đặt chúng xuống, vì vậy con trỏ 1 được nâng lên đầu tiên, không phải con trỏ 2.)

Bây giờ bit lạ.

Chúng tôi thấy sự kiện di chuyển, được chọn bởi onScroll trong SimpleOnGestureListener. Tham số đầu tiên me1 có toạ độ x và y từ sự kiện đầu tiên xuống trước khi cử chỉ thang đo bắt đầu Tham số thứ hai me2 có tọa độ mà dường như phản ánh một vị trí sau khi cử chỉ tỷ lệ đã dừng lại.

Trong ví dụ này, có một sự kiện di chuyển thứ hai cũng được hiểu là cử chỉ cuộn, một lần nữa với điểm xuất phát trước quy mô. Với đoạn mã trên, tôi sẽ nhận được 1, 2 hoặc không có sự kiện cuộn sau khi thu phóng pinch.

(Để kết thúc việc LogCat, chúng tôi là một sự kiện chính thức lên (1 = ACTION_UP) cho các ngón tay thứ hai và nhật ký đi yên tĩnh.)

Vì vậy, tôi làm việc đó sai? Tôi đã thử chỉ gọi SimpleOnGestureListener nếu SimpleOnScaleGestureListener trả về false từ isInProgress, nhưng không có niềm vui.

Bất kỳ ý tưởng nào?

Cảm ơn trước và cảm ơn tất cả các bạn trong cộng đồng vì lượng thông tin khổng lồ tôi đã nhận được từ trang web này trong những năm qua!

Trả lời

6

Tôi cũng tìm thấy hành vi đặc biệt này tạo chế độ xem tùy chỉnh với khả năng xoay/thu phóng. Nhưng sau một vài suy nghĩ, đây là lý do của tôi:

Trong môi trường multitouch, mỗi ngón tay được đăng ký và chuyển động tương ứng của chúng được xử lý trong một số loại phân tích song song. Đây là những gì cho phép phát hiện các sự kiện chạm khác nhau mà hệ thống có thể gửi bằng phương tiện của OnGestureListenerOnScaleGestureListener.

Phải, không có gì bạn chưa biết.

Bây giờ, nghĩ rằng hành vi khác nhau của hai dò:

  • GestureDetector phát hiện một kiện cuộn bằng một kéo chỉ với một ngón tay bên trong các giới hạn của khu vực có thể xem được các quan điểm. Mô hình của nó đáp ứng: down - pull - up. Các sự kiện cuộn được tạo ra khi các sự kiện kéo được phát hiện.

  • ScaleGestureDetector phát hiện quy mô sự kiện bằng hai lần kéo đồng thời được bắn bởi hai ngón tay trong môi trường cảm ứng đa điểm. Mẫu của nó phản hồi: (down1 & down2) - (kéo1 và/hoặc kéo2) - (up1 hoặc up2).

Và bây giờ, hãy nghĩ về chế độ xem tùy chỉnh nơi bạn chỉ cần phát hiện sự kiện cuộn (bỏ qua tất cả các sự kiện khác). Trong trường hợp này, sự kiện cuộn phải được bỏ qua một bên tất cả các cân nhắc khác vì bạn đã thực hiện mẫu của nó (kéo xuống).

Khi bạn kết hợp hai máy dò này, họ hành động một cách độc lập, vì vậy đám cháy dò quy mô đầu tiên, nhưng khi bạn nhấc ngón tay thứ hai, đám cháy phát hiện cuộn bởi vì nó phát hiện một ngón tay đó là kéo và kết thúc với một lên sự kiện!

Kết luận: Hành vi có vẻ hợp lý ... nhưng Android có thể đã cung cấp một số dò tìm chéo cho tình huống đồng thời.

Vâng, bạn có thể chỉ cần đặt boolean và giải quyết vấn đề. Tôi đã thực hiện điều này trong việc thực hiện của tôi:

  • Khai báo một boolean tên scaling
  • Đặt sự kiện onDown của bạn (trên các sự kiện ACTION_DOWN) để xóa scaling
  • Đặt sự kiện onScale của bạn để thiết lập scaling
  • Hãy của bạn sự kiện onScroll không xử lý cuộn nếu cờ scalingtrue

Điều này đã làm việc cho tôi rồi.

+0

Kế hoạch tốt và cảm ơn phản hồi chi tiết. Bây giờ tôi đã thực hiện một cái gì đó rất giống với việc giúp tôi bỏ qua cuộn giấy. –

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