2009-08-27 20 views
73

Hiểu biết của tôi là khi bạn có chế độ xem quá nhỏ để dễ dàng chạm, bạn phải sử dụng TouchDelegate để tăng vùng có thể nhấp cho chế độ xem đó.Có ví dụ về cách sử dụng TouchDelegate trong Android để tăng kích thước mục tiêu nhấp của chế độ xem không?

Tuy nhiên, việc tìm kiếm các ví dụ sử dụng trên Google khiến nhiều người đặt câu hỏi nhưng ít câu trả lời.

Có ai biết cách thích hợp để thiết lập đại biểu cảm ứng cho chế độ xem, giả sử, tăng vùng có thể nhấp của nó lên 4 pixel theo mọi hướng không?

+3

Đây là bài đăng bổ sung về cách sử dụng TouchDelegate: http://groups.google.com/group/android-developers/browse_thread/thread/178af525ab84b371 –

+0

Hướng dẫn hay: [Vùng có thể mở rộng được mở rộng] (http: // android.cyrilmottier.com/?p=574) –

Trả lời

85

Tôi đã hỏi một người bạn tại Google và họ có thể giúp tôi tìm hiểu cách sử dụng TouchDelegate. Đây là những gì chúng tôi đã đưa ra:

final View parent = (View) delegate.getParent(); 
parent.post(new Runnable() { 
    // Post in the parent's message queue to make sure the parent 
    // lays out its children before we call getHitRect() 
    public void run() { 
     final Rect r = new Rect(); 
     delegate.getHitRect(r); 
     r.top -= 4; 
     r.bottom += 4; 
     parent.setTouchDelegate(new TouchDelegate(r , delegate)); 
    } 
}); 
+14

Điều gì xảy ra nếu có hai nút trên một màn hình mà bạn muốn thực hiện việc này? Nếu bạn setTouchDelegate lại thì nó sẽ xóa đại biểu cảm ứng trước đó. – cottonBallPaws

+1

Điều này đã không làm việc cho tôi ... Tôi giả định các đại biểu là quan điểm tôi đang cố gắng để thêm TouchDelegate. –

+0

Có ai có giải pháp cho vấn đề của @ littleFluffyKitty không? Tôi đang chạy vào cùng một vấn đề! –

0

Nếu không muốn làm điều đó programatically sau đó chỉ cần tạo ra khu vực trong suốt xung quanh hình ảnh, Nếu bạn đang sử dụng hình ảnh làm nền cho nút (xem).

Khu vực màu xám có thể trong suốt để tăng diện tích cảm ứng.

enter image description here

+1

Điều đó sẽ không tạo ra khoảng trống xung quanh sau đó xem mà không thể được sử dụng cho bất cứ điều gì khác? Điều gì sẽ xảy ra nếu bạn muốn hiển thị văn bản thông tin đóng một nút và sử dụng vùng văn bản để nâng cao vùng nhấp của nút? – Martin

+0

Tôi không nói cách tốt nhất và cách tiếp cận cuối cùng. Nhưng nó sẽ phù hợp trong nhiều tình huống mà bạn muốn hiển thị một hình ảnh nút nhỏ nhưng khu vực cảm ứng sẽ được mở rộng. Trong trường hợp của bạn, rất khó để ưu tiên cho nút khi bạn nhấp vào các chế độ xem khác (xem văn bản), tất cả cùng nhau là thử thách khác nhau. –

9

Giải pháp này đã được đăng bởi @BrendanWeinstein trong nhận xét.

Thay vì gửi TouchDelegate bạn có thể ghi đè phương thức getHitRect(Rect) của View (trong trường hợp bạn đang mở rộng một).

public class MyView extends View { //NOTE: any other View can be used here 

    /* a lot of required methods */ 

    @Override 
    public void getHitRect(Rect r) { 
     super.getHitRect(r); //get hit Rect of current View 

     if(r == null) { 
      return; 
     } 

     /* Manipulate with rect as you wish */ 
     r.top -= 10; 
    } 
} 
+0

Ý tưởng thú vị. Nhưng sẽ không có nghĩa là chế độ xem có thể ** không ** được tạo từ bố cục? Không, chờ đã - nếu tôi thiết kế một lớp xem mới và sử dụng nó trong bố cục. Điều đó có thể hiệu quả. Đáng thử. – Martin

+6

@Martin đó là ý tưởng đúng. Rất tiếc, getHitRect không còn được gọi là ICS bởi dispatchTouchEvent http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/view/ViewGroup.java # 1834 Ghi đè getHitRect sẽ chỉ hoạt động đối với bánh gừng và dưới đây. –

0

Trong hầu hết các trường hợp, bạn có thể quấn quan điểm cho rằng đòi hỏi một khu vực cảm ứng lớn hơn trong một cái nhìn không đầu (xem nhân tạo trong suốt) và thêm padding/lề để nhìn wrapper và đính kèm các nhấp chuột/liên lạc thậm chí đến wrapper xem thay vì chế độ xem gốc phải có vùng cảm ứng lớn hơn.

+0

Điều đó sẽ không tạo ra không gian trống xung quanh sau đó xem mà không thể được sử dụng cho bất cứ điều gì khác?Điều gì sẽ xảy ra nếu bạn muốn hiển thị văn bản thông tin đóng một nút và sử dụng vùng văn bản để nâng cao vùng nhấp của nút? – Martin

+0

@Martin, Nó phụ thuộc vào cách bạn làm điều đó. Và nên dễ dàng làm bất cứ điều gì bạn muốn - chỉ cần bọc bất kỳ thứ gì bạn muốn (tuy nhiên bạn muốn nhiều chế độ xem) trong chế độ xem trong suốt trên đầu tất cả các chế độ xem này và chỉ định một nhấp chuột ngay cả đối với khu vực đó. – inteist

18

Tôi có thể thực hiện việc này với nhiều chế độ xem (hộp kiểm) trên một bản vẽ màn hình chủ yếu từ this blog post. Về cơ bản bạn có giải pháp của emmby và áp dụng nó cho mỗi nút và cha mẹ riêng của nó.

public static void expandTouchArea(final View bigView, final View smallView, final int extraPadding) { 
    bigView.post(new Runnable() { 
     @Override 
     public void run() { 
      Rect rect = new Rect(); 
      smallView.getHitRect(rect); 
      rect.top -= extraPadding; 
      rect.left -= extraPadding; 
      rect.right += extraPadding; 
      rect.bottom += extraPadding; 
      bigView.setTouchDelegate(new TouchDelegate(rect, smallView)); 
     } 
    }); 
} 

Trong trường hợp của tôi, tôi đã có một GridView của imageviews với hộp kiểm che trên đầu, và được gọi là phương pháp như sau:

CheckBox mCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox1); 
final ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView1); 

