2011-07-23 20 views
8

Mam dwa ImageButtons, każdy wewnątrz RelativeLayout i te dwa RelativeLayouts są w innym RelativeLayout, chcę ustawić TouchDelegate dla każdego ImageButton. Jeśli normalnie dodaję TouchDelegate do każdego ImageButton i jego rodzica RelativeLayout, to tylko jeden ImageButton działa poprawnie, Inny nie rozszerza jego obszaru klikania. Więc PLease pomoże mi w użyciu TouchDelegate w obu ImageButtons. Jeśli nie jest to możliwe, jaki może być skuteczny sposób rozszerzenia obszaru klikania widoku? Z góry dzięki ........Jak korzystać z wielu TouchDelegate

Tu jest mój kodu xml:

<?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> 

Moja klasa aktywny:

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

} 

}

Odpowiedz

3

Jest tylko powinien być jednym dotknięciem delegata dla każdego widoku. Dokumentacja getTouchDelegate() w klasie View brzmi:

"Pobiera TouchDelegate dla tego widoku."

Istnieje tylko jedno urządzenie TouchDelegate. Aby użyć tylko jednego TouchDelegate na widok, możesz zawinąć każdy dotykowy widok w widoku z wymiarami odzwierciedlającymi to, co chcesz dotknąć. Android developer na placu daje przykład, jak można to zrobić dla wielu Wyświetleń użyciem jednej metody statycznej (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)); 
    } 
}); 

}

Załóżmy, że nie chcesz zaśmiecać hierarchii widoku. Są dwie inne opcje, które mogę wymyślić. Możesz zdefiniować granice tego, co jest dotykalne wewnątrz dotykowego widoku i upewnij się, że przekazujesz wszystkie efekty touchevent do tego widoku podrzędnego z odpowiednich widoków rodzica. Lub możesz zastąpić getHitRect() dla dotykalnego widoku. Ten pierwszy szybko zapakuje twój kod i sprawi, że będzie go trudno zrozumieć, więc to drugie jest lepszym rozwiązaniem. Chcesz iść z nadpisaniem getHitRect.

Gdzie mPadding to ilość dodatkowego obszaru chcesz być dotykalne wokół widzenia, można użyć coś jak poniżej:

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

Jeśli użyć kodu jak wyżej będziesz musiał rozważyć, co wrażliwe widoki są w pobliżu. Dotykalny obszar widoku, który jest najwyższy na stosie, może nakładać się na inny widok.

Inną podobną opcją byłoby po prostu zmienić dopełnienie widoku dotykowego. Nie podoba mi się to jako rozwiązanie, ponieważ trudno jest śledzić sposób zmiany rozmiaru widoków.

+1

Próbowałem przesłonić getHitRect, ale nie działa (nie jest w ogóle wywoływany). Zasadniczo mogę utworzyć niestandardowy widok, który rozszerza ImageButton, a następnie w klasie I przesłonię getHitRect (z dodanym dopełnieniem), ale jak już wspomniałem, getHitRect nigdy nie zostanie wywołany. Czy można opublikować swoje rozwiązanie? – stephenteh

+2

Okazuje się, że oferowane przeze mnie rozwiązanie nie działa w ICS, może dlatego nie działa dla Ciebie. Napisałem post na blogu na temat dwóch różnych strategii Delegatów dotykowych http://www.brendanweinstein.me/2012/06/26/touchdelegate-and-gethitrect-making-buttons-with-expanded-touch-areas/ i możesz pobrać próbkę kod dla obu strategii na https://github.com/brendanw/Touch-Delegates/blob/master/src/com/brendan/touchdelegates/MyTouchDelegate.java –

+0

To nie odpowiada na pytanie OP. OP nie próbuje dodać wielu delegatów do jednego widoku. Dwa '' ImageButton''s w przykładzie OP mają * różnych * rodziców. – zyamys

15

