Désélectionner la liste si vous tapez du texte?

TL; DR: Vous choisissez une option dans (a) ma liste. Ensuite, vous changez d’avis et tapez quelque chose dans (b) mon texte d’édition. Comment effacer votre sélection de liste et ne montrer que votre edittext? (et vice versa)

J’ai une application avec une liste d’options ainsi qu’un edittext pour créer une option personnelle. J’ai besoin que l’utilisateur choisisse ou crée une option, mais pas les deux. Voici un dessin de ma mise en page:

entrez la description de l'image ici

Chaque fois que l’utilisateur sélectionne une option dans la liste, je la définit comme “sélectionnée” en la rendant verte, comme suit:

     

(ceci est défini comme arrière-plan de ma listview)

Problème: je souhaite désélectionner l’option listview si l’utilisateur décide de saisir sa propre option car il ne peut en avoir qu’une.

  1. L’utilisateur sélectionne une option dans la liste
  2. L’utilisateur décide qu’il veut créer sa propre option en utilisant edittext
  3. L’option listview est désélectionnée quand ils commencent à taper leurs propres

J’ai essayé de faire ce qui suit , mais rien ne désélectionne.

 e.setOnEditorActionListener(new TextView.OnEditorActionListener() { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { for(int i=0; i<=5; i++){ listView.setItemChecked(i, false); } listView.clearChoices(); listView.requestLayout() adapter.notifyDataSetChanged() } } 

Une situation très déroutante, toute aide est appréciée!

Edit: voici la mise en page de l’edittext:

  

Edit: voici la mise en page de la listview:

    

Longue histoire courte

  • Le sélecteur ListView ( android:listSelector ) est conçu pour indiquer un événement de clic, mais pas les éléments sélectionnés .
  • Si un sélecteur ListView est dessiné (après le premier clic), il ne disparaîtra pas sans changements radicaux dans ListView.
  • Par conséquent, utilisez uniquement des éléments dessinables avec un arrière-plan transparent si aucun état n’y est appliqué en tant que sélecteur ListView. N’utilisez pas une ressource de couleur unie pour cela, ne vous trompez pas .
  • Utilisez le mode de choix ListView ( android:choiceMode ) pour indiquer les éléments sélectionnés.
  • ListView indique quelle ligne est sélectionnée en définissant android:state_activated sur leur vue racine. Fournissez à votre adaptateur la disposition / les vues correspondantes pour représenter correctement les éléments sélectionnés.

Théorie

Eh bien, la sélection intégrée dans ListView est tout à fait délicate au premier abord. Toutefois, il convient de garder à l’esprit deux distinctions principales pour éviter toute confusion, comme ceci: sélecteur d’ affichage de liste et mode de choix .

Sélecteur ListView

Le sélecteur ListView est une ressource pouvant être dessinée qui est supposée indiquer un événement consistant à cliquer sur un élément de la liste . Vous pouvez le spécifier soit par la propriété XML android:listSelector ou en utilisant la méthode setSelector() . Je ne pouvais pas le trouver dans la documentation, mais je crois comprendre que cette ressource ne doit pas être une couleur unie, car après son dessin, elle ne disparaîtra pas sans des changements radicaux dans la vue (comme la configuration d’un adaptateur, qui certains problèmes apparaissent), par conséquent, cet élément dessinable ne devrait être visible que lorsqu’un état particulier (par exemple, android:state_pressed ) est appliqué. Voici un exemple simple de dessin pouvant être utilisé comme sélecteur de vue liste

     

Pour une raison quelconque, vous ne pouvez pas utiliser une liste d’états de couleurs en tant que sélecteur d’affichage de liste , mais vous pouvez toujours utiliser des couleurs simples (la plupart du temps inappropriées) et des éléments dessinables de la liste d’ états. Cela rend les choses un peu déroutantes. Après le premier clic sur une vue de liste, vous ne pourrez plus retirer facilement le sélecteur de vue de liste de la vue de liste.

L’idée principale ici est que le sélecteur d’affichage de liste n’est pas conçu pour indiquer l’élément sélectionné .

Mode de choix ListView

Le mode de choix ListView est supposé indiquer les éléments sélectionnés . Comme vous le savez peut-être, il existe principalement deux modes de choix que nous pouvons utiliser dans ListView – Choix unique et Choix multiple. Ils permettent de suivre une ou plusieurs lignes sélectionnées. Vous pouvez les définir via android:choiceMode XML-property ou la méthode setChoiceMode() . Le ListView lui-même conserve les lignes sélectionnées et leur permet de savoir laquelle est sélectionnée à tout moment en définissant la propriété android:state_activated de la vue racine de la ligne. Pour que vos lignes reflètent cet état, leur vue racine doit avoir un ensemble pouvant être dessiné correspondant, par exemple en tant qu’arrière-plan. Voici un exemple de ce dessin:

     

Vous pouvez créer / désélectionner des lignes par programme à l’aide de la méthode setItemChecked() . Si vous souhaitez qu’un ListView efface tous les éléments sélectionnés, vous pouvez utiliser la méthode clearChoices() . Vous pouvez également vérifier les éléments sélectionnés à l’aide de la famille de méthodes: getCheckedItemCount() , getCheckedItemIds() , getCheckedItemPosition() (pour le mode à choix unique), getCheckedItemPositions() (pour le mode à choix multiple)

Conclusion

Si vous voulez garder les choses simples, n’utilisez pas le sélecteur d’affichage de liste pour indiquer les éléments sélectionnés .


Résoudre le problème

Option 1. Sale solution – masquer le sélecteur

Au lieu de supprimer le sélecteur, de modifier les présentations et de mettre en œuvre une approche robuste, nous pouvons masquer le sélecteur pouvant être dessiné le cas échéant et l’afficher ultérieurement lorsque vous cliquez sur un élément ListView:

  public void hideListViewSelector() { mListView.getSelector().setAlpha(0); } @Override public void onItemClick(AdapterView parent, View view, int position, long id) { if (mListView.getSelector().getAlpha() == 0) { mListView.getSelector().setAlpha(255); } } 

Option 2. Manière réfléchie

Passons en revue votre code et faisons-le respecter les règles que j’ai décrites étape par étape.

Correction de la disposition ListView

Dans votre mise en page ListView, le sélecteur est défini sur une couleur unie. Par conséquent, vos éléments sont colorés par ce dernier lorsque vous cliquez dessus. Le dessin que vous utilisez comme arrière-plan ListView n’a aucun impact, car l’état de ListView ne change pas lorsque l’utilisateur clique sur ses lignes. Votre ListView a donc toujours un arrière-plan @color/windowBackground .

Pour résoudre votre problème, vous devez d’abord retirer le sélecteur de la présentation ListView:

 android:listSelector="@color/colorPrimary" android:background="@color/windowBackground" android:choiceMode="singleChoice"/> 

Faites en sorte que vos lignes reflètent l’état activé

Dans les commentaires, vous donnez votre adaptateur comme suit:

 final ArrayAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, text1, listOfThings); 

