62

我的布局中有一个 Android Spinner 视图。我希望该微调器在关闭时仅显示一个文本项,但是当用户单击它时(即打开微调器对话框)我想为每个项目显示更广泛的信息,包括一个图标和一个附加的描述文本视图. 就像现在一样,微调器在两种状态下都显示了完全相同的布局(图标、标题 + 描述)。

如果我将 ArrayAdapter 附加到微调器,那么我可以访问称为“setDropDownViewResource”的东西,但这不一定是我需要的,因为我的微调器数据是从游标中获取的,而不是从任何类型的数组中获取的(我有,到目前为止,创建了我自己的适配器,扩展了 BaseAdapter)。

谁能帮助我?

4

6 回答 6

115

您必须为 Spinner 创建一个自定义Adapter类并覆盖getView()正常关闭视图和getDropDownView()下拉列表视图的两种方法。两种方法都必须View为单个元素返回一个对象。

看看这个教程,它可能会帮助你入门。

于 2011-01-10T14:19:24.363 回答
16

我也遇到了问题。我没有覆盖课程,而是有一种更简单的方法来做到这一点。

但首先您需要了解适配器构造函数中的资源 id 与setDropDownViewResource(...). 例如,

SimpleAdapter adapter =
    new SimpleAdapter(ab.getThemedContext(), data, R.layout.actionbar_dropdown, new String[] { "EventID", "Icon" },
        new int[] { R.id.event_id, R.id.icon });

adapter.setDropDownViewResource(R.layout.actionbar_list_item);

R.layout.actionbar_dropdownspinnerR.layout.actionbar_list_item每个列表项的样式。

我在这里使用了 SimpleAdapter,因为如果我使用 ArrayAdapter,xml 只能是单个 TextView。

R.layout.actionbar_list_item包含一个 id 为的 TextViewevent_id和一个 id 为 的 ImageView icon

R.layout.actionbar_dropdown几乎完全一样actionbar_list_item,但后者的 ImageView 的可见性设置为GONE

这样,每个列表项都有一个 textview 和一个 imageview,但您只会在微调器上看到一个 textview。

于 2013-06-30T00:55:00.640 回答
11

使用 Flo 链接的教程代码,我创建了以下 CustomSpinnerAdapter 以显示两组不同的字符串,一组在显示项目时,另一组在不显示时。我希望它可以帮助某人。

public class CustomSpinnerAdapter extends ArrayAdapter<String> {

Context mContext;
int mTextViewResourceId;
String[] mObjects;
String[] mShortNameObjects;

public CustomSpinnerAdapter(Context context, int textViewResourceId,
                            String[] objects, String[] shortNameObjects) {
    super(context, textViewResourceId, objects);
    mContext = context;
    mTextViewResourceId = textViewResourceId;
    mObjects = objects;
    mShortNameObjects = shortNameObjects;
}

@Override
public View getDropDownView(int position, View convertView,
                            ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    TextView row = (TextView) inflater.inflate(mTextViewResourceId, parent, false);
    row.setText(mObjects[position]);

    return row;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    return getCustomView(position, convertView, parent);
}

public View getCustomView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    TextView row = (TextView) inflater.inflate(mTextViewResourceId, parent, false);
    row.setText(mShortNameObjects[position]);

    return row;
}
}

以及Fragment 内部的用法:

CustomSpinnerAdapter mSpinnerAdapter = new CustomSpinnerAdapter(getActivity(), R.layout.spinner_item, getResources().getStringArray(R.array.action_filter), getResources().getStringArray(R.array.action_filter_short_names));

最后,微调器项目的布局:

spinner_item.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="18dip"
    android:gravity="left"
    android:textColor="@color/navdraw_list_item_background_default"
    android:padding="5dip" />
于 2014-06-18T16:12:10.607 回答
8

仅使用您的替代布局设置下拉视图资源:

ArrayAdapter<String> genderAdapter = new ArrayAdapter<>(this, R.layout.adapter_spinner_white, Constants.GENDER);
genderAdapter.setDropDownViewResource(R.layout.adapter_spinner_white_dropdown);
view.setAdapter(genderAdapter);

对我来说,它只是一个带有额外填充的布局,因为我的微调器背景是圆形可绘制的,需要这个额外的空间。

于 2016-02-27T04:36:18.300 回答
1

setUpSpinner()在获取到 spinner 的引用后调用方法

// here is setUpSpinner method