// Increase checkbox clickable area 
expandTouchArea(imageView, mCheckBox, 100); 

Làm việc lớn đối với tôi.

0

Theo nhận xét của @ Lee Lee, điều này giải quyết được vấn đề của tôi. Dự án của tôi có bố cục tương đối và một nút. Vì vậy, cha mẹ là -> bố trí và con là -> một nút.

Dưới đây là một ví dụ google link google code

Trong trường hợp xóa câu trả lời rất có giá trị của ông tôi đặt ở đây câu trả lời của mình.

Gần đây tôi đã được hỏi về cách sử dụng TouchDelegate. Tôi đã hơi mệt mỏi về điều này và tôi không thể tìm thấy bất kỳ tài liệu nào tốt về nó. Đây là mã tôi đã viết sau một thử nghiệm và lỗi nhỏ. touch_delegate_view là một RelativeLayout đơn giản với id touch_delegate_root.Tôi đã định nghĩa với một con, bố cục con, nút delegated_button. Trong ví dụ này, tôi mở rộng vùng có thể nhấp của nút đến 200 pixel phía trên đầu nút của tôi.

lớp công khai TouchDelegateSample mở rộng Hoạt động {

Nút mButton; @Override được bảo vệ void onCreate (Bundle savedInstanceState) { super.onCreate (savedInstanceState); setContentView (R.layout.touch_delegate_view); mButton = (Button) findViewById (R.id.delegated_button); Xem parent = findViewById (R.id.touch_delegate_root);

// post a runnable to the parent view's message queue so its run after 
// the view is drawn 
parent.post(new Runnable() { 
    @Override 
    public void run() { 
    Rect delegateArea = new Rect(); 
    Button delegate = TouchDelegateSample.this.mButton; 
    delegate.getHitRect(delegateArea); 
    delegateArea.top -= 200; 
    TouchDelegate expandedArea = new TouchDelegate(delegateArea, delegate); 
    // give the delegate to an ancestor of the view we're delegating the 
    // area to 
    if (View.class.isInstance(delegate.getParent())) { 
     ((View)delegate.getParent()).setTouchDelegate(expandedArea); 
    } 
    } 
}); } } 

