微调不包装文本 – 这是一个Android的错误?

如果Spinner项目的文本太长而无法放入一行,则文本不会被打包,而会被截断。 API级别> = 11的情况才是这种情况。 这里是Android 4.2.2 (左)的屏幕截图,它显示了错误的行为和Android 2.3.3 (右),看起来如预期的那样。

android:singleLine="false"在这里就被忽略了。 所以像所有其他的尝试像android:linesandroid:minLinesandroid: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上实现多行下拉项目是不可能的,从我试过的。

解决方法是:

  • 为不是从Holoinheritance的Spinner创build风格。 这将启用多行下拉项目。
  • 微调风格“手动”,所以它看起来像是Holo主题。

这产生(显示closures和打开状态):

在这里输入图像说明

实施细节:

即使我们将下拉项目的TextView singleLine属性设置为false并提供自定义布局,也无法从SpinnerHolo主题inheritance,并在Spinner下拉菜单中显示多行。 我也尝试保持Holo风格,但改变了

 android:spinnerStyle android:spinnerItemStyle android:spinnerDropDownItemStyle 

样式属性( 在这里使用这些属性的例子),但我不能让它产生一个多行结果。

但是,如果我们重写Spinner的样式并且不从HoloinheritancespinnerStyle

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

Spinnerclosures状态将显示箭头,但会像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

Holographics和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 &amp;\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); 

希望它解决了你的问题。