2011-07-23 15 views
8

tôi có hai ImageButton, mỗi bên trong một RelativeLayout và hai RelativeLayouts này nằm trong một RelativeLayout khác, tôi muốn đặt TouchDelegate cho mỗi ImageButton. Nếu bình thường tôi thêm TouchDelegate vào mỗi ImageButton và nó là RelativeLayout mẹ thì chỉ một ImageButton hoạt động đúng, một cái khác không mở rộng vùng nhấp của nó. Vì vậy, xin vui lòng giúp tôi về cách sử dụng TouchDelegate trong cả hai ImageButtons. Nếu không thể, thì điều gì có thể là một cách hiệu quả để mở rộng vùng nhấp của chế độ xem? Cảm ơn trước ........Cách sử dụng nhiều TouchDelegate

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

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout android:id="@+id/FrameContainer" 
android:layout_width="fill_parent" android:layout_height="fill_parent" 
xmlns:android="http://schemas.android.com/apk/res/android"> 
<RelativeLayout android:layout_alignParentLeft="true" 
    android:id="@+id/relativeLayout3" android:layout_width="wrap_content" 
    android:layout_height="wrap_content"> 
    <RelativeLayout android:layout_alignParentLeft="true" 
     android:id="@+id/relativeLayout1" android:layout_width="113dip" 
     android:layout_height="25dip"> 
     <ImageButton android:id="@+id/tutorial1" 
      android:layout_width="wrap_content" android:layout_height="wrap_content" 
      android:background="@null" android:src="@drawable/tutorial" /> 
    </RelativeLayout> 
    <RelativeLayout android:layout_alignParentLeft="true" 
     android:id="@+id/relativeLayout2" android:layout_width="113dip" 
     android:layout_height="25dip" android:layout_marginLeft="100dip"> 
     <ImageButton android:id="@+id/tutorial2" 
      android:layout_width="wrap_content" android:layout_height="wrap_content" 
      android:background="@null" android:src="@drawable/tutorial" 
      android:layout_marginLeft="50dip" /> 
    </RelativeLayout> 
</RelativeLayout> 

lớp Hoạt động của tôi:

import android.app.Activity; 
import android.graphics.Rect; 
import android.os.Bundle; 
import android.view.TouchDelegate; 
import android.view.View; 
import android.widget.ImageButton; 
import android.widget.Toast; 

public class TestTouchDelegate extends Activity { 
/** Called when the activity is first created. */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    View mParent1 = findViewById(R.id.relativeLayout1); 
    mParent1.post(new Runnable() { 
     @Override 
     public void run() { 
      Rect bounds1 = new Rect(); 
      ImageButton mTutorialButton1 = (ImageButton) findViewById(R.id.tutorial1); 
      mTutorialButton1.setEnabled(true); 
      mTutorialButton1.setOnClickListener(new View.OnClickListener() { 
       public void onClick(View view) { 
        Toast.makeText(TestTouchDelegate.this, "Test TouchDelegate 1", Toast.LENGTH_SHORT).show(); 
       } 
      }); 

      mTutorialButton1.getHitRect(bounds1); 
      bounds1.right += 50; 
      TouchDelegate touchDelegate1 = new TouchDelegate(bounds1, mTutorialButton1); 

      if (View.class.isInstance(mTutorialButton1.getParent())) { 
       ((View) mTutorialButton1.getParent()).setTouchDelegate(touchDelegate1); 
      } 
     } 
    }); 

    //View mParent = findViewById(R.id.FrameContainer); 
    View mParent2 = findViewById(R.id.relativeLayout2); 
    mParent2.post(new Runnable() { 
     @Override 
     public void run() { 
      Rect bounds2 = new Rect(); 
      ImageButton mTutorialButton2 = (ImageButton) findViewById(R.id.tutorial2); 
      mTutorialButton2.setEnabled(true); 
      mTutorialButton2.setOnClickListener(new View.OnClickListener() { 
       public void onClick(View view) { 
        Toast.makeText(TestTouchDelegate.this, "Test TouchDelegate 2", Toast.LENGTH_SHORT).show(); 
       } 
      }); 

      mTutorialButton2.getHitRect(bounds2); 
      bounds2.left += 50; 
      TouchDelegate touchDelegate2 = new TouchDelegate(bounds2, mTutorialButton2); 

      if (View.class.isInstance(mTutorialButton2.getParent())) { 
       ((View) mTutorialButton2.getParent()).setTouchDelegate(touchDelegate2); 
      } 
     } 
    }); 

} 

}