private void setupSpinner() {

    // Create adapter for spinner. The list options are from the String array it will use
    // the spinner will use the default layout
    ArrayAdapter spinnerAdapter = ArrayAdapter.createFromResource(this,
            R.array.array_dropdown_options, android.R.layout.simple_spinner_item);

    // Specify dropdown layout style - simple list view with 1 item per line
    spinnerAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);

    // Apply the adapter to the spinner
    spinner.setAdapter(spinnerAdapter);
   // spinner is referenced spinner by finViewById.
    
    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            String selection = (String) parent.getItemAtPosition(position);
            if (!TextUtils.isEmpty(selection)) {
                if (selection.equals(getString(R.string.item_a))) {
                    // your code for selected item whose id equals to id to R.string.item_a
                } else if (selection.equals(getString(R.string.item_b))) {
                    // your code
                } else {
                    // your code
                }
            }
        }

        // Because AdapterView is an abstract class, onNothingSelected must be defined
        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            // code for nothing selected in dropdown
        }
    });
}
于 2018-07-14T19:37:53.393 回答
0

ArrayAdapter我尽可能多地扩展了哪些保存器的功能,只需将长描述设置为所选项目。

首先,我们需要一个新模型来为适配器供电。请注意,toString()返回shortDescription以便ArrayAdapter在下拉列表中显示简短描述:

data class DescriptiveArrayItem(val shortDescription: String, val longDescription: String) {
    override fun toString(): String {
        return shortDescription
    }
}

其次,我们创建了我们的自定义适配器,它getView()在选择项目时覆盖并显示长描述(不幸的是,其中的许多字段和方法ArrayAdapter是私有的,所以我不得不复制它们):

class DescriptiveArrayAdapter : ArrayAdapter<DescriptiveArrayItem> {
    private var mResource: Int
    private val mFieldId: Int
    private val mContext: Context
    private val mInflater: LayoutInflater

    constructor(context: Context, resource: Int) : super(context, resource) {
        mContext = context
        mFieldId = 0
        mInflater = LayoutInflater.from(context)
        mResource = resource
    }
    constructor(context: Context, resource: Int, textViewResourceId: Int) : super(context, resource, textViewResourceId) {
        mContext = context
        mFieldId = textViewResourceId
        mInflater = LayoutInflater.from(context)
        mResource = resource
    }
    constructor(context: Context, resource: Int, objects: Array<out DescriptiveArrayItem>) : super(context, resource, objects) {
        mContext = context
        mFieldId = 0
        mInflater = LayoutInflater.from(context)
        mResource = resource
    }
    constructor(context: Context, resource: Int, textViewResourceId: Int, objects: Array<out DescriptiveArrayItem>) : super(context, resource, textViewResourceId, objects) {
        mContext = context
        mFieldId = textViewResourceId
        mInflater = LayoutInflater.from(context)
        mResource = resource
    }
    constructor(context: Context, resource: Int, objects: List<DescriptiveArrayItem>) : super(context, resource, objects) {
        mContext = context
        mFieldId = 0
        mInflater = LayoutInflater.from(context)
        mResource = resource
    }
    constructor(context: Context, resource: Int, textViewResourceId: Int, objects: List<DescriptiveArrayItem>) : super(context, resource, textViewResourceId, objects) {
        mContext = context
        mFieldId = textViewResourceId
        mInflater = LayoutInflater.from(context)
        mResource = resource
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        return createViewFromResource(mInflater, position, convertView, parent, mResource)
    }

    private fun createViewFromResource(inflater: LayoutInflater, position: Int,
                                       convertView: View?, parent: ViewGroup, resource: Int): View {
        val text: TextView?
        val view: View = convertView ?: inflater.inflate(resource, parent, false)
        try {
            if (mFieldId == 0) {
                //  If no custom field is assigned, assume the whole resource is a TextView
                text = view as TextView
            } else {
                //  Otherwise, find the TextView field within the layout
                text = view.findViewById(mFieldId)
                if (text == null) {
                    throw RuntimeException("Failed to find view with ID "
                            + mContext.resources.getResourceName(mFieldId)
                            + " in item layout")
                }
            }
        } catch (e: ClassCastException) {
            Log.e("ArrayAdapter", "You must supply a resource ID for a TextView")
            throw IllegalStateException(
                    "ArrayAdapter requires the resource ID to be a TextView", e)
        }
        val item: DescriptiveArrayItem? = getItem(position)
        text.text = item?.longDescription
        return view
    }
}
于 2020-06-24T15:34:36.663 回答