【问题标题】:Dynamic Spinner with icons inheriting AppCompat theme带有继承 AppCompat 主题的图标的动态微调器
【发布时间】:2016-02-02 17:17:12
【问题描述】:

我正在努力实现两件事:

  1. 让我的 Spinner 继承 AppCompat 主题。
  2. 为微调器元素添加图标,就像在工具栏弹出菜单中一样。

由于我无法实现第一点,所以我专注于这一点,但我也想稍后添加图标。现在,我的工具栏弹出菜单继承了 AppCompat 主题,但 Spinner 没有,如下图所示。第一个图像显示了来自工具栏的(正确的)弹出菜单,而第二个显示了来自 Spinner 的弹出菜单。这是不继承样式的 Spinner 示例。还是应该期待这种弹出菜单样式?

我已经尝试了很多东西,所以这个问题可能有多个重复项,但我无法让它发挥作用。下面的代码有什么问题?正确继承主题后,以后如何添加图标?最低 SDK 版本为 16,目标为 23。

themes.xml:

<resources>

    <style name="MyTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>

        <item name="colorPrimary">@color/my_brown</item>
        <item name="colorPrimaryDark">@color/my_dark_gray</item>
        <item name="colorAccent">@color/my_green</item>

        <!-- This is just a test, it makes no difference. -->
        <item name="android:spinnerStyle">@style/MySpinnerStyle</item>

    </style>

    <style name="MyTheme" parent="MyTheme.Base"></style>

    <!--
        ActionBar style, applied directly to XML elements
    -->
    <style name="MyActionBarStyle" parent="@style/Widget.AppCompat.ActionBar">
        <item name="theme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
        <item name="popupTheme">@style/ThemeOverlay.AppCompat.Light</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:background">@color/my_brown</item>
        <item name="android:minHeight">?attr/actionBarSize</item>
    </style>

    <!--
        Spinner style, for testing. Also tried applied directly to xml Spinners.
    -->
    <style name="MySpinnerStyle" parent="@style/Widget.AppCompat.Spinner">
        <item name="popupTheme">@style/ThemeOverlay.AppCompat.Light</item>
        <item name="android:popupMenuStyle">@style/Widget.AppCompat.Light.PopupMenu</item>
     </style>
</resources>

微调器的设置很简单:

ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, mCategories);
mSpinner.setAdapter(adapter);

其中mSpinner 是膨胀的 Spinner,mCategories 是一个字符串数组。在 XML 中 Spinner 被定义为

<Spinner
    android:id="@+id/my_spinner"
    android:layout_weight="1"
    android:layout_width="0dp"
    android:layout_height="wrap_content"/>

我试过直接给 Spinner 添加各种样式,但是不行。

在我的 AndroidManifest.xml 中,我在 Application 标签中添加了以下内容:

android:theme="@style/MyTheme"

