Spinner не обертывает текст - это ошибка Android?
Если текст элемента Spinner
слишком длинный, чтобы вписаться в одну строку, текст не обернут, а обрезается. Это относится только к уровню API >= 11. Вот скриншоты Android 4.2.2 (слева), который показывает неправильное поведение и Android 2.3.3 (справа), где он выглядит так, как ожидалось.
![Marym.png]()
![xsXtn.png]()
android:singleLine="false"
просто игнорируется здесь. Так как все остальные, например, android:lines
, android:minLines
и т.д. TextView
как-то кажется намного шире ширины окна.
Я видел других людей, имеющих одну и ту же проблему, но никто не мог найти решение. Итак, это системная ошибка? Я не думаю, что это несоответствие между версиями ОС может быть предусмотрено.
Обратите внимание:
Были некоторые ответы, предлагающие относительно простые решения.
-
Написание пользовательского Adapter
и переопределения getView()
, а также getDropDownView()
. Это не решение здесь, потому что на данный момент все еще существует оригинальная проблема: как макет должен выглядеть так, чтобы обрабатывать правильную упаковку строк?
-
Обтекание TextView
раскрывающегося списка в родительском ViewGroup
. Не работает с android:layout_width="match_parent"
, потому что ширина родителя странно кажется неограниченной.
-
Предоставление раскрывающегося списка фиксированной ширины. Это не подходит для разных ширин, которые может иметь Spinner
.
-
И, конечно же, решение не должно вручную вставлять \n
в любом месте текста.
Воспроизвести следующий код:
UPDATE: Я также добавил это как пример проекта GitHub: Загрузить
/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" />
Установить Adapter
:
spinner.setAdapter(ArrayAdapter.createFromResource(this,
R.array.items,
R.layout.spinner_item));
Ответы
Ответ 1
В голой теме spinner по умолчанию использует выпадающий режим. И все движения с переопределяющими стилями по умолчанию просто переходят к переключению режима spinner в режим диалога, который успешно обертывает многострочный текст, как в api 11. Вместо этого вы можете создать spinner с помощью new Spinner(context, Spinner.MODE_DIALOG)
или в xml: android:spinnerMode="dialog"
. Но это не решает проблему, потому что это диалог, а не раскрывающийся список.
Я нашел другое решение для этой проблемы: переопределите метод getDropDownView
в ArrayAdapter
и поместите setSingleLine(false)
в метод post 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;
}
UPDATE:
И вот еще один ответ.
Вручную переместите listview в PopupWindow и покажите его в TextView при щелчке и спрячьте его в списке.
Простая реализация, чтобы показать идею:
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);
}
});
}
}
Ответ 2
Я решил эту проблему, переключившись на диалоговое окно:
<Spinner
...
android:spinnerMode="dialog" />
Ответ 3
Для меня работала только комбинация решений (тестирование на 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);
Ответ 4
Достижение многострочных выпадающих элементов на Spinner
при использовании темы Holo
невозможно, из того, что я пробовал.
Обходным решением является:
- создайте стиль для
Spinner
, который не наследуется от Holo
. Это позволит создавать многострочные выпадающие элементы.
- Стиль Spinner 'вручную', поэтому он выглядит как
Holo
-themed.
Это создает (показывает закрытые и открытые состояния):
![enter image description here]()
Подробности реализации:
Нет способа наследовать от темы Holo
на Spinner
и показывать несколько строк в раскрывающемся элементе Spinner
, насколько я могу судить, даже если мы установим раскрывающийся элемент TextView
singleLine
к 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
не a Spinner
без стрелки или визуальной подсказки. Spinner
. Если вместо spinnerStyle
родительский элемент установить: parent="android:style/Widget.Spinner
:
<style name="spinnerStyle" parent="android:style/Widget.Spinner">
<item name="android:clickable">true</item>
</style>
закрытое состояние Spinner
покажет стрелку, но будет выглядеть как серый pre-Holo Spinner
, который выглядит неуместным в приложении Holo
.
Итак, возможно решение:
- Отмените тему для
spinnerStyle
и не используйте Holo
для родителя. Это позволит многострочный текст в элементах DropDown.
- Измените фон
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>
в выделенной папке, поставьте 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>
и включите эти чертежи в папку drawables-hdpi
:
spinner_default_holo_light.9.png
spinner_disabled_holo_light.9.png
spinner_focused_holo_light.9.png
spinner_pressed_holo_light.9.png
Это создает счетчик с Holo
-замкнутым закрытым состоянием и многострочными элементами, как показано на скриншотах выше.
Выпадающие элементы в этом примере не являются Holo
-themed, но, возможно, это приемлемый компромисс, если многолинейное отображение выпадающих элементов действительно важно.
В этом примере в манифесте android:minSdkVersion
было установлено значение 14
и android:targetSdkVersion
- 17
.
Holo
и код spinner_background_holo_light.xml
поступают из HoloEverywhere Авторское право (c) 2012 Кристоф Верси, Сергей Шатунов. См. Связанный с github проект для получения сведений о лицензии.
Ответ 5
Добавление LinearLayout вокруг TextView позволяет тексту переворачивать правильно.
Макет (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>
Adapter:
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;
}
}
Ответ 6
Я думаю, что есть ошибка на Android. Вы можете попробовать это. Удалите пробелы из текста, а затем отобразите, что он будет работать нормально. Если длина текстового вида равна < это строка, она игнорирует все символы после пробела.
Для обхода вы можете попробовать следующее:
добавить файл в папку 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" />
и когда вы создаете spinner, создайте его из этого макета.
Что-то вроде:
ArrayAdapter.createFromResource(this, items, R.layout.multiline_spinner_dropdown_item);
В основном скопируйте макет android.R.layout.simple_spinner_dropdown_item в проект и измените макет, установив для атрибута singleLine значение false в CheckedTextView.
Ответ 7
Я столкнулся с той же проблемой. Я хочу видеть 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. Надеюсь, это поможет вам!
Ответ 8
Считывание этого ответа: ошибка при отправке текста: - android.widget.LinearLayout не может быть добавлен в android.widget.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.
Ответ 9
У меня была такая же проблема и я нашел решение.
Я хотел, чтобы текст был завершен на начальном экране и в раскрывающемся меню.
Текст был обернут на начальном экране, а для раскрывающегося списка я нашел другое решение, рекомендующее использовать пользовательский вид линейного макета с фиксированной шириной, охватывающий текстовое представление. Это привело к тому, что выпадающий список был корректным, а также начальный выбор. Однако это вызвало серьезную проблему для старых устройств.
Начальный дисплей не обновляется, и текст берет на себя сложный вид, если я попытаюсь выбрать что-то еще. и поскольку он складывается вниз, добавление фона не помогло.
![enter image description here]()
Как оказалось, адаптеры имеют метод setDropDownViewResource(), который позволяет вам установить другое представление для раскрывающегося списка, чем то, что отображается в исходном выборе счетчика.
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>
Теперь текст обертывается внутри раскрывающегося списка прядильщика И в выбранном прядильщике.
Ответ 10
Просто оберните 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>
Ответ 11
ArrayAdapter<?> specAdapter =
ArrayAdapter.createFromResource(
getActivity().getBaseContext(),
aa[position],
android.R.layout.select_dialog_item);
specAdapter.setDropDownViewResource(android.R.layout.select_dialog_item);
Ответ 12
Вот что я сделал, чтобы заставить его работать:
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"/>
Ответ 13
я просто нашел, что у андроида есть существующий стиль для этого случая
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);
надеюсь, что он решил вашу проблему.
Ответ 14
Я решил эту проблему, добавив в текст \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 &\nphysical job or 2x training)</string>
Похож:
![введите описание изображения здесь]()
И это макет, который spinner использует как строку:
<?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" />