Trả lời

3

Có chỉ được coi là đại diện một chạm cho mỗi lượt xem. Tài liệu cho getTouchDelegate() trong lớp Chế độ xem đọc:

"Lấy TouchDelegate cho Chế độ xem này".

Chỉ có một TouchDelegate. Để chỉ sử dụng một TouchDelegate cho mỗi chế độ xem, bạn có thể bao bọc từng chế độ xem có thể chạm trong chế độ xem có kích thước phản ánh những gì bạn muốn có thể chạm được. Một nhà phát triển Android tại quảng trường đưa ra một ví dụ về cách bạn có thể làm điều này cho nhiều lần xem chỉ sử dụng một phương pháp tĩnh (http://www.youtube.com/watch?v=jF6Ad4GYjRU & t = 37m4s):

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)); 
    } 
}); 

}

Giả sử bạn không muốn làm lộn xộn phân cấp chế độ xem của mình. Có hai lựa chọn khác mà tôi có thể nghĩ đến. Bạn có thể xác định giới hạn của những gì có thể chạm vào bên trong giao diện có thể chạm và đảm bảo truyền tất cả các liên lạc đến chế độ xem con đó từ các chế độ xem gốc tương ứng. Hoặc bạn có thể ghi đè getHitRect() cho chế độ xem có thể chạm. Các cựu sẽ nhanh chóng lộn xộn mã của bạn và làm cho nó khó hiểu, vì vậy sau này là cách tốt hơn về phía trước. Bạn muốn đi với trọng điểm getHitRect.

đâu mPadding là số tiền của khu vực có thêm bạn muốn trở thành có thể sờ xung quanh xem, bạn có thể sử dụng giống như sau:

@Override 
public void getHitRect(Rect outRect) { 
    outRect.set(getLeft() - mPadding, getTop() - mPadding, getRight() + mPadding, getTop() + mPadding); 
} 

Nếu bạn sử dụng mã như trên bạn sẽ phải xem xét những gì tầm nhìn có thể chạm được ở gần đó. Vùng có thể chạm của Chế độ xem cao nhất trên ngăn xếp có thể chồng lên nhau trên một Chế độ xem khác.

Một tùy chọn tương tự khác là chỉ thay đổi phần đệm của chế độ xem có thể chạm. Tôi không thích điều này như là một giải pháp bởi vì nó có thể trở nên khó khăn để theo dõi cách xem được thay đổi kích cỡ.

+1

Tôi đã cố gắng ghi đè getHitRect nhưng dường như nó không hoạt động (nó hoàn toàn không được gọi). Về cơ bản tôi tạo ra một cái nhìn tùy chỉnh mở rộng một ImageButton sau đó trong lớp tôi ghi đè lên getHitRect (với padding thêm) nhưng như tôi đã đề cập, getHitRect không bao giờ được gọi. Có thể đăng giải pháp của bạn không? – stephenteh

+2

Hóa ra giải pháp mà tôi cung cấp không hoạt động trong ICS, đó có thể là lý do tại sao nó không hoạt động cho bạn. Tôi đã viết một bài đăng trên blog về hai chiến lược Liên đoàn đại biểu khác nhau http://www.brendanweinstein.me/2012/06/26/touchdelegate-and-gethitrect-making-buttons-with-expanded-touch-areas/ và bạn có thể lấy mẫu mã cho cả hai chiến lược tại https://github.com/brendanw/Touch-Delegates/blob/master/src/com/brendan/touchdelegates/MyTouchDelegate.java –

+0

Điều này không trả lời câu hỏi OP. OP không cố thêm nhiều đại biểu vào một chế độ xem. Hai '' ImageButton''s trong ví dụ OP có * cha mẹ * khác nhau. – zyamys