Można użyć kompozytu wzór, aby móc dodać więcej niż jeden TouchDelegate do widoku.Kroki:

  1. Tworzenie TouchDelegateComposite (bez względu na to, co zobaczyć miniesz jako argument jest używany tylko po to żeby kontekstu)
  2. Tworzenie niezbędnych TouchDelegates i dodać je do kompozytowego
  3. Dodaj kompozytu widok jak zalecają here (przez view.post (nowa 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

To jest o wiele lepsze rozwiązanie, nieprzechwycona hierarchia widoków pełna widoków wrapperów lub mieszanie z dopełnieniem, bez konieczności podklasowania widoków w celu nadpisania metody getHitRect(). Jedną z pomniejszych sugestii byłoby włączenie metody expandTouchArea() z odpowiedzi @Brendana Weinsteina do tej klasy ze względu na czystość/łatwość. – AndroidNoob

+2

Zaadaptowałem to rozwiązanie, aby rozszerzyć klikalny obszar widoków z tym samym rodzica: [gist] (https://gist.github.com/nikosk/3854f2effe65438cfa40) @AndroidNoob: dodano statyczną metodę łatwego użycia. Używane w ten sposób: TouchDelegateComposite.expandClickArea (buttonView, parentView, clickListener, paddingInDP); – javito

+0

To nie odpowiada na pytanie OP. OP nie próbuje dodać wielu delegatów do jednego widoku. Dwa '' ImageButton''s w przykładzie OP mają * różnych * rodziców. – zyamys

0

Aby dokonać kod działa, aby zmniejszyć lewą granicę bounds2, a nie ją zwiększyć.

bounds2.left -= 50; 

Po zabawy z TouchDelegate, doszedłem do poniżej kod, który pracuje dla mnie cały czas na każdej wersji Androida. Sztuczka polega na rozszerzeniu obszaru gwarantowanego po wywołaniu układu.

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 chyba nikt zapewnia prawdziwą odpowiedź, aby roztwór i uczynić go easy.Lately miałem ten sam problem i czyta wszystko powyżej i po prostu nie miał pojęcia, jak to zrobić work.But wreszcie zrobiłem Najpierw pamiętaj, że masz cały układ, w którym trzymasz dwa małe guziki, który obszar musi zostać rozszerzony, więc MUSISZ zrobić kolejny układ w twoim głównym layoucie i włożyć inny przycisk do nowo utworzonego układu, tak aby w takim przypadku za pomocą metody statycznej można przekazać dotykiem dwa przyciski jednocześnie. Teraz głębiej i krok po kroku w kod! pierwszy na pewno po prostu znaleźć się widokiem swojej MAINLAYOUT i przycisk tak. (Ten układ będzie posiadał nasz pierwszy przycisk)

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

ok zrobiliśmy znalezienia główny układ i jego przycisk widok, który będzie trzymać wszystko to tylko nasze onCreate() wyświetlając układ, ale musisz znaleźć w przypadku korzystania z niego później.Na co dalej? Tworzymy kolejny RelativeLayout wewnątrz naszego głównego układu, którego szerokość i wysokość jest w twoim guście (ten nowo utworzony układ będzie trzymał nasz drugi przycisk)

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

ok zrobiliśmy znalezienie widoków, więc możemy teraz po prostu skopiować i wkleić c Ode naszego faceta, który najpierw odpowiedział na twoje pytanie. Tylko skopiuj ten kod do głównej działalności.

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

Teraz, jak korzystać z tej metody i jak to działa? Oto jak to zrobić! od metody onCreate() wklej następny kod snippet

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

wyjaśnienie o co zrobiliśmy w tym snipped.We wziął nasz tworzony metodą statyczną o nazwie expandTouchArea() i dał 3 argumenty. Pierwszy argument - układ, w którym znajduje się przycisk, który obszar musi zostać rozwinięty Drugi argument - aktualny przycisk, aby rozwinąć jego obszar Trzeci argument - obszar w pikselach, o ile chcemy rozszerzyć obszar przycisku! CIESZ SIĘ!

0

Miałem ten sam problem: Próbuję dodać wiele różnych TouchDelegates dla różnych, które kierują zdarzenia dotykowe, aby odpowiednio oddzielić Switches, w jednym układzie.

Aby uzyskać szczegółowe informacje, należy zapoznać się z this question asked by me i my answer.

Co znalazłem to: Raz Załączam każdy z LinearLayouts przez innyLinearLayout, odpowiednio, drugie (co drugi koniec kolejnych) TouchDelegate zacznie działać zgodnie z oczekiwaniami.

Może to pomóc OP stworzyć skuteczne rozwiązanie jego problemu. Nie mam zadowalającego wyjaśnienia, dlaczego tak się zachowuje.

Powiązane problemy