Mam problem z pozostawieniem podświetlonego przycisku po wykonaniu następujących czynności:
public class MainActivity extends AppCompatActivity {
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Test", "calling onClick");
}
});
button.setOnTouchListener(new View.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();
v.performClick();
Log.d("Test", "Performing click");
return true;
}
}
return false;
}
});
}
}
Jeśli chodzi o powyższy kod, podczas jego używania oczekuję, że kliknięcie przycisku będzie obsługiwane przez dotyk, a po zwróceniu „true” obsługa powinna zatrzymać się na touchListener.
Ale tak nie jest. Przycisk pozostaje podświetlony, nawet jeśli wywoływane jest kliknięcie.
Dostaję to:
Test - calling onClick
Test - Performing click
z drugiej strony, jeśli używam następującego kodu, przycisk jest klikany, drukowane są te same, ale przycisk nie zatrzymuje się w wyróżnionym stanie:
public class MainActivity extends AppCompatActivity {
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Test", "calling onClick");
}
});
button.setOnTouchListener(new View.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();
// v.performClick();
Log.d("Test", "Performing click");
return false;
}
}
return false;
}
});
}
}
Jestem trochę zdezorientowany co do łańcucha odpowiedzi na zdarzenie dotykowe. Domyślam się, że to:
1) TouchListener
2) ClickListener
3) ParentViews
Czy ktoś może to również potwierdzić?
android
onclicklistener
android-button
ontouchlistener
Biały niedźwiedź
źródło
źródło
Odpowiedzi:
Takie dostosowania nie wymagają modyfikacji programowych. Możesz to zrobić po prostu w
xml
plikach. Przede wszystkim usuńsetOnTouchListener
metodę podaną wonCreate
całości. Następnie zdefiniuj kolor selektora wres/color
katalogu, jak poniżej. (jeśli katalog nie istnieje, utwórz go)res / color / button_tint_color.xml
Teraz ustaw go na
app:backgroundTint
atrybut przycisku :Wynik wizualny:
EDYCJA: (w celu rozwiązania problemu ze zdarzeniem dotykowym)
Z ogólnego punktu widzenia przepływ zdarzenia dotyku rozpoczyna się od
Activity
, a następnie spływa do układu (od nadrzędnego do podrzędnego), a następnie do widoków. (Przepływ LTR na poniższym obrazku)Gdy zdarzenie dotykowy osiągnięciu docelowego obrazu, widok w stanie obsłużyć zdarzenie zdecydować, aby przekazać je do stanu układy / działania, czy nie (powrót
false
odtrue
wonTouch
sposób). (Przepływ RTL na powyższym zdjęciu)Teraz spójrzmy na kod źródłowy widoku , aby uzyskać głębszy wgląd w przepływy zdarzeń dotykowych. Patrząc na implementację
dispatchTouchEvent
, zobaczymy, że jeśli ustawiszOnTouchListener
na widok, a następnie powrócisztrue
w jegoonTouch
metodzie,onTouchEvent
widok nie zostanie wywołany.Teraz spójrz na
onTouchEvent
metodę, w której znajduje się akcja zdarzeniaMotionEvent.ACTION_UP
. Widzimy, że dzieje się tam akcja perform-click. Tak więc powróttrue
doOnTouchListener
„a”onTouch
i w konsekwencji nie wywołanie „onTouchEvent
powoduje” wywołanieOnClickListener
„”onClick
.Jest jeszcze jeden problem z nie wywołaniem
onTouchEvent
, który jest związany ze stanem wciśniętym i wspomnianym w pytaniu. Jak widać w poniższym bloku kodu, istnieje instancja takichUnsetPressedState
wywołań, gdy jest uruchomiona. W wyniku braku wywoływania widok utknie w stanie wciśniętym, a jego stan do rysowania nie zmieni się.setPressed
(false)
setPressed(false)
UnsetPressedState :
Jeśli chodzi o powyższe opisy, możesz zmienić kod, dzwoniąc
setPressed(false)
do siebie, aby zmienić stan rysowania, w którym akcja zdarzenia toMotionEvent.ACTION_UP
:źródło
Now, look at the onTouchEvent method where the event action is MotionEvent.ACTION_UP. We see that perform-click action happens there. So, returning true in the OnTouchListener's onTouch and consequently not calling the onTouchEvent, causes not calling the OnClickListener's onClick.
W moim przypadku wywoływany jest onClick. mUnsetPressedState sprawdza, czy ma wartość null przed ustawieniem wartości false, a także uruchamialność nie jest pewna, czy zostanie uruchomiona, jeśli jesteśmy przygotowani. Nie do końca rozumiem, jak można odjąć, że należy ustawić wartość falseonClick
Nazywa ponieważ dzwoniszv.performClick();
. Sprawdź ponownie powyższy kod wMotionEvent.ACTION_UP
sekcji, wsetPressed(false)
każdym razie jest wywoływany, niezależnie od tego, czymUnsetPressedState
ma wartość zerową, czyprepressed
jest prawdą, czy nie. Różnica polega na sposobie wywoływania,setPressed(false)
który może odbywać się bezpośredniopost
/postDelayed
bezpośrednio.Bałaganisz
touch
ifocus
wydarzenia. Zacznijmy od zrozumienia zachowania w tym samym kolorze. Domyślnie jestSelector
przypisany jako tło dlaButton
Androida. Po prostu zmieniając kolor tła, make jest statyczny (kolor się nie zmieni). Ale to nie jest rodzime zachowanie.Selector
może wyglądać takJak widać powyżej, istnieje stan
focused
i stanpressed
. UstawiająconTouchListener
, będziesz obsługiwać zdarzenia dotykowe, które nie mają z tym nic wspólnegofocus
.Selector
przycisku powinien zastąpićfocus
zdarzenietouch
podczas zdarzenia kliknięcia na przycisku. Ale w pierwszej części kodu przechwyciłeś zdarzenia dlatouch
(zwracając wartość true z wywołania zwrotnego). Zmiana koloru nie może być kontynuowana i marznie z tym samym kolorem. I dlatego drugi wariant (bez przechwytywania) działa dobrze i to jest twoje zamieszanie.AKTUALIZACJA
Wszystko, co musisz zrobić, to zmienić zachowanie i kolor
Selector
. Np. za pomocą następnego tła dlaButton
. IonTouchListener
w ogóle usuń ze swojej implementacji.źródło
onTouchListener
s. Po prostu nie musisz spożywać wydarzeńreturn true
.backgroundColor
.jeśli przypiszesz tło do przycisku, nie zmieni on koloru po kliknięciu.
i ustaw go jako tło dla swojego przycisku
źródło
możesz po prostu użyć żetonów materiału zamiast widoku przycisków. patrz: https://material.io/develop/android/components/chip tam obsługują te zdarzenia hililghted i można je dostosować za pomocą motywów.
źródło