Jak ustawić efekt kliknięcia przycisku w systemie Android?

105

W Androidzie, kiedy ustawię obraz tła na przycisk, nie widzę żadnego efektu na przycisku.

Potrzebuję jakiegoś efektu na przycisku, aby użytkownik mógł rozpoznać, że przycisk został kliknięty.

Przycisk powinien być ciemny przez kilka sekund po kliknięciu, więc co mam z tym zrobić?

Dzięki.

Jignesh Ansodariya
źródło
Poniższa metoda umożliwia użycie jednej klasy stylów do skórowania wszystkich przycisków, niezależnie od ich tekstu: stackoverflow.com/questions/5327553/…
Zack Marrapese
nie, nie używam przycisku obrazu, używam przycisku normalnego w prosty sposób?
Jignesh Ansodariya
3
Bardzo fajny tutorial: dibbus.com/2011/02/gradient-buttons-for-android
Pratik Butani

Odpowiedzi:

154

Można to osiągnąć, tworząc nadający się do rysowania plik xml zawierający listę stanów przycisku. Na przykład, jeśli utworzysz nowy plik xml o nazwie „button.xml” z następującym kodem:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/YOURIMAGE" />
    <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/gradient" />
    <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/gradient" />
    <item android:drawable="@drawable/YOURIMAGE" />
</selector>

Aby zachować przyciemniony obraz tła w druku, utwórz drugi plik xml i nazwij go gradient.xml z następującym kodem:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <bitmap android:src="@drawable/YOURIMAGE"/>
    </item>
    <item>
        <shape xmlns:android="http://schemas.android.com/apk/res/android">
            <gradient android:angle="90" android:startColor="#880f0f10" android:centerColor="#880d0d0f" android:endColor="#885d5d5e"/>
        </shape>
    </item>
</layer-list>

W pliku XML twojego przycisku ustaw tło na przycisk xml np

android:background="@drawable/button"

Mam nadzieję że to pomoże!

Edycja: Zmieniono powyższy kod, aby wyświetlać obraz (YOURIMAGE) na przycisku, a nie kolor bloku.

Ljdawson
źródło
To gdzie mogę ustawić obraz jako tło przycisku, aby ustawić obraz jest konieczny
Jignesh Ansodariya
1
Edytowano, aby pokazać, jak używać obrazu tła ze stanem XML. Zastąp YOURIMAGE zasobem obrazu w katalogu do rysowania.
Ljdawson
Działa to tylko wtedy, gdy src przycisku jest prostokątne. Jeśli element src drawable ma inny kształt niż ten, gradient zostanie również zastosowany do tła i jest to smutne.
Renato Lochetti
Nie bardzo, zawsze można użyć innego kształtu na liście warstw
Ljdawson
2
podczas gdy używam obrazu, to działa dla mnie .. ale kiedy używam tła XML. nie działa ...
DKV
88

Jest to prostsze, gdy masz dużo przycisków graficznych i nie chcesz pisać xml-s dla każdego przycisku.

Wersja Kotlin:

fun buttonEffect(button: View) {
    button.setOnTouchListener { v, event ->
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                v.background.setColorFilter(-0x1f0b8adf, PorterDuff.Mode.SRC_ATOP)
                v.invalidate()
            }
            MotionEvent.ACTION_UP -> {
                v.background.clearColorFilter()
                v.invalidate()
            }
        }
        false
    }
}

Wersja Java:

public static void buttonEffect(View button){
    button.setOnTouchListener(new OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
                    v.invalidate();
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    v.getBackground().clearColorFilter();
                    v.invalidate();
                    break;
                }
            }
            return false;
        }
    });
}
András
źródło
2
Używam tego w swoim kodzie i jedyny problem, jaki zauważyłem do tej pory, to to, że przycisk zachowuje się dziwnie po umieszczeniu w ScrollView.
Finnboy11
To naprawdę świetne rozwiązanie i to powinna być poprawna odpowiedź
Biraj Zalavadia
Jak to jest lepsze? Projektowanie należy trzymać poza kodem, prawda?
Błędy wydarzyły się
To tylko proste rozwiązanie tego problemu. Jeśli masz wiele przycisków i nie chcesz tworzyć plików XML dla każdego z nich, może to być pomocne.
András
O mój Boże! Wyobraź sobie, że masz 5 przycisków we fragmencie ... Będziesz miał całą masę tego standardowego kodu ... Jak więc to zreformować? Zmienić filtr kolorów dla wszystkich przycisków we wszystkich działaniach? Imho to twój następny programista nie będzie taki szczęśliwy ..
Leo Droidcoder
84

Stwórz swój AlphaAnimationobiekt, który decyduje o tym, jaki będzie efekt zanikania przycisku, a następnie pozwól mu rozpocząć się w jednym onClickListenerz przycisków

Na przykład :

private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.8F);

// some code

public void onClick(View v) {
    v.startAnimation(buttonClick);
}

oczywiście to tylko sposób, nie najbardziej preferowany, jest po prostu łatwiejszy