Vous m’avez également demandé s’il était possible de continuer à utiliser un adaptateur standard pour obtenir le comportement souhaité. Nous pouvons le faire, mais quelques modifications sont nécessaires. Je peux voir 3 options pour ce cas:

1. Utilisation de la structure Android vérifiée standard

Vous pouvez simplement spécifier une mise en page standard correspondante – soit l’une des mises en page qui utilise CheckedTextView sans arrière-plan modifié pouvant être dessiné en tant que composant racine, soit de celles qui utilisent ActivéBackgroundIndicator en tant qu’arrière-plan. Dans votre cas, l’option la plus appropriée devrait être simple_list_item_activated_1 . Il suffit de le définir comme dans votre constructeur ArrayAdapter comme ceci:

 final ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_activated_1 , android.R.id.text1, listOfThings); 

Cette option est la plus proche de ce que je comprends par adaptateur “standard”.

2. Personnalisez votre adaptateur

Vous pouvez utiliser une disposition standard et principalement un adaptateur standard, à une exception près: obtenir une vue de vos éléments. Introduisez simplement une classe anonyme et substituez la méthode getView() , en fournissant des vues de ligne avec l’arrière-plan correspondant dessinable:

 final ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, listOfThings) { @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { final View view = super.getView(position, convertView, parent); if (convertView == null) { view.setBackgroundResource(R.drawable.list_item_bg); } return view; } }; 