0
+0

Lưu ý rằng các câu trả lời chỉ có liên kết không được khuyến khích, các câu trả lời SO phải là điểm kết thúc của một tìm kiếm cho một giải pháp (so với một điểm dừng khác của các tham chiếu, có xu hướng bị cũ theo thời gian). Vui lòng xem xét thêm bản tóm tắt độc lập tại đây, giữ liên kết dưới dạng tham chiếu. – kleopatra

15

Bạn có thể sử dụng Composite Pattern để có thể thêm nhiều hơn một TouchDelegate cho View.Bước sau:

  1. Tạo TouchDelegateComposite (không có vấn đề gì xem bạn sẽ vượt qua như một cuộc tranh cãi , nó được sử dụng chỉ để có được bối cảnh)
  2. Tạo TouchDelegates cần thiết và thêm chúng vào hỗn
  3. Thêm composite xem như họ đề nghị here (thông qua view.post (new Runnable))

    public class TouchDelegateComposite extends TouchDelegate { 
    
        private final List<TouchDelegate> delegates = new ArrayList<TouchDelegate>(); 
        private static final Rect emptyRect = new Rect(); 
    
        public TouchDelegateComposite(View view) { 
         super(emptyRect, view); 
        } 
    
        public void addDelegate(TouchDelegate delegate) { 
         if (delegate != null) { 
          delegates.add(delegate); 
         } 
        } 
    
        @Override 
        public boolean onTouchEvent(MotionEvent event) { 
         boolean res = false; 
         float x = event.getX(); 
         float y = event.getY(); 
         for (TouchDelegate delegate : delegates) { 
          event.setLocation(x, y); 
          res = delegate.onTouchEvent(event) || res; 
         } 
         return res; 
        } 
    
    } 
    
+0

Đây là một giải pháp tốt hơn nhiều, không phải hệ thống phân cấp xem lộn xộn đầy đủ các khung nhìn wrapper, hoặc rối tung với đệm, và không cần cho các khung nhìn lớp con để ghi đè phương thức getHitRect(). Một gợi ý nhỏ sẽ là kết hợp phương thức expandTouchArea() từ câu trả lời của @Brendan Weinstein vào lớp này vì lợi ích của sự gọn gàng/dễ dàng. – AndroidNoob

+2

