Spinner不会包装文本 - 这是一个Android错误吗?

Mat*_*ers 66 android spinner android-layout android-spinner

如果项目的文本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>
Run Code Online (Sandbox Code Playgroud)

/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" />
Run Code Online (Sandbox Code Playgroud)

设置Adapter:

spinner.setAdapter(ArrayAdapter.createFromResource(this,
            R.array.items,
            R.layout.spinner_item));
Run Code Online (Sandbox Code Playgroud)

Kol*_*uga 33

在holo主题中,spinner默认使用下拉模式.所有具有覆盖默认样式的移动只是移动到将微调器模式切换到对话框模式,该模式成功地包装了api 11中的多行文本.相反,您可以使用new Spinner(context, Spinner.MODE_DIALOG)或在xml中创建微调器:android:spinnerMode="dialog".但它并没有解决问题,因为它是对话框,而不是下拉列表.

我找到了另一个解决这个问题的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;
}
Run Code Online (Sandbox Code Playgroud)

更新:

这是另一个答案.

在PopupWindow中手动包装listview并在单击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);
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)


cVo*_*nin 13

我通过切换到对话框式微调器解决了这个问题:

<Spinner
  ...
android:spinnerMode="dialog" />
Run Code Online (Sandbox Code Playgroud)

  • 这不*解决*问题,这*避免*问题 (7认同)

and*_*per 13

这里只有一组解决方案适合我(在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>
Run Code Online (Sandbox Code Playgroud)

  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);
Run Code Online (Sandbox Code Playgroud)


Mik*_*all 7

在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>
Run Code Online (Sandbox Code Playgroud)

适配器:

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

}
Run Code Online (Sandbox Code Playgroud)


gir*_*dge 7

我面临同样的问题。我想在微调器的下拉列表中看到 2 行,但是我发现的所有解决方案在我看来都无法解决如此简单的问题。我调查了Spinner 源代码,我发现如果我们使用 带有属性 android:singleLine="false" 的自定义 .xml

<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" />
Run Code Online (Sandbox Code Playgroud)

默认的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;        
}
Run Code Online (Sandbox Code Playgroud)

这就是为什么我们在每个列表行中只看到一个字符串行,它实际上是在滚动。

要解决这样的问题,我们的视图不应该是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>
Run Code Online (Sandbox Code Playgroud)

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 
               R.layout.multiline_spinner_dropdown_item,R.id.multiline_spinner_text_view,
                awasomeListValues);
Run Code Online (Sandbox Code Playgroud)

此解决方案适用于两种微调模式:MODE_DROPDOWN 和 MODE_DROPDOWN。希望对您有所帮助!


Gun*_*son 6

根据我的尝试,Spinner使用Holo主题暂时实现多行下拉项目是不可能的.

解决方案解决方案是:

  • Spinner不继承的样式创建样式Holo.这将启用多行下拉项.
  • 手动调整微调器的样式,使它看起来像是Holo主题.

这会产生(显示关闭和打开状态):

在此输入图像描述

实施细节:

就我所知,即使我们将下拉项的属性设置为并提供自定义布局,也无法从下拉项中的Holo主题继承Spinner并在Spinner下拉项中显示多行.我也试过保持风格,但改变了TextView singleLinefalseHolo

android:spinnerStyle
android:spinnerItemStyle 
android:spinnerDropDownItemStyle 
Run Code Online (Sandbox Code Playgroud)

样式属性(这里使用这些属性的例子)但我无法使它产生多行结果.

但是,如果我们覆盖该样式Spinner并且不继承spinnerStyleHolo:

 <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>
Run Code Online (Sandbox Code Playgroud)

然后下拉项将支持显示多行.但是,现在我们已经失去了Holo对主题Spinner和闭合状态貌似TextView不是Spinner没有箭头或视觉线索,这是一个Spinner.如果我们将spinnerStyleparent 设置为parent="android:style/Widget.Spinner:

<style name="spinnerStyle" parent="android:style/Widget.Spinner">
    <item name="android:clickable">true</item>
</style>
Run Code Online (Sandbox Code Playgroud)

Spinner闭合状态下会显示箭头,但会像样式灰色预全息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));        
}
Run Code Online (Sandbox Code Playgroud)

活动布局:

<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>
Run Code Online (Sandbox Code Playgroud)

款式:

<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>
Run Code Online (Sandbox Code Playgroud)

在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>
Run Code Online (Sandbox Code Playgroud)

并在您的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主题闭合状态和多行项目的微调器,如上面的屏幕截图所示.

此示例中的下拉项目不是Holo主题,但如果下拉项目的多行显示非常重要,则可能是可接受的权衡.

在这个例子中,android:minSdkVersion设置为14android:targetSdkVersion17在清单.

Holo图形和spinner_background_holo_light.xml代码来自HoloEverywhere版权所有(c)2012 Christophe Versieux,Sergey Shatunov.有关许可证详细信息,请参阅linked-to github项目.