J'ai fait une application de test très simple avec une activité et une mise en page. La onClick
ne se déclenche pas la première fois que vous appuyez dessus, comme il se doit.
L'activité:
package com.example.mytest;
import Android.os.Bundle;
import Android.app.Activity;
import Android.view.Menu;
import Android.view.View;
import Android.widget.EditText;
import Android.widget.Toast;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText ed1 = (EditText) findViewById(R.id.editText1);
ed1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_LONG)
.show();
}
});
}
}
La disposition:
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent" >
<EditText
Android:id="@+id/editText1"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentLeft="true"
Android:layout_alignParentTop="true"
Android:ems="10" >
<requestFocus />
</EditText>
<EditText
Android:id="@+id/editText2"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentLeft="true"
Android:layout_below="@+id/editText1"
Android:ems="10" />
</RelativeLayout>
Si vous exécutez cette application et cliquez sur la deuxième editText
, puis sur la première, la onClick
ne sera pas déclenchée. Vous pouvez continuer à sélectionner en arrière et cela ne déclenchera pas du tout la variable onClick
. J'ai besoin de cette fonctionnalité de base, mais je n'ai pas été en mesure de trouver un moyen de la faire fonctionner. Des idées?
J'ai essayé toutes les méthodes recommandées sur mon périphérique physique API de niveau 16 et mon émulateur d'API de niveau 8, mais je rencontre le même problème.
Lorsque editText1
est activé et que l'utilisateur clique dessus, la méthode onClick
est déclenchée. Si editText2
est ciblé et que l'on clique sur editText1
, il ne le fait pas est déclenché. Gros problème.
Overview, Lorsqu'un utilisateur interagit avec un composant de l'interface utilisateur, les différents écouteurs sont appelés dans un ordre descendant. Si l'un des écouteurs de priorité supérieure "consomme l'événement", les écouteurs inférieurs ne seront pas appelés .
Dans votre cas, ces trois auditeurs sont appelés dans l'ordre:
La première fois que l'utilisateur touche un texte d'édition, il reçoit le focus pour qu'il puisse taper. L'action est consommée ici. Par conséquent, la priorité inférieure OnClickListener n'est pas appelée. Chaque contact successif ne change pas le focus, donc ces événements se répercutent sur OnClickListener.
Les boutons (et autres composants similaires) ne reçoivent pas le focus d'un événement tactile, c'est pourquoi OnClickListener est appelé à chaque fois.
En gros, vous avez trois choix:
Implémentez un OnTouchListener par lui-même:
ed1.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(MotionEvent.ACTION_UP == event.getAction())
editTextClicked(); // Instead of your Toast
return false;
}
});
Cela s'exécutera à chaque fois que le EditText est touché. Notez que l'écouteur retourne false
, cela permet à l'événement de se répercuter sur OnFocusChangeListener intégré, qui modifie le focus afin que l'utilisateur puisse taper dans EditText.
Implémentez OnFocusChangeListener avec OnClickListener:
ed1.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus)
editTextClicked(); // Instead of your Toast
}
});
Cet écouteur attrape le premier événement tactile lorsque le focus est modifié, tandis que votre OnClickListener intercepte tous les autres événements.
(Ce n'est pas une réponse valable ici, mais c'est une bonne astuce à connaître.) Définissez l'attribut focusable sur false
dans votre XML:
Android:focusable="false"
Maintenant, le OnClickListener déclenchera chaque fois sur lequel il est cliqué. Mais cela rend le EditText inutile puisque l'utilisateur ne peut plus entrer de texte ...
Remarque:
getApplicationContext()
peut créer des fuites de mémoire. Une bonne habitude est d'éviter de l'utiliser sauf si cela est absolument nécessaire. Vous pouvez utiliser en toute sécurité v.getContext()
à la place.
J'espère que cela pourra aider!
rendre le texte d'édition cliquable .. En XML Android:clickable="true"
ou en code
ed1.setClickable(true);
alors fais
ed1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getBaseContext(), "1",Toast.LENGTH_SHORT).show();
}
});
Je suis probablement trop tard pour la fête, mais voici un extrait de code qui résout le problème avec onClick () non appelé:
ed1.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && !v.hasFocus()) {
// onClick() is not called when the EditText doesn't have focus,
// onFocusChange() is called instead, which might have a different
// meaning. This condition calls onClick() when click was performed
// but wasn't reported. Condition can be extended for v.isClickable()
// or v.isEnabled() if needed. Returning false means that everything
// else behaves as before.
v.performClick();
}
return false;
}
});
Cela est dû au fait que le premier tapotement met en évidence la vue. Le robinet suivant déclenche le clic.
Si vous gonflez la vue dynamiquement, procédez comme suit:
Android:clickable="true"
Android:focusable="false"
Android:focusableInTouchMode="false"
Si cela ne fonctionne pas, essayez également de l'appliquer à la vue parent.
public class TestProject extends Activity implements OnClickListener {
TextView txtmsg;
EditText ed1, ed2;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtmsg = (TextView) findViewById(R.id.txtmsg);
ed1 = (EditText) findViewById(R.id.edt1);
ed2 = (EditText) findViewById(R.id.edt2);
ed1.setOnClickListener(this);
ed2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v==ed1){
txtmsg.setText("1");
Toast.makeText(this, "first",Toast.LENGTH_SHORT).show();
}
if(v==ed2){
txtmsg.setText("2");
Toast.makeText(this, "second",Toast.LENGTH_SHORT).show();
}
}
}
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent" >
<EditText
Android:id="@+id/edt1"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentLeft="true"
Android:layout_alignParentTop="true"
Android:ems="10" />
<EditText
Android:id="@+id/edt2"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentLeft="true"
Android:layout_below="@+id/edt1"
Android:layout_marginTop="14dp"
Android:ems="10" />
<TextView
Android:id="@+id/txtmsg"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignRight="@+id/edt2"
Android:layout_below="@+id/edt2"
Android:layout_marginRight="22dp"
Android:layout_marginTop="160dp"
Android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
Évitez d’utiliser une FocusChangeListener
car elle se comportera de manière erratique si vous n’en avez pas vraiment besoin (par exemple lorsque vous entrez dans une activité). Il suffit de définir une OnTouchListener
avec votre OnClickListener
comme ceci:
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
view.requestFocus();
break;
}
return false;
}
Cela fera que votre EditText sera d'abord ciblé et que votre onClick
fonctionnera correctement la première fois.
Il m'a fallu une minute pour comprendre cela une fois où cela m'est arrivé. Ma ImageButton
avec setOnClickListener
et onClick
n'a pas semblé se déclencher, puis j'ai réalisé qu'il se trouvait en réalité sous un autre élément de ma présentation xml.
<RelativeLayout>
<ImageButton>
<LinearLayout></LinearLayout>
</RelativeLayout>
dans ceci:
<RelativeLayout>
<LinearLayout></LinearLayout>
<ImageButton>
</RelativeLayout>
et tout à coup l'imageButton n'a pas été superposée par l'autre mise en page, car elle a été ajoutée plus tard à la mise en page parent. Bonne chance, toujours amusant quand des choses de base semblent soudainement cesser de fonctionner
C'est la manière la plus simple de travailler avec le sélecteur de dates.
private DatePickerDialog datePickerDialog;
EditText etJoiningDate;
etJoiningDate=(EditText)findViewById(R.id.etJoiningDate);
etJoiningDate.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
final Calendar cldr = Calendar.getInstance();
int day = cldr.get(Calendar.DAY_OF_MONTH);
int month = cldr.get(Calendar.MONTH);
int year = cldr.get(Calendar.YEAR);
// date picker dialog
datePickerDialog = new DatePickerDialog(TestActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
etJoiningDate.setText(dayOfMonth + "/" + (monthOfYear + 1) + "/" + year);
}
}, year, month, day);
datePickerDialog.show();
break;
}
return false;
}
});