Spinner не переносит текст - это ошибка Android?

если текст Spinner элемент слишком длинный, чтобы поместиться в одну строку, текст не завернут, но отрезан. Это только в случае уровень API >= 11. Вот скриншоты Android 4.2.2 (слева), который показывает неправильное поведение и Android 2.3.3 (справа), где это выглядит так, как ожидалось.

android:singleLine="false" здесь просто игнорируется. Так как все остальные пытается вроде android:lines, android:minLines, etc. The TextView как-то кажется, намного шире, чем ширина окна.

я видел других людей, имеющих ту же проблему, но никто не мог найти решение. Так это системная ошибка? Я не думаю, что это несоответствие между версиями ОС может быть намеренным.


обратите внимание:

были некоторые ответы, предлагающие относительно простые решения.

  • написание на заказ Adapter и переопределить getView() as также getDropDownView(). Это не решение здесь, потому что на данный момент все еще существует исходная проблема: как макет должен выглядеть, чтобы обрабатывать правильную обертку линии?

  • упаковка TextView из выпадающего вида в родительский ViewGroup. Не работает с android:layout_width="match_parent" потому что ширина родителя странно кажется неограниченной.

  • предоставление выпадающего вида фиксированной ширины. Это не подходит для разных Ширин Spinner может быть.

  • и, конечно, нет решения, чтобы вручную вставить ns в любом месте текста.


воспроизвести со следующим кодом:

обновление: я выложил это как пример проекта на GitHub: скачать

/res/значения / массивы.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" />

Set Adapter:

spinner.setAdapter(ArrayAdapter.createFromResource(this,
            R.array.items,
            R.layout.spinner_item));

14 ответов


в holo theme spinner по умолчанию используется выпадающий режим. И все движения с переопределением стилей по умолчанию просто переходят в режим переключения spinner в режим диалога, который успешно обертывает многострочный текст, как в api 11. Вместо этого вы можете создать счетчик с new Spinner(context, Spinner.MODE_DIALOG) или в xml:android:spinnerMode="dialog". Но это не решает проблему, потому что это диалог, а не выпадающий.

Я нашел другое решение для этой проблемы: Override getDropDownView метод ArrayAdapter и поставить setSingleLine(false) в методе просмотра post. Так когда? просмотр полностью создан он обертывает текст в соответствующие строки.

@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;
}

обновление:

и вот еще один ответ.

вручную оберните listview в PopupWindow и покажите его под TextView на Щелчке и скройте его на Щелчке listItem.

простая реализация, чтобы показать идею:

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);
            }
        });
    }
}

Я решил эту проблему, переключившись на spinner в диалоговом стиле:

<Spinner
  ...
android:spinnerMode="dialog" />

только сочетание решений здесь работало для меня (протестировано на Android 5.1 тоже):

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>

код

  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);

достижение многострочных выпадающих элементов на Spinner при использовании Holo тема невозможна, из того, что я пробовал.

обходным решением является:

  • Создайте стиль для Spinner это не наследуется от Holo. Это позволит использовать многострочные раскрывающиеся элементы.
  • стиль спиннера "вручную", так что похоже, что это Holo-тематические.

это производит (показывая закрытое и открытое государства):

enter image description here

детали реализации:

нет никакого способа наследовать от Holo на Spinner и показать несколько строк Spinner выпадающий элемент, насколько я могу судить, даже если мы установим выпадающий элемент TextView до false и предоставить пользовательский макет. Я также попытался сохранить Holo стиль, но изменения

android:spinnerStyle
android:spinnerItemStyle 
android:spinnerDropDownItemStyle 

атрибуты стилей (пример использования этих атрибутов здесь), но я не мог заставить его произвести многострочный результат.

однако, если мы переопределим стиль для Spinner и не наследуют spinnerStyle С 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>

затем выпадающий элемент будет поддерживать отображение нескольких строк. Но теперь мы потеряли Holo на Spinner и закрытое состояние выглядит как TextView не Spinner без стрелки или визуальной подсказки это Spinner. Если вместо этого установить spinnerStyle родитель: parent="android:style/Widget.Spinner:

<style name="spinnerStyle" parent="android:style/Widget.Spinner">
    <item name="android:clickable">true</item>
</style>

the Spinner закрытое состояние покажет стрелку, но будет стилизовано как серый pre-Holo Spinner который выглядит неуместным в Holo app.

Итак, возможное решение тут:

  • переопределить тему для spinnerStyle и не использовать Holo для родителей. это позволит многострочный текст в выпадающих пунктов.
  • изменить Spinner фон, чтобы выглядеть так, как он наследует Holo тема.

вот пример:

создайте основное действие:

@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));        
}

активность планировка:

<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>

стили:

<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>

в папке drawable поместите 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>

и включите эти чертежи в свой :

enter image description here spinner_default_holo_light.9.формат PNG

enter image description here spinner_disabled_holo_light.9.формат PNG

enter image description here spinner_focused_holo_light.9.формат PNG

enter image description here spinner_pressed_holo_light.9.формат PNG

это производит счетчик с Holoтематические закрытом состоянии и многострочные элементы, как показано на скриншотах выше.

выпадающие элементы в этом примере не являются Holo-тематические, но, возможно, это приемлемый компромисс, если многострочный дисплей выпадающих элементов действительно важный.

