on Android 2.2 the Spinner in my ActionBar looks really ugly and the dropdown text color is the same as the background color. This makes the text unreadable.
Here is the relevant code.
spinner = new Spinner(getSupportActionBar().getThemedContext());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>
(
getSupportActionBar().getThemedContext(),
R.layout.sherlock_spinner_dropdown_item,
new String[]{"All", "Solved", "Unsolved"}
);
spinner.setAdapter(spinnerArrayAdapter);
Edit: I have added the below 3 lines for completeness.
menu.add("Display")
.setActionView(spinner)
.setShowAsAction(MenuItem.Show_AS_ACTION_ALWAYS);
Here is what it looks like on Android 4.2. This is what I expected it to look like on Android 2.2 also.
When you create the SpinnerArrayAdapter
, you should use R.layout.sherlock_spinner_item
; then you should call setDropDownViewResource(R.layout.sherlock_spinner_dropdown_item)
on the adapter. Note the difference between the two resource names.
From the sample code:
Context context = getSupportActionBar().getThemedContext();
ArrayAdapter<CharSequence> list = ArrayAdapter.createFromResource(context, R.array.locations, R.layout.sherlock_spinner_item);
list.setDropDownViewResource(R.layout.sherlock_spinner_dropdown_item);
For your code this would be:
spinner = new Spinner(getSupportActionBar().getThemedContext());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>
(
getSupportActionBar().getThemedContext(),
R.layout.sherlock_spinner_item,
new String[]{"All", "Solved", "Unsolved"}
);
spinnerArrayAdapter.setDropDownViewResource(R.layout.sherlock_spinner_dropdown_item);
spinner.setAdapter(spinnerArrayAdapter);
I created a solution that uses ICS styled Spinner in MenuItem. Android support library has SpinnerICS widget and it is used in list navigation mode but they decided to make it internal so we can't use it directly. My solution is to access SpinnerICS widget through reflection.
First create SpinnerICS.java:
package com.example.widget;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
public class SpinnerICS
{
private Spinner spinner = null;
private View spinnerICS = null;
private Method setAdapterICS = null;
private Method setSelectionICS = null;
private Method getAdapterICS = null;
private Method getSelectedItemPositionICS = null;
private Method getSelectedItemICS = null;
private Class<?> OnItemSelectedListenerICS = null;
private Method setOnItemSelectedListenerICS = null;
public SpinnerICS(Context context)
{
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
try {
Class<?> c = Class.forName("android.support.v7.internal.widget.SpinnerICS");
Constructor<?> ctor = c.getDeclaredConstructor(Context.class, AttributeSet.class, int.class);
ctor.setAccessible(true);
setAdapterICS = c.getMethod("setAdapter", SpinnerAdapter.class);
setSelectionICS = c.getMethod("setSelection", int.class);
getAdapterICS = c.getMethod("getAdapter");
getSelectedItemPositionICS = c.getMethod("getSelectedItemPosition");
getSelectedItemICS = c.getMethod("getSelectedItem");
OnItemSelectedListenerICS = Class.forName("android.support.v7.internal.widget.AdapterViewICS$OnItemSelectedListener");
setOnItemSelectedListenerICS = c.getMethod("setOnItemSelectedListener", OnItemSelectedListenerICS);
spinnerICS = (View)ctor.newInstance(context, null, android.support.v7.appcompat.R.attr.actionDropDownStyle);
} catch (Exception e) {
e.printStackTrace();
}
}
if (spinnerICS == null) {
spinner = new Spinner(context);
}
}
public View getView()
{
return (spinnerICS != null ? spinnerICS : spinner);
}
public void setAdapter(SpinnerAdapter adapter)
{
if (spinnerICS != null) {
try {
setAdapterICS.invoke(spinnerICS, adapter);
} catch (Exception e) {
e.printStackTrace();
}
} else if (spinner != null) {
spinner.setAdapter(adapter);
}
}
public void setSelection(int position)
{
if (spinnerICS != null) {
try {
setSelectionICS.invoke(spinnerICS, position);
} catch (Exception e) {
e.printStackTrace();
}
} else if (spinner != null) {
spinner.setSelection(position);
}
}
public SpinnerAdapter getAdapter()
{
if (spinnerICS != null) {
try {
return (SpinnerAdapter)getAdapterICS.invoke(spinnerICS);
} catch (Exception e) {
e.printStackTrace();
}
} else if (spinner != null) {
return spinner.getAdapter();
}
return null;
}
public int getSelectedItemPosition()
{
if (spinnerICS != null) {
try {
return (Integer)getSelectedItemPositionICS.invoke(spinnerICS);
} catch (Exception e) {
e.printStackTrace();
}
} else if (spinner != null) {
return spinner.getSelectedItemPosition();
}
return -1;
}
public Object getSelectedItem()
{
if (spinnerICS != null) {
try {
return getSelectedItemICS.invoke(spinnerICS);
} catch (Exception e) {
e.printStackTrace();
}
} else if (spinner != null) {
return spinner.getSelectedItem();
}
return null;
}
public class OnItemSelectedListenerProxyListener implements java.lang.reflect.InvocationHandler
{
private OnItemSelectedListener listener;
public OnItemSelectedListenerProxyListener(OnItemSelectedListener listener)
{
this.listener = listener;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
if (method.getName().equals("onItemSelected")) {
listener.onItemSelected(null, (View)args[1], (Integer)args[2], (Long)args[3]);
} else if (method.getName().equals("onNothingSelected")) {
listener.onNothingSelected(null);
}
return null;
}
}
public void setOnItemSelectedListener(OnItemSelectedListener listener)
{
if (spinnerICS != null) {
try {
Object obj = Proxy.newProxyInstance(OnItemSelectedListenerICS.getClassLoader(), new Class<?>[] { OnItemSelectedListenerICS } , new OnItemSelectedListenerProxyListener(listener));
setOnItemSelectedListenerICS.invoke(spinnerICS, obj);
} catch (Exception e) {
e.printStackTrace();
}
} else if (spinner != null) {
spinner.setOnItemSelectedListener(listener);
}
}
}
and then use this SpinnerICS like this:
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
String[] items = new String[] { "one", "two", "three" };
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.support.v7.appcompat.R.layout.support_simple_spinner_dropdown_item, items);
adapter.setDropDownViewResource(android.support.v7.appcompat.R.layout.support_simple_spinner_dropdown_item);
SpinnerICS spinner = new SpinnerICS(this);
MenuItem item = menu.add("Sample:");
MenuItemCompat.setActionView(item, spinner.getView());
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
spinner.setAdapter(adapter);
return true;
}
Just adding to the above answer. It works perfectly, but you need to set the context to themed context like below:
Context ctx = getSupportActionBar().getThemedContext();
Otherwise the theme won't match.
The SpinnerICS solution works well as shown but using it is a little different from a normal Spinner.
For example, you cannot do:
In the xml:
<TableRow>
<TextView android:text="@string/textview_abc"
android:layout_width="80sp"
android:gravity="center"
android:inputType="textMultiLine"
/>
<SpinnerICS android:id="@+id/spinner_abc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:prompt="@string/spinner_abc"
/>
</TableRow>
In the java:
SpinnerICS spinner = (SpinnerICS) view.findViewById(R.id.spinner_abc);
It errors like this:
[javac] /home/androidin/build/Project/src/com/example/FragmentTab.java:77: error: inconvertible types
[javac] SpinnerICS spinner = (SpinnerICS) view.findViewById(R.id.spinner_abc);
[javac] ^
[javac] required: SpinnerICS
[javac] found: View