如何让ArrayAdapter.getView()在ArrayList()上正常工作?

huangapple 未分类评论44阅读模式
英文:

How can ArrayAdapter.getView() be made to work on an ArrayList()?

问题

以下是您提供的代码部分的翻译:

我需要在我的下拉列表Spinner中显示特定位置上的值但是出现了以下错误

> java.lang.IllegalStateException: ArrayAdapter 要求资源 ID 为 TextView

错误是因为我的下拉列表使用以下简单列表设置

        mSpinner = findViewById(R.id.spinner);
        TextView msgTv = findViewById(R.id.errorMessage);
        if (listTypes.size() > 0) {
            /*
            隐藏错误消息
             */
            msgTv.setVisibility(View.GONE);
            /*
             *  列表有多于零个元素,因此在 LogCat 中打印它们
             */
            for(int i = 0; i < listTypes.size(); i++) {
                Type type = listTypes.get(i);
                int id = type.getId();
                typeNameString = type.getType();
                Log.d(TAG, "类型 " + typeNameString + ",ID 为:" + id);
            }
            // 为下拉列表创建仅包含 Type 名称的 spinnerList
            spinnerList =  new ArrayList<>();
            for (int i = 0; i &lt; listTypes.size(); i++) {
                typeNameString = listTypes.get(i).getType();
                spinnerList.add(typeNameString);
                Log.d(TAG, "类型 " + i + " 的 typeNameString 是:" + typeNameString);
            }
            /*
             * 将适配器设置为使用此上下文,使用默认的 Android 下拉列表部件,从 typeCursor 列作为源(from),
             * 在 'to' 目标中显示,无标志
             */
            typeArrayAdapter = new ArrayAdapter<>(this, R.layout.support_simple_spinner_dropdown_item, spinnerList);
            mSpinner.setAdapter(typeArrayAdapter);
        } else {
            /*
             * TABLE_TYPE 中不存在类型,因此添加它们
             */
            msgTv.setText(R.string.no_types);
            msgTv.setVisibility(View.VISIBLE);
        }
生成下拉列表的代码如下

    private void setProviderInfo() {
        Log.d(TAG, "进入 setProviderInfo");
        .
        .
        .
        mSpinner.setAdapter(typeArrayAdapter);
        mSpinner.setSelection(spinnerList.indexOf(type), true);
        //TODO: 尝试使用 getView() 来在下拉列表中显示 setSelection() 的值
        ViewGroup view = (ViewGroup) findViewById(android.R.id.content);
        typeArrayAdapter.getView(position, mSpinner, view);
        .
        .
        .
    }
我的下拉列表的 XML 如下:

    <Spinner
        android:id="@+id/spinner"
        style="@style/Spinner"
        android:prompt="@string/select_provider_type"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvProviderTitle" />
样式如下:

    <style name="Spinner">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:layout_marginTop">8dp</item>
        <item name="android:background">@android:color/holo_blue_bright</item>
        <item name="android:layout_marginStart">8dp</item>
        <item name="android:paddingTop">5dp</item>
        <item name="android:paddingBottom">10dp</item>
        <item name="android:layout_marginEnd">8dp</item>
        <item name="android:clickable">true</item>

我会尽量保持翻译的准确性,但如果您在代码的上下文中发现了一些不通顺或者错误的地方,请随时指出。

英文:

I need to display the value at a specific position in my spinner but get a

> java.lang.IllegalStateException: ArrayAdapter requires the resource ID
> to be a TextView

error because my spinner uses a simple list set up as follows:

    mSpinner = findViewById(R.id.spinner);
    TextView msgTv = findViewById(R.id.errorMessage);
    if (listTypes.size() &gt; 0) {
        /*
        hide the error message
         */
        msgTv.setVisibility(View.GONE);
        /*
         *  the List has more than zero elements, so print them out in LogCat
         */
        for(int i = 0; i &lt; listTypes.size(); i++) {
            Type type = listTypes.get(i);
            int id = type.getId();
            typeNameString = type.getType();
            Log.d(TAG, &quot;type &quot; + typeNameString + &quot; with an ID of: &quot; + id);
        }
        //create spinner List&lt;&gt; of Type names only for use with the spinner
        spinnerList =  new ArrayList&lt;&gt;();
        for (int i = 0; i &lt; listTypes.size(); i++) {
            typeNameString = listTypes.get(i).getType();
            spinnerList.add(typeNameString);
            Log.d(TAG, &quot;Type &quot; + i + &quot; typeNameString is: &quot; + typeNameString);
        }
        /*
         * set the adapter to use &#39;this&#39; context, the default Android spinner widget, typeCursor
         * tyepCursor column as the source (from), display in the &#39;to&#39; destination, no flags
         */
        typeArrayAdapter = new ArrayAdapter&lt;&gt;(this, R.layout.support_simple_spinner_dropdown_item, spinnerList);
        mSpinner.setAdapter(typeArrayAdapter);
    } else{
        /*
         * no types exist in TABLE_TYPE, so add them
         */
        msgTv.setText(R.string.no_types);
        msgTv.setVisibility(View.VISIBLE);
    }

