Spinner не переносит текст - это ошибка Android?
Если текст Spinner
Элемент слишком длинный, чтобы поместиться в одну строку, текст не оборачивается, а обрезается. Это относится только к уровню API> = 11. Вот скриншоты Android 4.2.2 (слева), который показывает неправильное поведение, и Android 2.3.3 (справа), где он выглядит, как и ожидалось.
android:singleLine="false"
просто игнорируется здесь. Так как все другие попытки, как android:lines
, android:minLines
и т. д. TextView
как-то кажется намного шире, чем ширина окна.
Я видел других людей, имеющих такую же проблему, но никто не мог найти решение. Итак, это системная ошибка? Я не думаю, что это несоответствие между версиями ОС может быть намеренным.
Пожалуйста, обратите внимание:
Были некоторые ответы, предлагающие относительно простые решения.
Написание кастома
Adapter
и переопределениеgetView()
так же какgetDropDownView()
, Здесь это не решение, потому что на данный момент все еще существует первоначальная проблема: как должен выглядеть макет для правильного переноса строк?Упаковка
TextView
раскрывающегося представления в родительскомViewGroup
, Не работает сandroid:layout_width="match_parent"
потому что ширина родителя, как ни странно, кажется неограниченной.Придание выпадающему виду фиксированной ширины. Это не подходит с различной шириной
Spinner
могу иметь.И, конечно же, нет решения вручную вставить
\n
где-нибудь в тексте.
Воспроизведите с помощью следующего кода:
ОБНОВЛЕНИЕ: Я также загрузил это как пример проекта на 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));
14 ответов
В голо-теме спиннер по умолчанию использует выпадающий режим. И все движения с переопределением стилей по умолчанию просто переходят к переключению режима счетчика в режим диалога, который успешно переносит многострочный текст, как в API 11. Вместо этого вы можете создать счетчик с new Spinner(context, Spinner.MODE_DIALOG)
или в xml: android:spinnerMode="dialog"
, Но это не решает проблему, потому что это диалог, а не выпадающий список.
Я нашел другое решение этой проблемы: переопределить getDropDownView
метод в ArrayAdapter
и положи setSingleLine(false)
в посте метод зрения. Поэтому, когда представление полностью создано, оно переносит текст в соответствующие строки.
@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;
}
ОБНОВИТЬ:
А вот и другой ответ.
Вручную оберните список в 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);
}
});
}
}
У меня сработала только комбинация решений (проверено и на 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
...
android:spinnerMode="dialog" />
Добавление 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>
адаптер:
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;
}
}
Достижение многострочных выпадающих пунктов на Spinner
при использовании Holo
тема не возможна, из того что я пробовал.
Обходное решение заключается в следующем:
- создать стиль для
Spinner
это не наследуется отHolo
, Это включит многострочные выпадающие элементы. - Стиль Spinner "вручную", чтобы он выглядел так, как будто
Holo
-themed.
Это производит (показывая закрытые и открытые состояния):
Детали реализации:
Нет способа унаследовать от 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
не 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>
в папке 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>
и включите эти Drawables в вашем 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
Тематически, но, возможно, это приемлемый компромисс, если многострочное отображение выпадающих элементов действительно важно.
В этом примере android:minSdkVersion
был установлен на 14
а также android:targetSdkVersion
в 17
в манифесте.
Holo
графика и spinner_background_holo_light.xml
код от HoloEverywhere Copyright (c) 2012 Кристоф Версье, Сергей Шатунов. См. Связанный с проектом github для деталей лицензии.
Я столкнулся с той же проблемой. Я хочу видеть 2 строки в выпадающем списке счетчика, но все решения, которые я нашел, кажутся мне неразумными для решения такой простой проблемы. Я исследую исходный код 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);
Это решение работает в режиме вращения: MODE_DROPDOWN и MODE_DROPDOWN. Надеюсь, оно вам поможет!
Я думаю, что есть ошибка на 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" />
и когда вы создаете счетчик, создайте его из этого макета.
Что-то вроде:
ArrayAdapter.createFromResource(this, items, R.layout.multiline_spinner_dropdown_item);
По сути, скопируйте макет android.R.layout.simple_spinner_dropdown_item в проект и измените макет, установив для атрибута singleLine значение false в CheckedTextView.
Я только что обнаружил, что 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);
надеюсь, это решило вашу проблему.
Вот что я сделал, чтобы это работало:
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"/>
Прочитав этот ответ: ошибка приведения в текстовое представление:- android.widget.LinearLayout не может быть приведен к android.widget.TextView и этой теме, я мог бы решить эту проблему: нам нужен LinearLayout, оборачивающий TextView (текст счетчика), чтобы избежать получения текста с экрана, но у нас будут некоторые проблемы, которые нужно решить. Для начала создайте макет (я назвал его 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, чтобы получить представление, отображающее данные в указанной позиции в наборе данных. Теперь мы можем видеть, что спиннер работает хорошо на новых и старых версиях Android
ArrayAdapter<?> specAdapter =
ArrayAdapter.createFromResource(
getActivity().getBaseContext(),
aa[position],
android.R.layout.select_dialog_item);
specAdapter.setDropDownViewResource(android.R.layout.select_dialog_item);
У меня была такая же проблема и я нашел решение.
Я хотел, чтобы текст был перенесен на начальный экран, а также в раскрывающийся список.
Текст был перенесен на начальный экран, и для раскрывающегося списка я нашел другое решение, рекомендующее использовать пользовательский вид линейного макета с фиксированной шириной, охватывающий текстовое представление. Это сделало правильное выпадающее меню счетчика, так же как и при первоначальном выборе. Однако это вызвало серьезную проблему на старых устройствах.
Начальный экран не обновлялся, и текст приобретал сложенный вид, если я пытался выбрать что-то еще. и так как он сложен вниз, добавление фона не помогло.
Как выяснилось, у адаптеров есть метод 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>
Теперь текст переносится внутри выпадающего списка счетчика И в отображаемом выделении счетчиков.
Spinner sp_type = dialogView.findViewById(R.id.sp_type);
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(getFragment().getContext(), android.R.layout.simple_spinner_dropdown_item, getFragment().getResources().getStringArray(R.array.courier_delivery_types_array));
dataAdapter.setDropDownViewResource(android.R.layout.simple_list_item_1);
simple_list_item_1 отобразит выпадающее текстовое окно счетчика с несколькими строками. Но выделенный с помощью счетчика текст отображается в одну строку. Мы можем заменить вторую строку на simple_list_item_1 вместо simple_spinner_dropdown_item(для нескольких строк)
Просто заверните 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>
Я решил эту проблему, добавив \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>
Выглядит так:
И это макет, который вращатель использует в качестве строки:
<?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" />