Mam imageview w mojej aplikacji na Androida, którego używam jak przycisku z podanym zdarzeniem onClick, ale jak możesz się domyślić, po kliknięciu nie daje on efektu klikalności Imageview. Jak mogę to osiągnąć?
84
Możesz zaprojektować różne obrazy dla stanów klikniętych / nie klikniętych i ustawić je w onTouchListener w następujący sposób
final ImageView v = (ImageView) findViewById(R.id.button0);
v.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
switch (arg1.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.setImageBitmap(res.getDrawable(R.drawable.img_down));
break;
}
case MotionEvent.ACTION_CANCEL:{
v.setImageBitmap(res.getDrawable(R.drawable.img_up));
break;
}
}
return true;
}
});
Lepszym wyborem jest zdefiniowanie selektora w następujący sposób
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true"
android:drawable="@drawable/img_down" />
<item android:state_selected="false"
android:drawable="@drawable/img_up" />
</selector>
i wybierz zdjęcie w przypadku:
v.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
v.setSelected(arg1.getAction()==MotionEvent.ACTION_DOWN);
return true;
}
});
MotionEvent.ACTION_DOWN || MotionEvent.ACTION_MOVE
aby obraz był widoczny, dopóki naciskamy.setOnTouchListener(...
. Możesz po prostu utworzyć,<selector ...>
a następnie ustawić klikalny ImageView w XML, na przykład<ImageView ... android:clickable="true" android:focusable="true" android:src="@drawable/my_selector" />
Możesz to zrobić z pojedynczym obrazem, używając czegoś takiego:
//get the image view ImageView imageView = (ImageView)findViewById(R.id.ImageView); //set the ontouch listener imageView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { ImageView view = (ImageView) v; //overlay is black with transparency of 0x77 (119) view.getDrawable().setColorFilter(0x77000000,PorterDuff.Mode.SRC_ATOP); view.invalidate(); break; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { ImageView view = (ImageView) v; //clear the overlay view.getDrawable().clearColorFilter(); view.invalidate(); break; } } return false; } });
Prawdopodobnie zrobię to w podklasie ImageView (lub ImageButton, ponieważ jest to również podklasa ImageView), aby ułatwić ponowne użycie, ale powinno to umożliwić zastosowanie „wybranego” wyglądu do widoku obrazu.
źródło
false
, w przeciwnym razie rzeczywisteonClick()
zdarzenie widoku nie zostanie uruchomioneMożna to zrobić z jednym plikiem obrazu przy użyciu metody ColorFilter. Jednak ColorFilter oczekuje, że będzie działać z ImageViews, a nie Buttons, więc musisz przekształcić swoje przyciski w ImageViews. Nie stanowi to problemu, jeśli i tak używasz obrazów jako przycisków, ale jest bardziej irytujące, jeśli masz tekst ... W każdym razie, zakładając, że znajdziesz sposób na obejście problemu z tekstem, oto kod do użycia:
ImageView button = (ImageView) findViewById(R.id.button); button.setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
Powoduje to nałożenie czerwonej nakładki na przycisk (kod koloru to kod szesnastkowy całkowicie nieprzezroczystej czerwieni - pierwsze dwie cyfry to przezroczystość, a następnie jest to RR GG BB.).
źródło
EDYCJA : Chociaż oryginalna odpowiedź poniżej działa i jest łatwa do skonfigurowania, zapoznaj się z tym postem napisanym przez rzecznika programistów Androida w Google, jeśli chcesz / potrzebujesz bardziej wydajnej implementacji. Należy również zauważyć, że
android:foreground
atrybut jest domyślnie dostępny we wszystkich widokach, w tym ImageView, w systemie Android M.Problem z używaniem selektora dla ImageView polega na tym, że możesz ustawić go tylko jako tło widoku - dopóki obraz jest nieprzezroczysty, nie zobaczysz efektu selektora za nim.
Sztuczka polega na owinięciu ImageView w FrameLayout atrybutem,
android:foreground
który pozwala nam zdefiniować nakładkę dla jego zawartości. Jeśli ustawimyandroid:foreground
selektor (np.?android:attr/selectableItemBackground
Dla poziomu API 11+) iOnClickListener
dołączymy do FrameLayout zamiast ImageView, obraz zostanie nałożony na nasz selektor do rysowania - pożądany efekt kliknięcia!Ujrzeć:
<FrameLayout android:id="@+id/imageButton" android:layout_width="match_parent" android:layout_height="match_parent" android:foreground="?android:attr/selectableItemBackground" > <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/yourImageFile" /> </FrameLayout>
(Pamiętaj, że powinno to być umieszczone w układzie nadrzędnym).
final View imageButton = findViewById(R.id.imageButton); imageButton.setOnClickListener(new OnClickListener(){ @Override public void onClick(View view) { // do whatever we wish! } });
źródło
selectableItemBackground
Atrybut został dodany tylko w poziomie API 11, więc trzeba użyć innego wyboru, jeśli chcesz korzystać z tego rozwiązania dla starszych poziomów API. Na przykład w przypadku jednej z moich aplikacji obsługujących poziom interfejsu API 7 używam@drawable/list_selector_holo_light
zasobu wygenerowanego za pomocą narzędzia Android Holo Colours Generator .<ImageButton>
z selectableItemBackground!Użyj style = "? Android: borderlessButtonStyle" w pliku XML. Pokaże domyślny efekt kliknięcia Androida.
<ImageView android:id="@+id/imageView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" style="?android:borderlessButtonStyle" />
źródło
android:adjustViewBounds="true"
do anulowania dopełnienia.style="?android:attr/borderlessButtonStyle"
: developer.android.com/guide/topics/ui/controls/…Po prostu użyj ImageButton .
źródło
Oto mój prosty sposób na rozwiązanie tego problemu:
ImageView iv = (ImageView) findViewById(R.id.imageView); iv.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub //Agrega porcentajes de cada fraccion de grafica pastel Animation animFadein = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fade_in); iv.startAnimation(animFadein); });
W pliku
res/anim/fade_in.xml
:<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true" > <alpha android:duration="100" android:fromAlpha="0.0" android:interpolator="@android:anim/accelerate_interpolator" android:toAlpha="1.0" /> </set>
źródło
Ustaw wybieralne tło na ImageView i dodaj trochę wypełnienia. Następnie dołącz
OnClickListener
.<ImageView android:id="@+id/your_image_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/your_image" android:padding="10dp" android:background="?android:attr/selectableItemBackground"/>
źródło
Do definiowania wyboru do rysowania selektora
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:drawable="@drawable/img_down" /> <item android:state_selected="false" android:drawable="@drawable/img_up" /> </selector>
Muszę używać android: state_pressed zamiast android: state_selected
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed ="true" android:drawable="@drawable/img_down" /> <item android:state_pressed ="false" android:drawable="@drawable/img_up" /> </selector>
źródło
Możesz spróbować z,
android:background="@android:drawable/list_selector_background"
aby uzyskać ten sam efekt, co „Dodaj alarm” w domyślnym „Budzik” (teraz Zegar na biurko).źródło
Jeśli chcesz mieć ripple po dotknięciu, możesz podać ten kod:
<ImageView ... android:background="?attr/selectableItemBackgroundBorderless" android:clickable="true" ... </ImageView>
Podobnie możesz zaimplementować efekt kliknięcia dla TextView
<TextView ... android:background="?attr/selectableItemBackgroundBorderless" android:clickable="true" ... </TextView>
źródło
To zadziałało dla mnie:
img.setOnTouchListener(new OnTouchListener(){ @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { ((ImageView)v).setImageAlpha(200); break; } case MotionEvent.ACTION_MOVE: { // if inside bounds if(event.getX() > 0 && event.getX() < v.getWidth() && event.getY() > 0 && event.getY() < v.getHeight()) { ((ImageView)v).setImageAlpha(200); } else { ((ImageView)v).setImageAlpha(255); } break; } case MotionEvent.ACTION_UP: { ((ImageView)v).setImageAlpha(255); } } return true; } });
@Edit: Jak powiedział Gunhan, wystąpi problem z kompatybilnością wsteczną z metodą setImageAlpha. Użyłem tej metody:
public static void setImageAlpha(ImageView img, int alpha) { if(Build.VERSION.SDK_INT > 15) { img.setImageAlpha(alpha); } else { img.setAlpha(alpha); } }
źródło
Robię kilka podobnych rzeczy. Zobacz, które są dla Ciebie odpowiednie, czy nie
Zobacz pomocnika efektu prasowego:
użycie: wykonaj prosty efekt prasowy, taki jak iOS
Proste użycie:
ImageView img = (ImageView) findViewById (R.id.img);
https://gist.github.com/extralam/7489370
źródło
W połączeniu ze wszystkimi powyższymi odpowiedziami chciałem, aby ImageView został naciśnięty i zmienił stan, ale jeśli użytkownik się poruszył, „anuluj” i nie wykonuj onClickListener.
Skończyło się na utworzeniu obiektu Point w klasie i ustawieniu jego współrzędnych w zależności od tego, kiedy użytkownik nacisnął ImageView. W MotionEvent.ACTION_UP nagrywam nowy punkt i porównałem punkty.
Mogę to tylko dobrze wyjaśnić, ale oto co zrobiłem.
// set the ontouch listener weatherView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // Determine what action with a switch statement switch (event.getAction()) { // User presses down on the ImageView, record the original point // and set the color filter case MotionEvent.ACTION_DOWN: { ImageView view = (ImageView) v; // overlay is black with transparency of 0x77 (119) view.getDrawable().setColorFilter(0x77000000, PorterDuff.Mode.SRC_ATOP); view.invalidate(); p = new Point((int) event.getX(), (int) event.getY()); break; } // Once the user releases, record new point then compare the // difference, if within a certain range perform onCLick // and or otherwise clear the color filter case MotionEvent.ACTION_UP: { ImageView view = (ImageView) v; Point f = new Point((int) event.getX(), (int) event.getY()); if ((Math.abs(f.x - p.x) < 15) && ((Math.abs(f.x - p.x) < 15))) { view.performClick(); } // clear the overlay view.getDrawable().clearColorFilter(); view.invalidate(); break; } } return true; } });
Mam ustawiony onClickListener na imageView, ale może to być metoda.
źródło
MotionEvent.ACTION_CANCEL
z taką samą funkcjonalnością jakMotionEvent.ACTION_UP
wtedy możliwe jest „wyczyszczenie” widoku, jeśli użytkownik wykona „przeciągnięcie”, które nie jest akcją kliknięcia.Możesz Override
setPressed
w ImageView i tam wykonać filtrowanie kolorów, zamiast tworzyć detektory onTouchEvent:@Override public void setPressed(boolean pressed) { super.setPressed(pressed); if(getDrawable() == null) return; if(pressed) { getDrawable().setColorFilter(0x44000000, PorterDuff.Mode.SRC_ATOP); invalidate(); } else { getDrawable().clearColorFilter(); invalidate(); } }
źródło
W oparciu o odpowiedź pana Zorna używam metody statycznej w mojej abstrakcyjnej klasie Utility:
public abstract class Utility { ... public static View.OnTouchListener imgPress(){ return imgPress(0x77eeddff); //DEFAULT color } public static View.OnTouchListener imgPress(final int color){ return new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch(event.getAction()) { case MotionEvent.ACTION_DOWN: { ImageView view = (ImageView) v; view.getDrawable().setColorFilter(color, PorterDuff.Mode.SRC_ATOP); view.invalidate(); break; } case MotionEvent.ACTION_UP: v.performClick(); case MotionEvent.ACTION_CANCEL: { ImageView view = (ImageView) v; //Clear the overlay view.getDrawable().clearColorFilter(); view.invalidate(); break; } } return true; } }; } ... }
Następnie używam go z onTouchListener:
ImageView img=(ImageView) view.findViewById(R.id.image); img.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /* Your click action */ } }); img_zc.setOnTouchListener(Utility.imgPress()); //Or Utility.imgPress(int_color_with_alpha)
Jest to bardzo proste, jeśli masz dużo obrazów i chcesz mieć prosty efekt onTouch, bez żadnego XML-a do rysowania i tylko jeden obraz.
źródło
Użyj
android.widget.Button
i ustaw jegobackground
właściwość naandroid.graphics.drawable.StateListDrawable
. Wszystko to można zrobić w XML lub programowo. Zobacz sekcję Przycisk niestandardowy w samouczku dotyczącym elementów formularza .źródło
Tworzę tutaj przykład , po prostu zmień ImageView na ClickableImageView z twojego układu. Mam nadzieję, że to pomoże.
źródło
Myślę, że ImageButton jest lepszym rozwiązaniem
<ImageButton android:layout_width="96dp" android:layout_height="56dp" android:src="@mipmap/ic_launcher" android:adjustViewBounds="true" android:background="@android:color/transparent" android:foreground="@drawable/selector" />
źródło
Mam bardziej upiększające rozwiązanie, jeśli używasz obrazów tła :)
public static void blackButton(View button){ button.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { v.getBackground().setColorFilter(0xf0f47521,PorterDuff.Mode.SRC_ATOP); v.invalidate(); break; } case MotionEvent.ACTION_UP: { v.getBackground().clearColorFilter(); v.invalidate(); break; } } return false; } }); }
źródło
LUB:
Możesz użyć tego formularza, z przyciskiem Obraz.
Utwórz plik
res/drawable/btn_video.xml
:<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/image" android:state_pressed="true" /> <item android:drawable="@drawable/ico2" android:state_focused="true" /> <item android:drawable="@drawable/ico2" /> </selector>
Oraz
res/layout/activity_main.xml
:<ImageButton android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/imageButton" android:layout_gravity="center_horizontal" android:onClick="eventImageBtn" android:background="@drawable/btn_video" android:adjustViewBounds="true" android:scaleType="fitXY" />
Twój obraz zmienia się jednym kliknięciem i możesz dostosować go za pomocą układu liniowego:
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@color/menu_item_background"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingLeft="@dimen/main_screen_side_padding" android:paddingRight="@dimen/main_screen_side_padding" android:paddingTop="@dimen/main_screen_side_padding" android:paddingBottom="@dimen/main_screen_side_padding" android:background="#ffb3ff13" android:weightSum="10.00"> <LinearLayout android:layout_weight="2.50" android:background="#ff56cfcd" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="0dp" > <ImageButton android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/imageButton" android:layout_gravity="center_horizontal" android:onClick="eventImageBtn" android:background="@drawable/btn_video" android:adjustViewBounds="true" android:scaleType="fitXY" /> </LinearLayout> <LinearLayout android:layout_weight="0.50" android:layout_height="0dp" android:background="#ffffffff" android:orientation="vertical" android:layout_width="fill_parent" > </LinearLayout> <LinearLayout android:layout_weight="4.50" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="0dp" android:background="#ff8aa5ff"> </LinearLayout> <LinearLayout android:layout_weight="0.50" android:layout_height="0dp" android:background="#ffffffff" android:orientation="vertical" android:layout_width="fill_parent" > </LinearLayout> <LinearLayout android:layout_weight="2.00" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="0dp" android:background="#ffff7d1a" > </LinearLayout> </LinearLayout> </LinearLayout> </ScrollView>
źródło
Oto moje rozwiązanie, które przy użyciu biblioteki „ nineOldAndroids ” obsługuje również stare interfejsy API:
rootView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(final View v, final MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: v.setBackgroundResource(R.drawable.listview_normal); ViewHelper.setAlpha(imageView, 1); break; case MotionEvent.ACTION_DOWN: v.setBackgroundResource(0); v.setBackgroundColor(getResources().getColor(R.color.listview_pressed)); ViewHelper.setAlpha(imageView, 0.75f); break; } return false; } });
Zakłada się, że rootView jest samą komórką (układem) i ma pojedynczy imageView, na który chcesz wpływać kolor, który chcesz zastosować do całej komórki.
EDYCJA: jeśli chcesz, możesz również rozszerzyć ImageView, aby obsługiwał pierwszy plan i ustawić go na „? Android: attr / selectableItemBackground”. Jest to biblioteka do tego tutaj i tutorial jak to zrobić dla dowolnego widoku chcesz, tutaj .
źródło
Dzięki za pomoc w tym wątku. Jednak przegapiłeś jedną rzecz ... musisz też obsłużyć ACTION_CANCEL. Jeśli tego nie zrobisz, możesz nieprawidłowo przywrócić wartość alfa ImageView w przypadku, gdy widok nadrzędny w hierarchii widoków przechwytuje zdarzenie dotykowe (pomyśl, że ScrollView otacza cię ImageView).
Oto pełna klasa, która jest oparta na powyższej klasie, ale zajmuje się również ACTION_CANCEL. Używa klasy pomocniczej ImageViewCompat, aby wyodrębnić różnice w interfejsie API JellyBean przed opublikowaniem.
public class ChangeAlphaOnPressedTouchListener implements OnTouchListener { private final float pressedAlpha; public ChangeAlphaOnPressedTouchListener(float pressedAlpha) { this.pressedAlpha = pressedAlpha; } @Override public boolean onTouch(View v, MotionEvent event) { ImageView iv = (ImageView) v; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: ImageViewCompat.setAlpha(iv, pressedAlpha); break; case MotionEvent.ACTION_MOVE: if (isInsideViewBounds(v, event)) { ImageViewCompat.setAlpha(iv, pressedAlpha); } else { ImageViewCompat.setAlpha(iv, 1f); } break; case MotionEvent.ACTION_UP: ImageViewCompat.setAlpha(iv, 1f); break; case MotionEvent.ACTION_CANCEL: ImageViewCompat.setAlpha(iv, 1f); } return false; } private static boolean isInsideViewBounds(View v, MotionEvent event) { return event.getX() > 0 && event.getX() < v.getWidth() && event.getY() > 0 && event.getY() < v.getHeight(); } }
źródło
Oto mój kod. Chodzi o to, że ImageView pobiera filtr kolorów, gdy użytkownik go dotknie, a filtr kolorów jest usuwany, gdy użytkownik przestaje go dotykać.
Martin Booka Weser, András, Ah Lam, altosh, rozwiązanie nie działa, gdy ImageView ma również onClickEvent. worawee.s i kcoppock (z ImageButton) wymaga tła, co nie ma sensu, gdy ImageView nie jest przezroczysty.
Ten jest rozwinięciem pomysłu AZ_ na temat filtra koloru.
class PressedEffectStateListDrawable extends StateListDrawable { private int selectionColor; public PressedEffectStateListDrawable(Drawable drawable, int selectionColor) { super(); this.selectionColor = selectionColor; addState(new int[] { android.R.attr.state_pressed }, drawable); addState(new int[] {}, drawable); } @Override protected boolean onStateChange(int[] states) { boolean isStatePressedInArray = false; for (int state : states) { if (state == android.R.attr.state_pressed) { isStatePressedInArray = true; } } if (isStatePressedInArray) { super.setColorFilter(selectionColor, PorterDuff.Mode.MULTIPLY); } else { super.clearColorFilter(); } return super.onStateChange(states); } @Override public boolean isStateful() { return true; } }
stosowanie:
Drawable drawable = new FastBitmapDrawable(bm); imageView.setImageDrawable(new PressedEffectStateListDrawable(drawable, 0xFF33b5e5));
źródło
Próbowałem z:
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:contentDescription="@string/get_started" android:src="@drawable/home_started" style="?android:borderlessButtonStyle" android:adjustViewBounds="true" android:clickable="true" android:elevation="5dp" android:longClickable="true" />
i to zadziałało. Uwaga na linii:
style="?android:borderlessButtonStyle"
źródło
Myślę, że najłatwiejszym sposobem jest utworzenie nowego pliku XML. W tym przypadku nazwijmy to „example.xml” w folderze do rysowania i wstawmy następujący kod:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/blue" android:state_pressed="true" /> </selector>
Ale wcześniej musisz ustawić kolory w pliku colors.xml, w folderze wartości, na przykład:
<resources> <color name="blue">#0000FF</color> </resources>
To sprawiło, że po prostu ustawiłeś Button / ImageButton, aby używał nowego układu, na przykład:
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/example" />
Następnie po kliknięciu tego obrazu zmieni się on na ustawiony kolor
<item android:drawable="@color/blue" android:state_pressed="true" />
przekazując informacje zwrotne, które chcesz ...
źródło
To najlepsze rozwiązanie, jakie kiedykolwiek widziałem. Jest bardziej ogólny.
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true" > <alpha android:duration="100" android:fromAlpha="0.0" android:interpolator="@android:anim/accelerate_interpolator" android:toAlpha="1.0" /> </set>
źródło
Zrobiłem co następuje w XML - z dopełnieniem 0 wokół obrazu i falowaniem na górze obrazu:
<ImageView android:layout_width="100dp" android:layout_height="100dp" android:background="@drawable/my_image" android:clickable="true" android:focusable="true" android:src="?android:attr/selectableItemBackground" />
źródło
Na razie powinniśmy rozwinąć praktykę Material Design . W takim przypadku możesz dodać efekt tętnienia na ImageView.
źródło
Po prostu dodaj atrybut XML, android: clickable = "true" ...
źródło