Je rencontre un problème avec mon bouton dans un état mis en surbrillance, après avoir effectué les opérations suivantes:
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;
}
});
}
}
En ce qui concerne le code ci-dessus, lorsque je l'utilise, je m'attends à ce que le clic sur le bouton soit géré par le toucher, et en renvoyant "true", le traitement devrait s'arrêter au touchListener.
Mais ce n'est pas le cas. Le bouton reste dans un état en surbrillance, même si le clic est appelé.
Ce que je reçois est:
Test - calling onClick
Test - Performing click
d'autre part, si j'utilise le code suivant, le bouton est cliqué, même impressions, mais le bouton ne finit pas coincé dans un état en surbrillance:
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;
}
});
}
}
Je suis un peu confus quant à la chaîne de réponse à l'événement tactile. Je suppose que c'est:
1) TouchListener
2) ClickListener
3) ParentViews
Quelqu'un peut-il également le confirmer?
la source
Réponses:
De telles personnalisations ne nécessitent aucune modification programmatique. Vous pouvez le faire simplement dans des
xml
fichiers. Tout d'abord, supprimez entièrement lasetOnTouchListener
méthode que vous fournissezonCreate
. Ensuite, définissez une couleur de sélecteur dans leres/color
répertoire comme suit. (si le répertoire n'existe pas, créez-le)res / color / button_tint_color.xml
Maintenant, définissez-le sur l'
app:backgroundTint
attribut du bouton :Résultat visuel:
ÉDITÉ: (pour résoudre le problème de l'événement tactile)
D'un point de vue global, le flux de l'événement tactile commence à partir du
Activity
, puis descend vers la disposition (du parent vers les dispositions enfant), puis vers les vues. (Flux LTR dans l'image suivante)Lorsque l'événement tactile atteint la vue cible, la vue peut gérer l'événement, puis décider de le transmettre aux dispositions / activités précédentes ou non (retour
false
de la méthodetrue
inonTouch
). (Flux RTL dans l'image ci-dessus)Maintenant , nous allons jeter un oeil à la Voir le code source d » acquérir une connaissance plus approfondie des flux événement tactile. En jetant un œil à l'implémentation de la
dispatchTouchEvent
, nous verrions que si vous définissez unOnTouchListener
sur la vue et que vous revenez ensuitetrue
dans saonTouch
méthode, laonTouchEvent
de la vue ne sera pas appelée.Maintenant, regardez la
onTouchEvent
méthode où se trouve l'action d'événementMotionEvent.ACTION_UP
. Nous voyons que l'action effectuer un clic s'y produit. Donc, retournertrue
dans leOnTouchListener
'sonTouch
et par conséquent ne pas appeler le'onTouchEvent
, provoque ne pas appeler leOnClickListener
'sonClick
.Il y a un autre problème à ne pas appeler le
onTouchEvent
, qui est lié à l'état pressé et que vous avez mentionné dans la question. Comme nous pouvons le voir dans le bloc de code ci-dessous, il existe une instance deUnsetPressedState
cet appel lors de son exécution. Le résultat de ne pas appeler que la vue se coince dans l'état pressé et son état drawable ne change pas.setPressed
(false)
setPressed(false)
UnsetPressedState :
Concernant les descriptions ci-dessus, vous pouvez changer le code en
setPressed(false)
vous appelant pour changer l'état de dessin où l'action d'événement estMotionEvent.ACTION_UP
:la source
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.
dans mon cas, onClick est appelé. mUnsetPressedState vérifie s'il est nul avant de le définir sur false et la runnable n'est pas sûre de s'exécuter si nous sommes prépresse. Je ne comprends pas très bien comment vous déduisez qu'il doit être défini sur fauxonClick
est appelé parce que vous appelezv.performClick();
. Veuillez vérifier à nouveau le code ci-dessus dans laMotionEvent.ACTION_UP
section, ilsetPressed(false)
est appelé de toute façon, qu'ilmUnsetPressedState
soit nul ou non,prepressed
vrai ou non. La différence réside dans la manière d'appelersetPressed(false)
qui pourrait se faire parpost
/postDelayed
ou directement.Vous dérangez
touch
et lesfocus
événements. Commençons par comprendre le comportement avec la même couleur. Par défaut, il estSelector
assigné comme arrière-plan àButton
dans Android. Donc, tout simplement en changeant la couleur d'arrière-plan, make est statique (la couleur ne changera pas). Mais ce n'est pas un comportement natif.Selector
pourrait ressembler à celui-ci.Comme vous pouvez le voir ci-dessus, il y a état
focused
et étatpressed
. En définissant,onTouchListener
vous gérerez les événements tactiles, qui n'ont rien à voir avecfocus
.Selector
du bouton doit remplacer l'focus
événement par un événement detouch
clic sur le bouton. Mais dans la première partie de votre code, vous avez intercepté des événements pour letouch
(retour vrai du rappel). Le changement de couleur ne peut pas continuer et gèle avec la même couleur. Et c'est pourquoi la deuxième variante (sans interception) fonctionne bien et c'est votre confusion.MISE À JOUR
Il vous suffit de changer le comportement et la couleur du
Selector
. Par exemple. en utilisant le fond suivant pour leButton
. ET supprimezonTouchListener
du tout votre implémentation.la source
onTouchListener
s que vous le souhaitez. Vous n'avez tout simplement pas besoin de consommer un événementreturn true
.backgroundColor
.si vous attribuez un arrière-plan au bouton, il ne changera pas la couleur au clic.
et définissez-le en arrière-plan sur votre bouton
la source
vous pouvez simplement utiliser des puces matérielles pour au lieu de la vue Bouton. référez-vous: https://material.io/develop/android/components/chip là, ils gèrent ces événements heureux et vous pouvez personnaliser en appliquant les thèmes.
la source