My code to generate the spinner is as follows:

private void setProviderInfo(){
    Log.d(TAG, &quot;Entered setProviderInfo&quot;);
    .
    .
    .
    mSpinner.setAdapter(typeArrayAdapter);
    mSpinner.setSelection(spinnerList.indexOf(type), true);
    //TODO: try getView() to display the setSelection() value in spinner
    ViewGroup view = (ViewGroup) findViewById(android.R.id.content);
    typeArrayAdapter.getView(position, mSpinner, view);
    .
    .
    .
}

My spinner's xml is:

&lt;Spinner
    android:id=&quot;@+id/spinner&quot;
    style=&quot;@style/Spinner&quot;
    android:prompt=&quot;@string/select_provider_type&quot;
    app:layout_constraintStart_toStartOf=&quot;parent&quot;
    app:layout_constraintTop_toBottomOf=&quot;@+id/tvProviderTitle&quot; /&gt;

The style is:

&lt;style name=&quot;Spinner&quot;&gt;
    &lt;item name=&quot;android:layout_width&quot;&gt;match_parent&lt;/item&gt;
    &lt;item name=&quot;android:layout_height&quot;&gt;50dp&lt;/item&gt;
    &lt;item name=&quot;android:layout_marginTop&quot;&gt;8dp&lt;/item&gt;
    &lt;item name=&quot;android:background&quot;&gt;@android:color/holo_blue_bright&lt;/item&gt;
    &lt;item name=&quot;android:layout_marginStart&quot;&gt;8dp&lt;/item&gt;
    &lt;item name=&quot;android:paddingTop&quot;&gt;5dp&lt;/item&gt;
    &lt;item name=&quot;android:paddingBottom&quot;&gt;10dp&lt;/item&gt;
    &lt;item name=&quot;android:layout_marginEnd&quot;&gt;8dp&lt;/item&gt;
    &lt;item name=&quot;android:clickable&quot;&gt;true&lt;/item&gt;

My spinner works that means that ArrayAdapter.getView() works on the ArrayList that is spinnerList using R.layout.support_simple_spinner_dropdown_item, not a TextView. So, what do I need to do to get my direct call to getView() to display the value at setSelection() as happens when Android does it by default?

I have read the following (there are more), but didn't find anything useful as the initial, default call to ArrayAdapter.getView() works without a TextView widget in my xml:

ArrayAdapter requires the resource ID to be a TextView

“ArrayAdapter requires the resource ID to be a TextView” issue

ArrayAdapter requires the resource ID to be a TextView in DialogFragment

“ArrayAdapter requires the resource ID to be a TextView” xml problems

“ArrayAdapter requires the resource ID to be a TextView” error for AndroidX

Android ExpandableListAdapter: ArrayAdapter requires the resource ID to be a TextView

答案1

得分: 0

好的,以下是翻译好的内容:

好的,当您使用Android提供的资源(如R.layout.support_simple_spinner_dropdown_item)时,无法将微调器设置为特定值。正如我在原始问题的评论中指出的那样,ArrayAdapter创建了一个您无法访问的视图。这就要求您创建一个自定义适配器。有很多关于在网络和stackoverflow上执行此操作的示例。

其中的核心是在Activity的xml布局文件中声明您的微调器,如下所示:

<Spinner
    android:id="@+id/spinner"
    style="@style/Spinner"
    android:prompt="@string/select_provider_type"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/tvProviderTitle" />

以及Adapter将把spinnerList的值写入的TextView元素,该元素位于其自己的xml文件中:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/typeName"
    style="@style/TypeName"/>

TextView将由您的自定义适配器使用其getView()方法填充,用于微调器本身,以及getDropDownView()方法,用于点击后展开的列表:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    Log.d(TAG, "Entered: getView");
    convertView = mLayoutInflater.inflate(R.layout.type_name_only, null);
    TextView typeName = convertView.findViewById(R.id.typeName);
    typeName.setText(types.get(position));
    return convertView;
}

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    Log.d(TAG, "Entered: getDropDownView");
    convertView = mLayoutInflater.inflate(R.layout.type_name_only, null);
    TextView typeName = convertView.findViewById(R.id.typeName);
    typeName.setText(types.get(position));
    typeName.setBackgroundColor(GREEN);
    typeName.setTextColor(BLUE);
    return convertView;
}