【问题讨论】:

    标签: android material-design android-spinner android-appcompat android-theme


    【解决方案1】:

    我设法通过改变主题和风格来做到这一点(或非常接近它):

    只需添加到您的主题中:

    <item name="android:spinnerDropDownItemStyle">@style/MySpinnerItem</item>
    

    然后为 MySpinnerItem 创建一个继承自 Widget.AppCompat.DropDownItem.Spinner 的样式:

    <style name="MySpinnerItem" parent="@style/Widget.AppCompat.DropDownItem.Spinner">
        <item name="android:textColor">@color/your_text_color</item>
        <item name="android:textSize">16sp</item>
        <item name="android:paddingLeft">16dp</item>
        <item name="android:paddingStart" tools:targetApi="jelly_bean_mr1">16dp</item>
        <item name="android:paddingRight">16dp</item>
        <item name="android:paddingEnd" tools:targetApi="jelly_bean_mr1">16dp</item>
    </style>
    

    这就是 AppCompat 主题。

    最后,如果您想为列表项添加图标,您必须创建自定义布局并以编程方式进行设置。您可以按照本教程 http://android-er.blogspot.sg/2010/12/custom-arrayadapter-for-spinner-with.html 进行说明。 基本上你必须:

    • 创建自定义布局
    • 创建一个继承自ArrayAdapter的自定义适配器
    • 实现getCutomView() 方法来为每个项目设置不同的图像
    • 最后使用MyCustomAdapter.createFromResource(this, R.array.my_data, R.layout.my_cutom_item_layout); 将您的适配器设置为微调器

    【讨论】:

    • 我们真的必须为 Spinner 实现填充和一切吗?从documentation 看来,它应该开箱即用。 Spinner 的外观同样重要,而不仅仅是弹出菜单。这在其他 StackOverflow 答案中也有建议,例如 this
    • 事实上,它开箱即用,但出于某种原因,在三星设备上,字体颜色不是来自 AppCompat 主题的颜色,并且边距与所有设备的溢出菜单不同,这就是为什么我以我在回答中描述的方式结束。
    • 我找不到任何继承主题的设备。我试过两台三星设备和一台索尼设备以及多个模拟器。也许我必须像你一样做。不过好像有点奇怪。
    【解决方案2】:

    我的问题的原因是在行

    ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, mCategories);
    

    我在这里使用android.R.layout.simple_spinner_item,这可能是为了微调器本身。改用 android.R.layout.simple_spinner_dropdown_item 可以为下拉项提供所需的外观。

    this 问题中详细描述了它们之间的区别,尽管这些图像适用于较旧的 Android 版本。

    作为参考,这里是直接取自 Android 源代码的两个布局。

    simple_spinner_item

    <TextView xmlns:android="http://schemas.android.com/apk/res/android" 
        android:id="@android:id/text1"
        style="?android:attr/spinnerItemStyle"
        android:singleLine="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="marquee"
        android:textAlignment="inherit"/>
    

    simple_spinner_dropdown_item

    <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@android:id/text1"
        style="?android:attr/spinnerDropDownItemStyle"
        android:singleLine="true"
        android:layout_width="match_parent"
        android:layout_height="?android:attr/dropdownListPreferredItemHeight"
        android:ellipsize="marquee"/>
    

    为下拉项添加图标

    现在,对于图标部分,我按照@euitam 的步骤进行操作,结果如下:

    我的适配器:

    public class MyAdapter extends ArrayAdapter<String>
    {
        private String[] mCategories;
        private int[] mIcons;
    
        public CategoryDropDownAdapter(Context context, int layoutResourceId, String[] categories)
        {
            super(context, layoutResourceId, categories);
            mCategories = categories;
    
            // Add the same icon to all items, just for testing.
            mIcons = new int[mCategories.length];
            for (int i = 0; i < mIcons.length; i++)
            {
                mIcons[i] = R.drawable.my_icon;
            }
        }
    
        /**
        * View for a dropdown item.
        * */
        @Override
        public View getDropDownView(int position, View convertView, ViewGroup parent)
        {
            View rowView = convertView;
    
            if (rowView == null)
            {
                LayoutInflater inflater = LayoutInflater.from(parent.getContext());
                rowView = inflater.inflate(R.layout.my_spinner_categories_dropdown_item, parent, false);
            }
    
            TextView categoryText = (TextView) rowView.findViewById(R.id.my_spinner_dropdown_item_text);
            categoryText.setText(mCategories[position]);
    
            ImageView icon = (ImageView) rowView.findViewById(R.id.my_spinner_dropdown_item_icon);
            icon.setImageResource(mIcons[position]);
    
            return rowView;
        }
    
        /**
         * The Spinner View that is selected and shown in the *Spinner*, i.e. not the dropdown item.
         * */
        @Override
        public View getView(int position, View convertView, ViewGroup parent)
        {
            View spinnerView = convertView;
    
            if (spinnerView == null)
            {
                LayoutInflater inflater = LayoutInflater.from(parent.getContext());
                spinnerView = inflater.inflate(R.layout.my_spinner_categories_spinner_item, parent, false);
            }
    
            TextView categoryText = (TextView) spinnerView.findViewById(R.id.my_spinner_item_text);
            categoryText.setText(mCategories[position]);
    
            return spinnerView;
        }
    
    }
    

    my_spinner_categories_dropdown_item.xml

    <?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"
        android:orientation="horizontal" >
    
        <ImageView
            android:id="@+id/my_spinner_dropdown_item_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
        <!-- Stolen from android.R.layout.simple_spinner_dropdown_item -->
        <TextView
            android:id="@+id/my_spinner_dropdown_item_text"
            style="?android:attr/spinnerDropDownItemStyle"
            android:singleLine="true"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ellipsize="marquee" />
    
    </LinearLayout>
    

    my_spinner_categories_spinner_item.xml

    <?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"
        android:orientation="horizontal" >
    
        <!-- Stolen from android.R.layout.simple_spinner_dropdown_item -->
        <TextView
            android:id="@+id/my_spinner_item_text"
            style="?android:attr/spinnerDropDownItemStyle"
            android:singleLine="true"
            android:layout_width="0dp"
            android:layout_height="48dp"
            android:layout_weight="1"
            android:ellipsize="marquee" />
    
    </LinearLayout>
    

    最后,设置适配器:

    MyAdapter adapter = new MyAdapter(getContext(), android.R.layout.simple_spinner_dropdown_item, mCategories);
    mSpinner.setAdapter(adapter);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-18
      • 2015-05-25
      • 1970-01-01
      • 1970-01-01
      • 2014-12-25
      • 2015-08-31
      • 1970-01-01
      • 2012-05-31
      相关资源
      最近更新 更多