в этом примере android:minSdkVersion был установлен до 14 и android:targetSdkVersion to 17 в Манифесте.

Holo графика и spinner_background_holo_light.xml код пришел из HoloEverywhere Авторское право (c) 2012 Кристоф Versieux, Сергей Шатунов. Увидеть ссылке на GitHub проекта по лицензии.


добавление LinearLayout вокруг TextView позволяет тексту правильно обернуться.

Layout(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>

адаптер:

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;
    }

}

я столкнулся с той же проблемой. Я хочу видеть 2 строки в раскрывающемся списке spinner, но все решения, которые я нашел, кажутся мне неразумными для решения такой простой проблемы. Я расследую Spinner исходный код и я нашел, если мы используем таможни .в XML С атрибутом 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" />

и по умолчанию ArrayAdapter, следующий код, выполненный в ListPopupWindow каждый раз

    @Override
       View More obtainView(int position, boolean[] isScrap) {
            View view = super.obtainView(position, isScrap);

           if (view instanceof TextView) {
                ((TextView) view).setHorizontallyScrolling(true);
            }

            return view;        
}

и вот почему мы видим только одну строку для каждой строки списка, это на самом деле прокрутки.

чтобы решить такую проблему, наш взгляд должен быть Не экземпляр TextView, просто поместите свой TextView внутри FrameLayout или 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>

и

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 
               R.layout.multiline_spinner_dropdown_item,R.id.multiline_spinner_text_view,
                awasomeListValues);

это решение работает как в режиме spinner: MODE_DROPDOWN и MODE_DROPDOWN.Надеюсь, это поможет вам!


Я думаю, что на android есть ошибка. Ты можешь попробовать это. Удалите пробелы из текста, а затем покажите, что он будет работать нормально. Если длина textview

добавьте файл в папку res/layout с именем multiline_spinner_dropdown_item.xml с образцом кода:

<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" />

и когда вы создаете счетчик, создайте его из этого макет.

что-то типа :

ArrayAdapter.createFromResource(this, items, R.layout.multiline_spinner_dropdown_item);

в основном, скопируйте android.R. макет.simple_spinner_dropdown_item макет в проект и изменить макет, установив singleline атрибут false в CheckedTextView.


читать этот ответ: ошибка кастинга textview: - android.штучка.LinearLayout не может быть приведен к android.штучка.Поле TextView и в этой теме я мог бы решить эту проблему: нам нужен LinearLayout, обертывающий TextView (текст spinner), чтобы избежать выхода текста с экрана, но у нас будут некоторые проблемы для решения. Для начала создайте макет (я назвал его 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>

следующим шагом является создание экземпляра ArrayAdapter для установите его на счетчик:

    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);

Не забудьте добавить имя макета и идентификатор TextView в ArrayAdapter, потому что мы добавили LinearLayout и нам нужно указать TextView и переопределить getDropDownView, чтобы получить представление, которое отображает данные в указанной позиции в наборе данных. Теперь мы можем видеть, что spinner хорошо работает на новых и старых версиях android


Я только что обнаружил, что android имеет существующий стиль для этого случая

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);

надеюсь, это решило вашу проблему.


у меня была такая же проблема и я нашел решение.

Я хотел, чтобы текст обернулся на начальном дисплее и в раскрывающемся списке.

текст обертывался на начальном дисплее, и для раскрывающегося списка я нашел другое решение, рекомендующее использовать пользовательский вид линейного макета с фиксированной шириной, охватывающей textview. Это сделало выпадающий список блесны выглядеть правильно, а также, что из первоначального выбора. Тем не менее, это вызвало серьезную проблему на старое устройство.

начальный дисплей не обновлялся, и текст принимал сложенный вид, если я пытался выбрать что-то еще. и так как он складывался вниз, добавление фона не помогло. enter image description here

как оказалось, адаптеры имеют метод setDropDownViewResource (), который позволяет установить другой вид для раскрывающегося списка, чем то, что отображается в начальном выборе 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);

в этом примере simple_list_item является представление по умолчанию, предоставляемое android и my_simple_list_item, -

<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> 

теперь текст обертывается внутри раскрывающегося списка блесны и в блесны отображается выбор.


просто обернуть TextView С 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);

вот что я сделал, чтобы заставить его работать:

ArrayAdapter<KeyValue> adapter = new ArrayAdapter<>(getContext(), R.layout.simple_dropdown_item_multiline, R.id.nameTextView, choices);

и это содержимое "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"/>


Я решил эту проблему, добавив \n (новая строка) в текст (так просто).

<string name="bmr1">sedentary (little or no exercise)</string>
<string name="bmr2">lightly active (light exercise/\nsports 1-3 days/week)</string>
<string name="bmr3">moderately active (moderate exercise/\nsports 3-5 days/week)</string>
<string name="bmr4">very active (hard exercise/\nsports 6-7 days a week)</string>
<string name="bmr5">extra active (very hard exercise/sports &amp;\nphysical job or 2x training)</string>

выглядит так:

enter image description here

и это макет, который счетчик использует в качестве строки:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/default_listview_row"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:singleLine="false"
    android:gravity="center_vertical"
    android:textColor="@android:color/white"
    android:background="@android:color/transparent"
    android:padding="5dp" />