Ahmed Adel Ismail
źródło
5
To, co podoba mi się w tym rozwiązaniu, to to, że nie wymaga tworzenia wielu selektorów, gdy masz wiele przycisków z własnymi niestandardowymi obrazami.
Pete,
2
Nie powoduje to zaniku przycisku przy dotknięciu, a jedynie wygaszenie go na ułamek sekundy po wykryciu kliknięcia i podniesieniu palca użytkownika.
Doug Voss
1
Ładnie i prosto
@Doug Voss, możesz ustawić czas trwania animacji, aby ją wydłużyć
Ahmed Adel Ismail
a co z onLongClick i „roundReveal”?
Acauã Pitta
45

Można po prostu wykorzystać nową wiedzę dla Twojego Viewosiągnąć efekt klikalny:

android:foreground="?android:attr/selectableItemBackground"


Do użytku z ciemnym motywem dodaj także motyw do swojego layout(aby klikalny efekt był jasny):

android:theme="@android:style/ThemeOverlay.Material.Dark"
Francis
źródło
5
Najłatwiejszy sposób wdrożenia. Do Twojej wiadomości, Atrybut android: foreground nie ma wpływu na poziomy API niższe niż 23.
dolgom
1
Najprostsze rozwiązanie.
Jerry Chong
2
To powinna być akceptowana odpowiedź, znacznie prostsza i dodaje przyjemny efekt animacji tętnienia.
Tyler
1
@dolgom Dla poziomu API <23 użyj go w atrybucie "background". Więc: android: background = "? android: attr /
selectableItemBackground
24

Aby element był spójny z wyglądem i działaniem systemu, spróbuj odnieść się do atrybutu systemowego android:attr/selectableItemBackgroundw tagu tła lub pierwszego planu żądanego widoku:

<ImageView
    ...
    android:background="?android:attr/selectableItemBackground"      
    android:foreground="?android:attr/selectableItemBackground"
    ...
/>

Użyj obu atrybutów, aby uzyskać pożądany efekt odpowiednio przed / po 23 poziomie API.

https://stackoverflow.com/a/11513474/4683601

Ely Dantas
źródło
2
Zdecydowanie najprostsze rozwiązanie. Dzięki!
tykom
9

Lub używając tylko jednego obrazu tła, możesz osiągnąć efekt kliknięcia używając setOnTouchListener

Dwie drogi

((Button)findViewById(R.id.testBth)).setOnTouchListener(new OnTouchListener() {

      @Override
        public boolean onTouch(View v, MotionEvent event) {
          switch (event.getAction()) {
              case MotionEvent.ACTION_DOWN: {
                  Button view = (Button) v;
                  view.getBackground().setColorFilter(0x77000000, PorterDuff.Mode.SRC_ATOP);
                  v.invalidate();
                  break;
              }
              case MotionEvent.ACTION_UP:
                  // Your action here on button click
              case MotionEvent.ACTION_CANCEL: {
                  Button view = (Button) v;
                  view.getBackground().clearColorFilter();
                  view.invalidate();
                  break;
              }
          }
          return true;
        }
});

wprowadź opis obrazu tutaj