Chúc mừng, Đội Justin Android @ Google

Vài lời từ tôi: nếu bạn muốn mở rộng bên trái, bạn cho giá trị với trừ, và nếu bạn muốn mở rộng phía bên phải của đối tượng, bạn cho giá trị với cộng. Điều này hoạt động tương tự với trên và dưới. approch

+0

Gợi ý ma thuật ở đây có vẻ là * một nút * - Bằng cách nào đó tôi có cảm giác rằng TouchDelegate không sử dụng được cho nhiều nút. Bạn có thể xác nhận điều đó không? – Martin

6

emmby đã không làm việc cho tôi nhưng sau một thay đổi nhỏ nó đã làm:

private void initApplyButtonOnClick() { 
    mApplyButton.setOnClickListener(onApplyClickListener); 
    final View parent = (View)mApplyButton.getParent(); 
    parent.post(new Runnable() { 

     @Override 
     public void run() { 
      final Rect hitRect = new Rect(); 
      parent.getHitRect(hitRect); 
      hitRect.right = hitRect.right - hitRect.left; 
      hitRect.bottom = hitRect.bottom - hitRect.top; 
      hitRect.top = 0; 
      hitRect.left = 0; 
      parent.setTouchDelegate(new TouchDelegate(hitRect , mApplyButton));   
     } 
    }); 
} 

Có lẽ nó có thể tiết kiệm thời gian của một ai đó

+0

đây là những gì làm việc cho tôi. nó thực sự làm cho toàn bộ phụ huynh gửi các sự kiện nhấp chuột cho đứa trẻ. nó thậm chí không phải là cha mẹ trực tiếp (có thể là cha mẹ của một phụ huynh). –

+0

Điều đó có thể hoạt động nếu bạn có một chế độ xem để ủy quyền. nếu bạn có, nói, 50 lượt xem để tăng cường diện tích cảm ứng? - Giống như trong Ảnh chụp màn hình này: https://plus.google.com/u/0/b/112127498414857833804/112127498414857833804/posts - TouchDelegate có phải là giải pháp thích hợp không? – Martin

1

không Đó có phải là ý tưởng tốt hơn về cho Padding đó đặc biệt thành phần (Button).

+1

Điều đó sẽ làm cho việc xem lớn hơn. Điều gì xảy ra nếu bạn có một số văn bản văn bản không phải là clickabe ở trên một nút và bạn muốn khu vực của văn bản đó được sử dụng để cải thiện độ chính xác của nhấp chuột cho nút. - Giống như trong Ảnh chụp màn hình này: https://plus.google.com/u/0/b/112127498414857833804/112127498414857833804/posts – Martin

1

Một chút muộn để đảng, nhưng sau khi nghiên cứu nhiều, Tôi bây giờ sử dụng:

/** 
* Expand the given child View's touchable area by the given padding, by 
* setting a TouchDelegate on the given ancestor View whenever its layout 
* changes. 
*/*emphasized text* 
public static void expandTouchArea(final View ancestorView, 
    final View childView, final Rect padding) { 

    ancestorView.getViewTreeObserver().addOnGlobalLayoutListener(
     new OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
       TouchDelegate delegate = null; 

       if (childView.isShown()) { 
        // Get hitRect in parent's coordinates 
        Rect hitRect = new Rect(); 
        childView.getHitRect(hitRect); 

        // Translate to ancestor's coordinates 
        int ancestorLoc[] = new int[2]; 
        ancestorView.getLocationInWindow(ancestorLoc); 

        int parentLoc[] = new int[2]; 
        ((View)childView.getParent()).getLocationInWindow(
         parentLoc); 

        int xOffset = parentLoc[0] - ancestorLoc[0]; 
        hitRect.left += xOffset; 
        hitRect.right += xOffset; 

        int yOffset = parentLoc[1] - ancestorLoc[1]; 
        hitRect.top += yOffset; 
        hitRect.bottom += yOffset; 

        // Add padding 
        hitRect.top -= padding.top; 
        hitRect.bottom += padding.bottom; 
        hitRect.left -= padding.left; 
        hitRect.right += padding.right; 

        delegate = new TouchDelegate(hitRect, childView); 
       } 

       ancestorView.setTouchDelegate(delegate); 
      } 
     }); 
} 