3. Personnalisez votre mise en page

La manière la plus courante de résoudre ce problème consiste bien entendu à introduire votre propre présentation pour la vue des éléments. Voici mon exemple simple:

    

Je l’ai enregistré dans un fichier /res/layout/list_view_item.xml N’oubliez pas de définir cette présentation dans votre adaptateur:

 final ArrayAdapter adapter = new ArrayAdapter(this, R.layout.list_view_item , android.R.id.text1, listOfThings); 

Des choix clairs au besoin

Après quoi, vos lignes refléteront l’état sélectionné lorsque vous cliquez dessus et vous pouvez facilement effacer l’état sélectionné de votre ListView en appelant clearChoices() et conséquent requestLayout() pour demander à ListView de se redessiner.

Un petit commentaire ici: si vous souhaitez désélectionner l’élément lorsque l’utilisateur commence à taper, mais pas lorsqu’il clique sur le bouton de retour (terminé), vous devez utiliser un rappel TextWatcher place:

  mEditText.addTextChangedListener(new TextWatcher(){ @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (mListView.getCheckedItemCount() > 0) { mListView.clearChoices(); mListView.requestLayout(); } } @Override public void afterTextChanged(Editable s) {} }); 

J’espère que ça a aidé.

J’ai une bonne solution pour le faire. Ajoutez EditText à votre mise en page qui contient sur votre ListView la mise en page suivante:

      

Puis initialisez la variable booléenne pour vérifier si editText est activé ou non, par exemple, utilisez ceci: boolean canBeSelected = true;

Ensuite, après avoir configuré l’adaptateur, utilisez ce code:

 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView adapterView, View view, int i, long l) { if (canBeSelected) { listView.setSelector(R.drawable.background); listView.setSelected(true); listView.setSelection(i); } else { if (!editText.isFocused()){ canBeSelected = true; listView.setSelector(R.drawable.background); listView.setSelected(true); listView.setSelection(i); } } } }); editText.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { canBeSelected = false; Drawable transparentDrawable = new ColorDrawable(Color.TRANSPARENT); listView.setSelector(transparentDrawable); listView.clearChoices(); listView.setSelected(false); return false; } }); editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { if (editText.isFocused()){ Drawable transparentDrawable = new ColorDrawable(Color.TRANSPARENT); listView.setSelector(transparentDrawable); listView.clearChoices(); listView.setSelected(false); canBeSelected = false; } } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { Drawable transparentDrawable = new ColorDrawable(Color.TRANSPARENT); listView.setSelector(transparentDrawable); listView.clearChoices(); listView.setSelected(false); canBeSelected = false; } @Override public void afterTextChanged(Editable editable) { if (editText.isFocused()) { Drawable transparentDrawable = new ColorDrawable(Color.TRANSPARENT); listView.setSelector(transparentDrawable); listView.clearChoices(); listView.setSelected(false); canBeSelected = false; } } }); } 

J’espère que ça marche avec toi 🙂

La réinitialisation de l’adaptateur dans l’écouteur edittext a fonctionné pour moi:

 editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { listview.clearChoices(); listview.setAdapter(adapter); Toast.makeText(getApplicationContext(),"Typing" + listview.getSelectedItemPosition(), Toast.LENGTH_SHORT).show(); } @Override public void afterTextChanged(Editable editable) { } }); 

Je mets l’index sélectionné dans un toast pour vérifier si l’élément a été désélectionné correctement.

J’espère que ça marche !!

Avez-vous essayé setsélectionné pour chaque élément de votre adaptateur de liste?

 mEditText.setSelected(false); 

https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo.html#setSelected(boolean)