A jeśli nie chcesz używać setOnTouchLister, innym sposobem na osiągnięcie tego jest

    myButton.getBackground().setColorFilter(.setColorFilter(0xF00, Mode.MULTIPLY);

    StateListDrawable listDrawable = new StateListDrawable();
    listDrawable.addState(new int[] {android.R.attr.state_pressed}, drawablePressed);
    listDrawable.addState(new int[] {android.R.attr.defaultValue}, myButton);

    myButton.setBackgroundDrawable(listDrawable);
Vinayak Bevinakatti
źródło
są błędy w kodzie w 2. sposób. Co to jest funkcja getCurrent ()? Również myButton nie jest Drawable, więc nie można go dodać jako stanu.
Ehtesham Hasan,
Dziękuję za wskazanie błędu. Poprawiłem to, a myButton jest instancją klasy Button, która dostarcza metodę setBackgroundDrawable i pobiera instancje Drawable, więc to zadziała.
Vinayak Bevinakatti
Sprawdź moją odpowiedź, która jest oparta na Twoim drugim podejściu. stackoverflow.com/a/39430738/5229515
Ehtesham Hasan
Powinno to prawdopodobnie mieć na końcu „return false”, aby nie zużywało zdarzenia i można było wywołać jakiekolwiek dodatkowe onClickListeners.
Doug Voss
3

po prostu chcę dodać inny łatwy sposób, aby to zrobić: Jeśli twój ImageButton pozostaje tłem i nie ustawisz go na null, będzie działał jak normalny przycisk i wyświetli animację kliknięcia podczas klikania dokładnie tak, jak inne przyciski. tło, gdy jeszcze tam jest:

<ImageButton
    android:id="@+id/imageButton2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingBottom="1dp"
    android:paddingLeft="1dp"
    android:paddingRight="1dp"
    android:paddingTop="1dp"
    android:src="@drawable/squareicon" />

Wypełnienia nie pozwolą, aby tło było widoczne i sprawi, że przycisk będzie działał jak inne przyciski.

arianoo
źródło
1
to zachowa kwadratową ramkę przycisku wokół obrazu, jeśli jest okrągła
MSaudi
3

To najlepsze rozwiązanie, jakie wymyśliłem, biorąc wskazówki z odpowiedzi @ Vinayak. Wszystkie inne rozwiązania mają różne wady.

Przede wszystkim utwórz taką funkcję.

void addClickEffect(View view)
{
    Drawable drawableNormal = view.getBackground();

    Drawable drawablePressed = view.getBackground().getConstantState().newDrawable();
    drawablePressed.mutate();
    drawablePressed.setColorFilter(Color.argb(50, 0, 0, 0), PorterDuff.Mode.SRC_ATOP);

    StateListDrawable listDrawable = new StateListDrawable();
    listDrawable.addState(new int[] {android.R.attr.state_pressed}, drawablePressed);
    listDrawable.addState(new int[] {}, drawableNormal);
    view.setBackground(listDrawable);
}

Wyjaśnienie:

getConstantState (). newDrawable () służy do klonowania istniejącego Drawable, w przeciwnym razie zostanie użyty ten sam drawable. Przeczytaj więcej tutaj: Android: klonowanie elementu do rysowania w celu utworzenia StateListDrawable z filtrami

mutate () służy do tego, aby klon Drawable nie współdzielił swojego stanu z innymi wystąpieniami Drawable. Przeczytaj więcej na ten temat tutaj: https://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate ()

Stosowanie:

Możesz przekazać dowolny typ widoku (Button, ImageButton, View itp.) Jako parametr do funkcji, a uzyskają zastosowany do nich efekt kliknięcia.

addClickEffect(myButton);
addClickEffect(myImageButton);
Ehtesham Hasan
źródło
2
Step: set a button in XML with onClick Action:

 <Button
android:id="@+id/btnEditUserInfo"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/txt_height"
android:layout_gravity="center"
android:background="@drawable/round_btn"
android:contentDescription="@string/image_view"
android:onClick="edit_user_info"
android:text="Edit"
android:textColor="#000"
android:textSize="@dimen/login_textSize" />

Step: on button clicked show animation point
//pgrm mark ---- ---- ----- ---- ---- ----- ---- ---- -----  ---- ---- -----

    public void edit_user_info(View view) {

        // show click effect on button pressed
        final AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.8F);
        view.startAnimation(buttonClick);

        Intent intent = new Intent(getApplicationContext(),  EditUserInfo.class);
        startActivity(intent);

    }// end edit_user_info
Vinod Joshi
źródło
2

Użyj RippleDrawable dla efektu wciśnięcia / kliknięcia stanu Material Design.

Aby to osiągnąć, utwórz element ripple jako folder .xml under / drawable i użyj go w android: background dla dowolnych widoków.

  • Efekt po naciśnięciu / kliknięciu ikony, użyj efektu tętnienia kołowego, na przykład:

    <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@android:color/darker_gray" />

  • Efekt dla widoku klikniętego granicą prostokąta, możemy dodać tętnienie na istniejącym rysunku, jak poniżej:

    <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="#000000"> <item android:drawable="@drawable/your_background_drawable"/> </ripple>

giang nguyen
źródło
2

Za wszystkie widoki

android:background="?android:attr/selectableItemBackground"

Ale dla widoku karty, który ma zastosowanie elewacji

android:foreground="?android:attr/selectableItemBackground"

Efekt kliknięcia kołowego jak na pasku narzędzi

android:background="?android:attr/actionBarItemBackground"

Musisz także ustawić

 android:clickable="true"
 android:focusable="true"
Faizan Khan
źródło
0

Drobny dodatek do odpowiedzi Andràs:

Możesz użyć, postDelayedaby filtr koloru trwał przez krótki czas, aby był bardziej zauważalny:

        @Override
        public boolean onTouch(final View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    v.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
                    v.invalidate();
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    v.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            v.getBackground().clearColorFilter();
                            v.invalidate();
                        }
                    }, 100L);
                    break;
                }
            }
            return false;
        }

Możesz zmienić wartość opóźnienia 100L zgodnie ze swoimi potrzebami.

hiddeneyes02
źródło
0

Jeśli używasz tła XML zamiast IMG, po prostu usuń to:

<item>
    <bitmap android:src="@drawable/YOURIMAGE"/>
</item>

z pierwszej odpowiedzi, którą dał nam @Ljdawson.

RastaPopuloS
źródło
0

Utwórz plik bounce.xml do animacji

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <scale
        android:duration="100"
        android:fromXScale="0.9"
        android:fromYScale="0.9"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.0"
        android:toYScale="1.0" />

</set>

Dodaj tę linię w onClick, aby zainicjować

final Animation myAnim = AnimationUtils.loadAnimation (this, R.anim.bounce); button.startAnimation (myAnim);

Efekt zmniejszania się uzyskuje się po kliknięciu przycisku.

Arpit Patel
źródło