Đây là tốt hơn so với các giải pháp chấp nhận bởi vì nó cũng cho phép một TouchDelegate được đặt trên bất kỳ tổ tiên View, không chỉ là Chế độ xem gốc.

Không giống như giải pháp được chấp nhận, nó cũng cập nhật TouchDelegate bất cứ khi nào có thay đổi trong bố cục của tổ tiên.

0

Để mở rộng vùng cảm ứng một cách chung chung với các hạn chế khá ít, hãy sử dụng mã sau đây.

Tính năng này cho phép bạn mở rộng vùng cảm ứng của view nhất định trong chế độ xem ancestor nhất định theo expansion theo pixel. Bạn có thể chọn bất kỳ tổ tiên nào miễn là khung nhìn nhất định nằm trong cây bố trí tổ tiên.

public static void expandTouchArea(final View view, final ViewGroup ancestor, final int expansion) { 
    ancestor.post(new Runnable() { 
     public void run() { 
      Rect bounds = getRelativeBounds(view, ancestor); 
      Rect expandedBounds = expand(bounds, expansion); 
      // LOG.debug("Expanding touch area of {} within {} from {} by {}px to {}", view, ancestor, bounds, expansion, expandedBounds); 
      ancestor.setTouchDelegate(new TouchDelegate(expandedBounds, view)); 
     } 

     private Rect getRelativeBounds(View view, ViewGroup ancestor) { 
      Point relativeLocation = getRelativeLocation(view, ancestor); 
      return new Rect(relativeLocation.x, relativeLocation.y, 
          relativeLocation.x + view.getWidth(), 
          relativeLocation.y + view.getHeight()); 
     } 

     private Point getRelativeLocation(View view, ViewGroup ancestor) { 
      Point absoluteAncestorLocation = getAbsoluteLocation(ancestor); 
      Point absoluteViewLocation = getAbsoluteLocation(view); 
      return new Point(absoluteViewLocation.x - absoluteAncestorLocation.x, 
          absoluteViewLocation.y - absoluteAncestorLocation.y); 
     } 

     private Point getAbsoluteLocation(View view) { 
      int[] absoluteLocation = new int[2]; 
      view.getLocationOnScreen(absoluteLocation); 
      return new Point(absoluteLocation[0], absoluteLocation[1]); 
     } 

     private Rect expand(Rect rect, int by) { 
      Rect expandedRect = new Rect(rect); 
      expandedRect.left -= by; 
      expandedRect.top -= by; 
      expandedRect.right += by; 
      expandedRect.bottom += by; 
      return expandedRect; 
     } 
    }); 
} 

hạn chế áp dụng:

  • Khu vực cảm ứng không thể vượt quá giới hạn của tổ tiên của xem kể từ khi tổ tiên phải có khả năng nắm bắt những sự kiện liên lạc để chuyển tiếp nó để xem.
  • Chỉ một TouchDelegate mới có thể được đặt thành ViewGroup. Nếu bạn muốn làm việc với nhiều đại biểu cảm ứng, hãy chọn tổ tiên khác nhau hoặc sử dụng một đại biểu cảm ứng sáng tác như được giải thích trong How To Use Multiple TouchDelegate.
0

Bởi vì tôi không thích ý tưởng chờ đợi đèo bố trí chỉ để có được kích thước mới của hình chữ nhật của TouchDelegate, tôi đi kiếm một giải pháp khác nhau:

public class TouchSizeIncreaser extends FrameLayout { 
    public TouchSizeIncreaser(@NonNull Context context, @Nullable AttributeSet attrs) { 
     super(context, attrs); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent event) { 
     return true; 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     final View child = getChildAt(0); 
     if(child != null) { 
      child.onTouchEvent(event); 
     } 
     return true; 
    } 
} 

Và sau đó, trong một bố trí:

<ch.tutti.ui.util.TouchSizeIncreaser 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:padding="10dp"> 

    <Spinner 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center"/> 
</ch.tutti.ui.util.TouchSizeIncreaser> 

ý tưởng là TouchSizeIncreaser FrameLayout sẽ quấn Spinner (có thể là bất kỳ con View) và chuyển tiếp tất cả các sự kiện liên lạc bị bắt trong nó nhấn rect cho đứa trẻ View. Nó hoạt động cho các nhấp chuột, spinner sẽ mở ra ngay cả khi được nhấp bên ngoài giới hạn của nó, không chắc chắn ý nghĩa của các trường hợp phức tạp hơn.

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