Tôi đã điều chỉnh giải pháp này để mở rộng khu vực có thể nhấp có cùng chế độ xem: [gist] (https://gist.github.com/nikosk/3854f2effe65438cfa40) @AndroidNoob: bao gồm một phương pháp tĩnh để dễ sử dụng. Được sử dụng như thế này: TouchDelegateComposite.expandClickArea (buttonView, parentView, clickListener, paddingInDP); – javito

+0

Điều này không trả lời câu hỏi OP. OP không cố thêm nhiều đại biểu vào một chế độ xem. Hai '' ImageButton''s trong ví dụ OP có * cha mẹ * khác nhau. – zyamys

0

Để làm cho bạn mã hoạt động bạn cần phải giảm đường viền trái của bounds2 và không tăng nó.

bounds2.left -= 50; 

Sau khi chơi xung quanh với TouchDelegate, tôi đến với mã bên dưới, luôn hoạt động trên mọi phiên bản Android. Bí quyết là để mở rộng khu vực bảo đảm sau khi bố trí được gọi là.

public class ViewUtils { 

    public static final void extendTouchArea(final View view, 
      final int padding) { 

     view.getViewTreeObserver().addOnGlobalLayoutListener(
       new OnGlobalLayoutListener() { 

      @Override 
      @SuppressWarnings("deprecation") 
      public void onGlobalLayout() { 
       final Rect touchArea = new Rect(); 
       view.getHitRect(touchArea); 
       touchArea.top -= padding; 
       touchArea.bottom += padding; 
       touchArea.left -= padding; 
       touchArea.right += padding; 

       final TouchDelegate touchDelegate = 
        new TouchDelegate(touchArea, view); 
       final View parent = (View) view.getParent(); 
       parent.setTouchDelegate(touchDelegate); 

       view.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
      } 
     }); 
    } 

} 
0

Ok tôi đoán không ai cung cấp câu trả lời thực sự để làm cho giải pháp của nó và làm cho nó easy.Lately tôi đã có cùng một vấn đề và đọc tất cả ở trên tôi chỉ không có đầu mối như thế nào chỉ để làm cho nó work.But cuối cùng tôi đã làm Cho phép giả vờ bạn có một bố trí toàn bộ đang giữ hai nút nhỏ của bạn mà khu vực phải được mở rộng, vì vậy bạn PHẢI thực hiện một bố cục khác bên trong bố cục chính của bạn và đặt một nút khác vào bố cục mới được tạo của bạn trong trường hợp đó với phương thức tĩnh, bạn có thể cung cấp cho đại biểu liên lạc đến 2 nút cùng một lúc.Bây giờ sâu hơn và từng bước vào mã! đầu tiên bạn chắc chắn chỉ cần tìm quan điểm của MAINLAYOUT và Button của bạn như thế này. (Bố cục này sẽ giữ nút đầu tiên của chúng tôi)

RelativeLayout mymainlayout = (RelativeLayout)findViewById(R.id.mymainlayout) 
Button mybutoninthislayout = (Button)findViewById(R.id.mybutton) 

ok chúng tôi thực hiện việc tìm kiếm cách bố trí chính và xem nút của nó mà sẽ giữ tất cả mọi thứ chỉ mình chúng tôi onCreate() hiển thị bố cục nhưng bạn phải tìm trong trường hợp sử dụng nó sau này.Kì gì tiếp theo? Chúng tôi tạo một RelativeLayout khác bên trong bố cục chính của chúng tôi mà chiều rộng và chiều cao là vị của bạn (bố cục mới được tạo này sẽ giữ nút thứ hai của chúng tôi)

RelativeLayout myinnerlayout = (RelativeLayout)findViewById(R.id.myinnerlayout) 
Button mybuttoninsideinnerlayout = (Button)findViewById(R.id.mysecondbutton) 

ok, chúng tôi đã hoàn thành việc tìm kiếm chế độ xem để chúng tôi có thể chỉ cần sao chép và dán c ode của anh chàng của chúng tôi, người đầu tiên trả lời câu hỏi của bạn.Chỉ cần sao chép mã đó bên trong hoạt động chính của bạ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)); 
     } 
    }); 
} 

Bây giờ, làm thế nào để sử dụng phương pháp này và làm cho nó hoạt động? trên phương pháp onCreate() bạn dán đoạn mã mã tiếp theo

expandTouchArea(mymainlayout,mybutoninthislayout,60); 
    expandTouchArea(myinnerlayout, mybuttoninsideinnerlayout,60); 

Giải thích về những gì chúng tôi đã làm trong snipped.We này mất phương pháp tĩnh tạo của chúng tôi đặt tên expandTouchArea() và đưa 3 đối số. Đối số thứ nhất-Bố cục chứa nút mà khu vực phải được mở rộng Đối số thứ 2 - nút thực để mở rộng diện tích của nó Đối số thứ ba - diện tích bằng pixel bao nhiêu chúng tôi muốn khu vực nút được mở rộng! ENJOY!

0

Tôi có cùng một sự cố: Cố gắng thêm nhiều TouchDelegates cho các sự kiện khác nhau LinearLayouts định tuyến các sự kiện chạm để tách riêng Switches tương ứng, trong một bố cục.

Để biết chi tiết, vui lòng tham khảo this question asked by memy answer.

Những gì tôi thấy là: Một khi tôi gửi kèm theo mỗi sự LinearLayouts bởi khácLinearLayout, tương ứng, thứ hai (cuối mỗi khác liên tiếp) TouchDelegate bắt đầu làm việc như mong đợi.

Vì vậy, điều này có thể giúp OP tạo ra giải pháp làm việc cho vấn đề của mình. Tôi không có một giải thích thỏa đáng về lý do tại sao nó cư xử như thế này, mặc dù.

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