Si le texte d'un élément Spinner
est trop long pour tenir sur une seule ligne, le texte n'est pas encapsulé mais coupé. C'est seulement le cas pour niveau API> = 11 . Voici des captures d'écran de Android 4.2.2 (gauche) qui montre le mauvais comportement et Android 2.3.3 (à droite) où il se présente comme prévu.
Android:singleLine="false"
Est simplement ignoré ici. Donc, comme tous les autres essais comme Android:lines
, Android:minLines
, Etc. Le TextView
semble en quelque sorte être beaucoup plus large que la largeur de la fenêtre.
J'ai vu d'autres personnes avoir le même problème, mais personne n'a pu trouver de solution. Alors, est-ce un bug système? Je ne pense pas que cette incohérence entre les versions du système d'exploitation puisse être intentionnelle.
Certaines réponses suggèrent des solutions relativement simples.
Ecrire un Adapter
personnalisé et remplacer getView()
ainsi que getDropDownView()
. Ce n'est pas la solution ici, car à ce stade, il y a toujours le problème d'origine: à quoi la disposition doit-elle ressembler pour gérer le retour à la ligne approprié?
Envelopper le TextView
de la vue déroulante dans un parent ViewGroup
. Ne fonctionne pas avec Android:layout_width="match_parent"
Car la largeur du parent semble étrangement illimitée.
Donner la vue déroulante une largeur fixe. Cela ne convient pas aux différentes largeurs que Spinner
peut avoir.
Et bien sûr, aucune solution n'est d'insérer manuellement \n
N'importe où dans le texte.
MISE À JOUR: J'ai également téléchargé ceci comme exemple de projet sur GitHub : Download
/res/values/arrays.xml:
<string-array name="items">
<item>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</item>
<item>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est.</item>
</string-array>
/res/layout/spinner_item.xml:
<TextView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@Android:id/text1"
style="?android:attr/spinnerDropDownItemStyle"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:ellipsize="none"
Android:minHeight="?android:attr/listPreferredItemHeight"
Android:singleLine="false" />
Définissez Adapter
:
spinner.setAdapter(ArrayAdapter.createFromResource(this,
R.array.items,
R.layout.spinner_item));
Dans le thème holo, le spinner utilise par défaut le mode déroulant. Et tous les mouvements avec des styles par défaut remplaçants se déplacent simplement pour passer du mode spinner au mode dialogue qui encapsule avec succès le texte multiligne comme dans l'api 11. Au lieu de cela, vous pouvez créer un spinner avec new Spinner(context, Spinner.MODE_DIALOG)
ou en xml: Android:spinnerMode="dialog"
. Mais cela ne résout pas le problème, car c'est une boîte de dialogue, pas une liste déroulante.
J'ai trouvé une autre solution à ce problème: remplacer la méthode getDropDownView
dans ArrayAdapter
et mettre setSingleLine(false)
dans la méthode de visualisation post. Ainsi, lorsque la vue est complètement créée, elle enveloppe le texte sur les lignes appropriées.
@Override
public View getDropDownView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = new TextView(_context);
}
TextView item = (TextView) convertView;
item.setText("asddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
final TextView finalItem = item;
item.post(new Runnable() {
@Override
public void run() {
finalItem.setSingleLine(false);
}
});
return item;
}
MISE À JOUR:
Et voici une autre réponse.
Enveloppez manuellement listview dans PopupWindow et affichez-le sous TextView au clic et masquez-le sur listItem click.
Implémentation simple juste pour montrer l'idée:
public class MySpinner extends TextView {
private PopupWindow _p;
private ListView _lv;
public MySpinner(Context context) {
super(context);
init();
}
public MySpinner(Context context, AttributeSet attributeSet){
super(context, attributeSet);
init();
}
private void init(){
setBackgroundResource(R.drawable.spinner_background);
final List<String> list = new ArrayList<String>();
list.add("Very long text AAAAAAAAAAAAAAAA");
list.add("1 Very long text AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
list.add("2 Very long text A");
list.add("3 Very long text AAAAAAAAA");
setMinimumWidth(100);
setMaxWidth(200);
_lv = new ListView(getContext());
_lv.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.simple_list_item_1, list));
_lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
_p.dismiss();
setText(list.get(i));
}
});
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
_p = new PopupWindow(getContext());
_p.setContentView(_lv);
_p.setWidth(getWidth());
_p.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
_p.setTouchable(true);
_p.setFocusable(true);
_p.setOutsideTouchable(true);
_p.showAsDropDown(view);
}
});
}
}
Seule une combinaison de solutions a fonctionné pour moi (testée sur Android 5.1 aussi):
spinner_item.xml
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="wrap_content">
<TextView
Android:id="@Android:id/text1"
style="?android:attr/spinnerItemStyle"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:singleLine="false"
Android:textAlignment="inherit"/>
</LinearLayout>
code
final ArrayAdapter<String> spinnerArrayAdapter=new ArrayAdapter<String>(activity,R.layout.spinner_item,Android.R.id.text1,spinnerItemsList)
{
@Override
public View getDropDownView(final int position,final View convertView,final ViewGroup parent)
{
final View v=super.getDropDownView(position,convertView,parent);
v.post(new Runnable()
{
@Override
public void run()
{
((TextView)v.findViewById(Android.R.id.text1)).setSingleLine(false);
}
});
return v;
}
};
spinnerArrayAdapter.setDropDownViewResource(Android.R.layout.simple_spinner_dropdown_item);
J'ai résolu ce problème en passant au spinner de style boîte de dialogue:
<Spinner
...
Android:spinnerMode="dialog" />
L'ajout d'un LinearLayout autour de TextView permet au texte de s'habiller correctement.
Présentation (common_domainreferencemodel_spinner_item.xml):
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_height="wrap_content"
Android:layout_width="match_parent"
Android:padding="4dp">
<TextView
Android:id="@+id/nameTextView"
Android:singleLine="false"
Android:layout_width="match_parent"
Android:layout_height="wrap_content" />
</LinearLayout>
Adaptateur:
public class DomainReferenceModelAdapter extends ArrayAdapter<DomainReferenceModel> {
private List<DomainReferenceModel> objects;
private LayoutInflater inflater;
private int oddRowColor = Color.parseColor("#E7E3D1");
private int evenRowColor = Color.parseColor("#F8F6E9");
public DomainReferenceModelAdapter(Context context, int resource, List<DomainReferenceModel> objects) {
super(context, resource, objects);
this.objects = objects;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
static class ViewHolder {
public TextView nameTextView;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return getViewInternal(position, convertView, parent, false);
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getViewInternal(position, convertView, parent, true);
}
private View getViewInternal(int position, View convertView, ViewGroup parent, boolean isDropdownView) {
View view = convertView;
if (view == null) {
view = inflater.inflate(R.layout.common_domainreferencemodel_spinner_item, null);
ViewHolder viewHolder = new ViewHolder();
viewHolder.nameTextView = (TextView) view.findViewById(R.id.nameTextView);
view.setTag(viewHolder);
}
if (isDropdownView) {
view.setBackgroundColor(position % 2 == 0 ? evenRowColor : oddRowColor);
}
ViewHolder holder = (ViewHolder) view.getTag();
DomainReferenceModel model = objects.get(position);
holder.nameTextView.setText(model.getName());
return view;
}
}
Il n'est pas possible d'obtenir des éléments déroulants sur plusieurs lignes sur un Spinner
tout en utilisant un thème Holo
, d'après ce que j'ai essayé.
Une solution de contournement consiste à:
Spinner
qui n'hérite pas de Holo
. Cela activera les éléments déroulants sur plusieurs lignes.Holo
.Cela produit (montrant les états fermés et ouverts):
Détails de mise en œuvre:
Il n'y a aucun moyen d'hériter d'un thème Holo
sur le Spinner
et d'afficher plusieurs lignes dans l'élément de liste déroulante Spinner
pour autant que je sache, même si nous définissons l'attribut TextView
singleLine
de l'élément déroulant à false
et fournir une mise en page personnalisée. J'ai également essayé de conserver le style Holo
mais en modifiant la
Android:spinnerStyle
Android:spinnerItemStyle
Android:spinnerDropDownItemStyle
styles attributs (exemple d'utilisation de ces attributs ici ) mais je n'ai pas pu faire en sorte qu'il produise un résultat multi-lignes.
Cependant, si nous remplaçons le style de Spinner
et n'héritons pas de spinnerStyle
de Holo
:
<style name="AppTheme" parent="Android:Theme.Holo.Light">
<item name="Android:spinnerStyle">@style/spinnerStyle</item>
</style>
<--no parent attribute-->
<style name="spinnerStyle">
<item name="Android:clickable">true</item>
</style>
l'élément déroulant prendra en charge l'affichage de plusieurs lignes. Mais maintenant, nous avons perdu le thème Holo
sur le Spinner
et l'état fermé ressemble à un TextView
pas à un Spinner
sans flèche ni indice visuel c'est un Spinner
. Si nous définissons plutôt spinnerStyle
parent sur: parent="Android:style/Widget.Spinner
:
<style name="spinnerStyle" parent="Android:style/Widget.Spinner">
<item name="Android:clickable">true</item>
</style>
l'état Spinner
fermé affichera la flèche mais sera stylisé comme le pré-Holo gris Spinner
qui semble déplacé dans une application Holo
.
Donc, une solution possible est alors:
spinnerStyle
et n'utilisez pas Holo
pour parent. Cela activera le texte sur plusieurs lignes dans les éléments DropDown.Spinner
pour lui donner l'impression qu'il hérite du thème Holo
.Voici un exemple:
Créez une activité de base:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Spinner spinner = (Spinner)findViewById(R.id.styled_spinner);
spinner.setAdapter(ArrayAdapter.createFromResource(this,
R.array.items,
R.layout.spinner_item));
}
Disposition de l'activité:
<LinearLayout 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"
Android:padding="50dip"
tools:context=".MainActivity" >
<Spinner
Android:id="@+id/styled_spinner"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"/>
</LinearLayout>
modes:
<resources xmlns:Android="http://schemas.Android.com/apk/res/Android">
<style name="AppTheme" parent="Android:Theme.Holo.Light">
<item name="Android:spinnerStyle">@style/spinnerStyle</item>
</style>
<style name="spinnerStyle">
<item name="Android:clickable">true</item>
<item name="Android:background">@drawable/spinner_background_holo_light</item>
</style>
</resources>
dans le dossier dessinable, placez spinner_background_holo_light:
<selector xmlns:Android="http://schemas.Android.com/apk/res/Android">
<item Android:state_enabled="false"
Android:drawable="@drawable/spinner_disabled_holo_light" />
<item Android:state_pressed="true"
Android:drawable="@drawable/spinner_pressed_holo_light" />
<item Android:state_pressed="false" Android:state_focused="true"
Android:drawable="@drawable/spinner_focused_holo_light" />
<item Android:drawable="@drawable/spinner_default_holo_light" />
</selector>
et incluez ces drawables dans votre drawables-hdpi
dossier:
spinner_default_holo_light.9.png
spinner_disabled_holo_light.9.png
spinner_focused_holo_light.9.png
spinner_pressed_holo_light.9.png
Cela produit un spinner avec des éléments fermés à thème Holo
et multi-lignes, comme indiqué dans les captures d'écran ci-dessus.
Les éléments déroulants de cet exemple ne sont pas sur le thème Holo
mais c'est peut-être un compromis acceptable si l'affichage sur plusieurs lignes des éléments déroulants est vraiment important.
Dans cet exemple, Android:minSdkVersion
a été défini sur 14
et Android:targetSdkVersion
à 17
dans le manifeste.
Holo
graphiques et spinner_background_holo_light.xml
le code provient de HoloEverywhere Copyright (c) 2012 Christophe Versieux, Sergey Shatunov. Voir le projet github lié pour les détails de la licence.
Je pense qu'il y a un bug sur Android. Vous pouvez essayer ça. Supprimez les espaces du texte, puis affichez que cela fonctionnerait bien. Si la longueur de la vue de texte est <celle de la chaîne, elle ignore tous les caractères après l'espace. Pour contourner ce problème, vous pouvez essayer ceci:
ajoutez un fichier au dossier res/layout nommé multiline_spinner_dropdown_item.xml avec l'exemple de code:
<CheckedTextView xmlns:Android="http://schemas.Android.com/apk/res/Android"
style="?android:attr/spinnerDropDownItemStyle"
Android:singleLine="false"
Android:layout_width="match_parent"
Android:layout_height="?android:attr/listPreferredItemHeight"
Android:ellipsize="Marquee" />
et lorsque vous créez le spinner, créez-le à partir de cette disposition.
Quelque chose comme :
ArrayAdapter.createFromResource(this, items, R.layout.multiline_spinner_dropdown_item);
Fondamentalement, copiez la disposition Android.R.layout.simple_spinner_dropdown_item dans le projet et modifiez la disposition en définissant l'attribut singleLine sur false dans CheckedTextView.
J'ai fait face au même problème. Je veux voir 2 lignes dans la liste déroulante de spinner, mais toutes les solutions que j'ai trouvées me semblent déraisonnables pour résoudre un problème aussi simple. J'étudie code source Spinner et j'ai trouvé Si nous utilisons .xml personnalisé avec l'attribut Android: singleLine = "false"
<CheckedTextView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/multiline_spinner_text_view"
Android:layout_width="fill_parent"
Android:layout_height="?android:attr/listPreferredItemHeight"
Android:singleLine="false" />
et par défaut ArrayAdapter, code suivant exécuté dans ListPopupWindow à chaque fois
@Override
View More obtainView(int position, boolean[] isScrap) {
View view = super.obtainView(position, isScrap);
if (view instanceof TextView) {
((TextView) view).setHorizontallyScrolling(true);
}
return view;
}
et c'est pourquoi nous ne voyons qu'une ligne de chaîne par ligne de liste, elle défile en fait.
Pour résoudre ce problème, notre vue doit être pas une instance de TextView, il suffit de placer votre TextView dans FrameLayout ou LinearLayout.
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="wrap_content" >
<CheckedTextView
Android:id="@+id/multiline_spinner_text_view"
Android:layout_width="fill_parent"
Android:layout_height="?android:attr/listPreferredItemHeight"
Android:singleLine="false" />
</LinearLayout>
et
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
R.layout.multiline_spinner_dropdown_item,R.id.multiline_spinner_text_view,
awasomeListValues);
Cette solution fonctionne dans les deux modes spinner: MODE_DROPDOWN et MODE_DROPDOWN.J'espère qu'elle vous aidera!
En lisant cette réponse: erreur de conversion textview: - Android.widget.LinearLayout ne peut pas être converti en Android.widget.TextView et ce sujet, je pourrais résoudre ce problème: nous avons besoin d'un LinearLayout encapsulant TextView (le spinner texte) pour éviter que le texte sorte de l'écran, mais nous aurons des problèmes à résoudre. Pour commencer, créez la mise en page ( Je l'ai appelée spinner_dd_item.xml ):
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:orientation="vertical">
<TextView
Android:id="@+id/simple_spinner_dropdown"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:paddingBottom="5dp"
Android:paddingLeft="10dp"
Android:paddingRight="10dp"
Android:paddingTop="5dp"
Android:textColor="@color/colorAccent"
tools:text="Hello" />
</LinearLayout>
L'étape suivante consiste à créer une instance ArrayAdapter pour la définir sur le spinner:
ArrayAdapter<CharSequence> arrayAdapter = new ArrayAdapter<CharSequence>(getActivity(), R.layout.spinner_dd_item,
R.id.simple_spinner_dropdown, hashmapToString(hashMap, keys)) {
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
};
spinner.setAdapter(arrayAdapter);
N'oubliez pas d'ajouter le nom de la présentation et l'ID TextView sur ArrayAdapter car nous avons ajouté LinearLayout et nous devons spécifier TextView et remplacer getDropDownView pour obtenir la vue qui affiche les données à la position spécifiée dans l'ensemble de données. Maintenant, nous pouvons voir que le spinner fonctionne bien sur les versions plus récentes et plus anciennes Android versions
je viens de trouver que Android a un style existant pour ce cas
final Spinner pelanggaran = (Spinner) findViewById(R.id.pelanggaran);
ArrayAdapter<CharSequence> pelanggaran_adapter = ArrayAdapter.createFromResource(this,R.array.pelanggaran_array, Android.R.layout.simple_expandable_list_item_1);
pelanggaran_adapter.setDropDownViewResource(Android.R.layout.simple_expandable_list_item_1);
pelanggaran.setAdapter(pelanggaran_adapter);
j'espère que cela vous a résolu le problème.
Enveloppez simplement TextView
avec LinearLayout
:
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="wrap_content">
<TextView
Android:id="@Android:id/text1"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"/>
</LinearLayout>
ArrayAdapter<?> specAdapter =
ArrayAdapter.createFromResource(
getActivity().getBaseContext(),
aa[position],
Android.R.layout.select_dialog_item);
specAdapter.setDropDownViewResource(Android.R.layout.select_dialog_item);
J'ai eu ce même problème et j'ai trouvé une solution.
Je voulais que le texte apparaisse dans l'affichage initial et dans la liste déroulante également.
Le texte était enveloppé dans l'affichage initial et pour la liste déroulante, j'avais trouvé une autre solution recommandant l'utilisation d'une vue personnalisée d'une mise en page linéaire avec une largeur fixe entourant une vue de texte. Cela a rendu la liste déroulante du spinner correcte, ainsi que celle de la sélection initiale. Cependant, cela a causé un problème majeur sur les appareils plus anciens.
L'affichage initial ne s'actualisait pas et le texte prenait un aspect empilé si j'essayais de sélectionner autre chose. et comme il s'est empilé vers le bas, l'ajout d'un arrière-plan n'a pas aidé.
Comme il s'avère que les adaptateurs ont une méthode appelée setDropDownViewResource () qui vous permet de définir une vue différente pour la liste déroulante que celle affichée dans la sélection initiale du spinner.
import org.holoeverywhere.widget.Spinner;
ArrayAdapter adapter1 = ArrayAdapter.createFromResource(this,R.array.array_of_strings,R.layout.simple_list_item_1);
adapter1.setDropDownViewResource(R.layout.my_simple_list_item_1);
spQ1.setAdapter(adapter1);
dans cet exemple, simple_list_item est la vue par défaut fournie par Android et my_simple_list_item est
<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="300dp"
Android:layout_height="wrap_content" >
<TextView
Android:id="@+id/Android:text1"
Android:layout_width="wrap_content"
Android:layout_height="50dp"
Android:ellipsize="Marquee"
Android:layout_gravity="center_vertical"
Android:singleLine="false"/>
</LinearLayout>
Maintenant, le texte passe à l'intérieur de la vue déroulante du spinner ET dans la sélection affichée des spinners.
Voici ce que j'ai fait pour que cela fonctionne:
ArrayAdapter<KeyValue> adapter = new ArrayAdapter<>(getContext(), R.layout.simple_dropdown_item_multiline, R.id.nameTextView, choices);
Et voici le contenu de "simple_dropdown_item_multiline":
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="wrap_content">
<TextView Android:id="@+id/nameTextView"
style="?android:attr/dropDownItemStyle"
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:ellipsize="Marquee"
Android:paddingBottom="@dimen/large"
Android:paddingTop="@dimen/large"
Android:singleLine="false"
Android:textAppearance="?android:attr/textAppearanceLargePopupMenu"/>