微调不包装文本 – 这是一个Android的错误?
如果Spinner
项目的文本太长而无法放入一行,则文本不会被打包,而会被截断。 API级别> = 11的情况才是这种情况。 这里是Android 4.2.2 (左)的屏幕截图,它显示了错误的行为和Android 2.3.3 (右),看起来如预期的那样。
android:singleLine="false"
在这里就被忽略了。 所以像所有其他的尝试像android:lines
, android:minLines
等android:minLines
似乎比窗口宽度宽得多。
我看到其他人有同样的问题,但没有人能find解决办法。 那么,这是一个系统错误吗? 我不认为操作系统版本之间的这种不一致可能是有意的。
请注意:
有一些答案提出了相对简单的解决scheme。
-
编写一个自定义
Adapter
并重写getView()
以及getDropDownView()
。 这不是解决scheme,因为在这一点上,仍然存在原始问题:布局如何处理正确的换行? -
将下拉视图的
TextView
包装到父ViewGroup
。 不能使用android:layout_width="match_parent"
因为父母的宽度似乎是无限的。 -
给下拉查看一个固定的宽度。 这不适用于
Spinner
可以具有的不同的宽度。 -
当然,没有任何解决scheme是手动将
\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));
在holo主题中,默认情况下使用下拉模式。 所有移动覆盖默认样式只是移动到切换微调模式对话框模式,成功地包装多行文本,如在api 11.相反,你可以创build与new Spinner(context, Spinner.MODE_DIALOG)
或在xml中的new Spinner(context, Spinner.MODE_DIALOG)
: android:spinnerMode="dialog"
。 但这并不能解决问题,因为它是对话框,而不是下拉菜单。
我发现了另一个解决这个问题的方法:重写ArrayAdapter
getDropDownView
方法,并将setSingleLine(false)
放在post方法的视图中。 所以当查看完全创build它包装文本适当的行。
@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); } }); } }
我已经通过切换到对话框样式的微调来解决了这个问题:
<Spinner ... android:spinnerMode="dialog" />
使用Holo
主题在Spinner
上实现多行下拉项目是不可能的,从我试过的。
解决方法是:
- 为不是从
Holo
inheritance的Spinner
创build风格。 这将启用多行下拉项目。 - 微调风格“手动”,所以它看起来像是
Holo
主题。
这产生(显示closures和打开状态):
实施细节:
即使我们将下拉项目的TextView
singleLine
属性设置为false
并提供自定义布局,也无法从Spinner
的Holo
主题inheritance,并在Spinner
下拉菜单中显示多行。 我也尝试保持Holo
风格,但改变了
android:spinnerStyle android:spinnerItemStyle android:spinnerDropDownItemStyle
样式属性( 在这里使用这些属性的例子),但我不能让它产生一个多行结果。
但是,如果我们重写Spinner
的样式并且不从Holo
inheritancespinnerStyle
:
<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>
那么下拉项目将支持显示多行。 但是现在我们已经在Spinner
上丢失了Holo
主题,closures的状态看起来像是一个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
closures状态将显示箭头,但会像Holo
应用程序中看起来不合适的灰色Holo Spinner
一样。
那么,一个可能的解决scheme是:
- 覆盖
spinnerStyle
的主题,不要使用Holo
作为父项。 这将启用DropDown项目中的多行文本。 - 将
Spinner
背景更改为inheritanceHolo
主题。
这是一个例子:
创build一个基本的活动:
@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-hdpi
文件夹中包含这些drawable:
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
主题的closures状态和多行项目的微调,如上面的截图所示。
在这个例子中的下拉菜单不是全部主题,但是如果多行显示下拉菜单是非常重要的话,这也许是一个可以接受的折衷。
在这个例子中, android:minSdkVersion
被设置为14
,在Manifest中android:targetSdkVersion
被设置为17
。
Holo
graphics和spinner_background_holo_light.xml
代码来自HoloEverywhere版权所有(c)2012 Christophe Versieux,Sergey Shatunov。 有关许可证详细信息,请参阅链接到github项目。
在TextView周围添加一个LinearLayout允许文本正确包装。
布局(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; } }
这里只有解决scheme的组合(也在Android 5.1上testing过):
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);
我面临同样的问题。 我想看看下拉列表中的2行,但是我发现的所有解决scheme对于解决这个简单的问题似乎都是不合理的。 我调查微调源代码 ,我发现如果我们使用自定义.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; }
这就是为什么我们看到每个列表只有一个string行,实际上是滚动。
为了解决这个问题,我们的视图应该不是 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);
这个解决scheme工作在微调模式:MODE_DROPDOWN和MODE_DROPDOWN.HOP它可以帮助你!
阅读这个答案︰textview铸造错误: – android.widget.LinearLayout不能转换为android.widget.TextView和这个主题,我可以解决这个问题:我们需要一个LinearLayout包装TextView(微调文本),以避免文本获取从屏幕出来,但是我们会有一些问题需要解决。 要开始,创build布局( 我称之为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>
下一步是创build一个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);
不要忘了在ArrayAdapter中添加布局名称和TextView id,因为我们添加了LinearLayout,我们需要指定TextView,并重写getDropDownView以获取在数据集中指定位置显示数据的视图。 现在,我们可以看到微调器在较新和较旧的Android版本上运行良好
我认为在android上有一个错误。 你可以试试这个。 从文本中删除空格,然后显示它将正常工作。 如果textview的长度小于string的长度,则忽略空格后的所有字符。 对于解决方法,你可以试试这个:
使用示例代码将一个文件添加到名为multiline_spinner_dropdown_item.xml的res / layout文件夹中:
<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" />
当你创build微调,从这个布局创build它。
就像是 :
ArrayAdapter.createFromResource(this, items, R.layout.multiline_spinner_dropdown_item);
基本上,将android.R.layout.simple_spinner_dropdown_item布局复制到项目中,并通过在CheckedTextView中将singleLine属性设置为false来修改布局。
我有这个相同的问题,并find了解决办法。
我想在最初的显示和下拉视图中包装文本。
文本包装在最初的显示和下拉我发现了另一个解决schemebuild议使用自定义视图的固定宽度的线性布局封闭一个文本视图。 这使得微调器的下拉看起来是正确的,以及最初的select。 但是,这在旧设备上造成了一个主要问题。
最初的显示不会刷新,如果我试图select其他的东西,文本就会堆叠起来。 而且由于它向下叠加,添加背景没有帮助。
事实certificate,适配器有一个名为setDropDownViewResource()的方法,它允许你为下拉菜单设置一个不同的视图,而不是鼠标初始select中显示的内容。
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的下拉视图内以及在spinners中显示的选项中进行包装。
用LinearLayout
包装TextView
:
<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);
我通过在文本中添加\ 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" />
以下是我所做的工作:
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已有的风格
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);
希望它解决了你的问题。