请注意,您还必须重写getCount()方法,以便适配器可以确定要添加到微调器中的元素数量:

@Override
public int getCount() {
    return yourList.size();
}

如果对您来说不太明显,一开始对我来说也不是很明显,您在Activity中不需要声明也不需要设置TextView,只需要设置微调器:

    mSpinner = findViewById(R.id.spinner);

在您的Activity中,将微调器设置为其列表中的特定元素,如下所示:

    mSelectTypeAdapter = new SelectTypeAdapter(mContext, R.id.spinner, spinnerList);
    mSpinner.setAdapter(mSelectTypeAdapter);
    mSpinner.setOnItemSelectedListener(this);
    mSpinner.setSelection(spinnerList.indexOf(itemToBeSelected), true);
    ViewGroup viewGroup = findViewById(android.R.id.content);
    mSelectTypeAdapter.getView(spinnerList.indexOf(itemToBeSelected), mSpinner, viewGroup);
  • mSpinner.setSelection()选择要显示的特定列表索引,即itemToBeSelected的spinnerList项目的索引
  • ViewGroup是“this” Activity的容器
  • mSelectTypeAdapter.getView()根据其在spinnerList中的索引设置要在微调器中显示的列表项

Android会将您的每个列表元素分别显示在Activity的微调器中的TextView中,就像您在适配器的getView()和getDropDownView()方法中设置的一样。我制作了很多丰富多彩且不同的内容,以验证它是否按照我想的那样工作。

英文:

OK, you cannot set the spinner to a specific value when you use the Android provided resources, such as R.layout.support_simple_spinner_dropdown_item. As I noted in the comments under the original question, the ArrayAdapter created a View that you cannot access. This mandates that you create a custom adapter. There are many examples of doing this on the web and on stackoverflow.

Central to this is to have your spinner declared in the Activity's xml layout file, such as:

&lt;Spinner
    android:id=&quot;@+id/spinner&quot;
    style=&quot;@style/Spinner&quot;
    android:prompt=&quot;@string/select_provider_type&quot;
    app:layout_constraintStart_toStartOf=&quot;parent&quot;
    app:layout_constraintTop_toBottomOf=&quot;@+id/tvProviderTitle&quot; /&gt;

and the TextView element that the Adapter will write your spinnerList values to in its own xml file:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;

&lt;TextView xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:id=&quot;@+id/typeName&quot;
    style=&quot;@style/TypeName&quot;/&gt;

The TextView will be filled by your custom adapter using its getView() method, for the spinner itself, and the getDropDownView() method, for the expanded list upon click:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    Log.d(TAG, &quot;Entered: getView&quot;);
    convertView = mLayoutInflater.inflate(R.layout.type_name_only, null);
    TextView typeName = convertView.findViewById(R.id.typeName);
    typeName.setText(types.get(position));
    return convertView;
}

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    Log.d(TAG, &quot;Entered: getDropDownView&quot;);
    convertView = mLayoutInflater.inflate(R.layout.type_name_only, null);
    TextView typeName = convertView.findViewById(R.id.typeName);
    typeName.setText(types.get(position));
    typeName.setBackgroundColor(GREEN);
    typeName.setTextColor(BLUE);
    return convertView;
}

Note that you must also override the getCont() method so that the adapter can determine how many elements to add to your spinner:

@Override
public int getCount() {
    return yourList.size();
}

If it isn't obvious to you, it wasn't at first to me, you do not declare nor set your TextView in your Activity, only your spinner:

    mSpinner = findViewById(R.id.spinner);

In your Activity, set the spinner to a specific element in its list as follows:

    mSelectTypeAdapter = new SelectTypeAdapter(mContext, R.id.spinner, spinnerList);
    mSpinner.setAdapter(mSelectTypeAdapter);
    mSpinner.setOnItemSelectedListener(this);
    mSpinner.setSelection(spinnerList.indexOf(itemToBeSelected), true);
    ViewGroup viewGroup = findViewById(android.R.id.content);
    mSelectTypeAdapter.getView(spinnerList.indexOf(itemToBeSelected), mSpinner, viewGroup);
  • mSpinner.setSelection() selects the specific list index to show, in
    this case that of the itemToBeSelected spinnerList item
  • The ViewGroup is that of "this" Activity
  • mSelectTypeAdapter.getView() sets the list item that is to be
    displayed in the spinner in accordance with its index in the
    spinnerList

Android will display each of your list elements in its own TextView in the Activity's spinner as you set in the Adapter's getView() and getDropDownView() methods. I made mine very colorful and different to verify that it worked as I thought it would.

huangapple
  • 本文由 发表于 2020年4月4日 06:33:59
  • 转载请务必保留本文链接:https://java.coder-hub.com/61021411.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定