具有继承 AppCompat 主题的图标的动态微调器
Dynamic Spinner with icons inheriting AppCompat theme
我正在努力实现两件事:
- 让我的 Spinners 继承 AppCompat 主题。
- 向微调器元素添加图标,这在工具栏弹出菜单中是可能的。
由于我无法实现第一点,所以我专注于此,但我也想稍后添加图标。就像现在一样,我的工具栏弹出菜单继承了 AppCompat 主题,但 Spinners 没有,如下图所示。第一张图片显示了工具栏中的(正确的)弹出菜单,而第二张图片显示了微调器中的弹出菜单。这是未继承样式的 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>
Spinner 的设置非常简单:
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"/>
我试过直接在微调器中添加各种样式,但是没有用。
在我的 AndroidManifest.xml 中,我已将以下内容添加到应用程序标签中:
android:theme="@style/MyTheme"
我设法通过改变主题和风格来做到(或非常接近):
只需添加到您的主题中:
<item name="android:spinnerDropDownItemStyle">@style/MySpinnerItem</item>
然后为继承自 Widget.AppCompat.DropDownItem.Spinner
的 MySpinnerItem 创建样式:
<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);
将适配器设置为微调器
我的问题出在行
ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, mCategories);
这里我使用的是 android.R.layout.simple_spinner_item
,这可能是 Spinner 本身的意思。使用 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);
我正在努力实现两件事:
- 让我的 Spinners 继承 AppCompat 主题。
- 向微调器元素添加图标,这在工具栏弹出菜单中是可能的。
由于我无法实现第一点,所以我专注于此,但我也想稍后添加图标。就像现在一样,我的工具栏弹出菜单继承了 AppCompat 主题,但 Spinners 没有,如下图所示。第一张图片显示了工具栏中的(正确的)弹出菜单,而第二张图片显示了微调器中的弹出菜单。这是未继承样式的 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>
Spinner 的设置非常简单:
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"/>
我试过直接在微调器中添加各种样式,但是没有用。
在我的 AndroidManifest.xml 中,我已将以下内容添加到应用程序标签中:
android:theme="@style/MyTheme"
我设法通过改变主题和风格来做到(或非常接近):
只需添加到您的主题中:
<item name="android:spinnerDropDownItemStyle">@style/MySpinnerItem</item>
然后为继承自 Widget.AppCompat.DropDownItem.Spinner
的 MySpinnerItem 创建样式:
<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);
将适配器设置为微调器
我的问题出在行
ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, mCategories);
这里我使用的是 android.R.layout.simple_spinner_item
,这可能是 Spinner 本身的意思。使用 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);