How can I fix the Spinner style for Android 4.x placed on top of the Toolbar
Asked Answered
B

15

49

According to Android documentation, Material Design style is supported for Spinner widget.

So I decided to use it in my app placing it on top of the Toolbar.

layout/activity_base.xml

<android.support.v7.widget.Toolbar
    android:id="@+id/my_awesome_toolbar"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    android:elevation="5dp"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
    <Spinner
        android:id="@+id/spinner"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
 </android.support.v7.widget.Toolbar>

Activity theme

<style name="BaseAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/omni_primary_color</item>
    <item name="colorPrimaryDark">@color/omni_primary_color_dark</item>
    <item name="colorAccent">@color/omni_accent_color</item>
</style>

BaseActivity.java

public class BaseActivity extends ActionBarActivity {

    @InjectView(R.id.my_awesome_toolbar)
    Toolbar mToolbar;

    @InjectView(R.id.spinner)
    Spinner spinner;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base);
        ButterKnife.inject(this);
        //setup toolbar
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(false);
        mToolbar.setNavigationIcon(R.drawable.ic_action_navigation_menu);
          
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mToolbar.getContext(),
                R.array.planets_array, R.layout.support_simple_spinner_dropdown_item);
        adapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
    }
}

On Lollipop spinner and dropdown looks fine, although dropdown background color is black comparing to menu dropdown which is white. I guess that app:popupTheme="@style/ThemeOverlay.AppCompat.Light" is not propagated to the spinner.

Android 5.0

enter image description here enter image description here

Now the big problem is with Android 4.x where dropdown background color is white(popupTheme propagated?) and icon next to the spinner is black.

Android 4.4

enter image description here

How can I set it properly in the XML or implement in the code to make it work on both Android 5 and 4? Ideally, I would like to have both looks like on Android 5 but with white spinner dropdown(like Setting menu dropdown).

Update

I have noticed that setting property colorControlNormal affects spinner's filter icon. If someone finds out how to make use of that for Spinner(without changing other content controls), then I would have my solution combining that finding with @Sven answer.

Update

The following change fixes the problem for spinner text and popup color. So the only problem to the final solution is the filter icon.

ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getSupportActionBar().getThemedContext(),
                R.array.planets_array, R.layout.support_simple_spinner_dropdown_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

Update

I found that filter icon is actually a part of android:background specified for the spinner and it's transparent. Providing own background would fix it e.g.

<item name="android:background">?android:selectableItemBackground</item>

Mystery solved!

The last piece of the puzzle is the popup on Android 5 that has black background and white text but I guess it can be solved with custom layout. If no one provides full answer I will do it myself and mark as accepted.

Brinker answered 5/11, 2014 at 11:16 Comment(8)
try to use getSupportActionBar().getThemedContext() instead mToolbar.getContext()Actinopod
@Actinopod I have tried that already. It looks exactly the sameBrinker
for the spinner icon, this may help.Rhianna
@Loop I was struggling with the same thing, and found out that updating AppCompat from 21.0.0 to 21.0.2 fixed spinner's filter icon color. I solved other issues by using custom layouts.Brigettebrigg
How did you get this to compile on anything lower with sdk lower than 21? I tried using toolbar and eclipse required minsdk to be 21, once I set that it won't compile on anything but 21. Can you post your manifest?Optimism
How can I also allow for tabs to be compatible with android 4 and 5?Optimism
Hi, Still facing the same issue, though I have followed all your instructions. Even I removed filter icon, I am getting only black background.Perjured
see this similar question #26852608Assurance
X
65

I know this is late but I came accross this question when I encountered this problem myself and I found a solution in the BrowseSessionsActivity of the Google I/O 2014 app and adapted it.

Layouts

toolbar_spinner.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Spinner
        android:id="@+id/toolbar_spinner"
        style="@style/Widget.MyApp.HeaderBar.Spinner"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"/>

</LinearLayout>

toolbar_spinner_item_actionbar.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@android:id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawablePadding="8dp"
        android:drawableRight="@drawable/spinner_triangle"
        android:fontFamily="sans-serif"
        android:paddingLeft="16dp"
        android:paddingRight="4dp"
        android:textColor="#ffffffff"
        android:textSize="18dp"
        android:textStyle="bold"/>

</LinearLayout>

The spinner_triangle drawable can be found here.

toolbar_spinner_item_dropdown.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@android:id/text1"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:drawablePadding="8dp"
        android:gravity="center_vertical|start"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:textColor="#ff333333"
        android:textSize="16sp"/>
        
</LinearLayout>

Styles

toolbar_spinner.xml uses the following style.

<style name="Widget.MyApp.HeaderBar.Spinner" parent="Widget.AppCompat.Light.Spinner.DropDown.ActionBar">
        <item name="android:background">?android:selectableItemBackground</item>
        <item name="android:dropDownSelector">?android:selectableItemBackground</item>
        <item name="android:divider">@null</item>
        <item name="android:overlapAnchor">true</item>
</style>

Adapter

This adapter will need to be changed to match your own needs. getTitle() returns the text for each item shown in the spinner.

private class YourObjectSpinnerAdapter extends BaseAdapter {
    private List<YourObject> mItems = new ArrayList<>();

    public void clear() {
        mItems.clear();
    }

    public void addItem(YourObject yourObject) {
        mItems.add(yourObject);
    }

    public void addItems(List<YourObject> yourObjectList) {
        mItems.addAll(yourObjectList);
    }

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

    @Override
    public Object getItem(int position) {
        return mItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getDropDownView(int position, View view, ViewGroup parent) {
        if (view == null || !view.getTag().toString().equals("DROPDOWN")) {
            view = getLayoutInflater().inflate(R.layout.toolbar_spinner_item_dropdown, parent, false);
            view.setTag("DROPDOWN");
        }

        TextView textView = (TextView) view.findViewById(android.R.id.text1);
        textView.setText(getTitle(position));

        return view;
    }

    @Override
    public View getView(int position, View view, ViewGroup parent) {
        if (view == null || !view.getTag().toString().equals("NON_DROPDOWN")) {
            view = getLayoutInflater().inflate(R.layout.
                    toolbar_spinner_item_actionbar, parent, false);
            view.setTag("NON_DROPDOWN");
        }
        TextView textView = (TextView) view.findViewById(android.R.id.text1);
        textView.setText(getTitle(position));
        return view;
    }

    private String getTitle(int position) {
        return position >= 0 && position < mItems.size() ? mItems.get(position).title : "";
    }
}

Adding the Spinner to Your Toolbar

Toolbar toolbar = getActionBarToolbar();

View spinnerContainer = LayoutInflater.from(this).inflate(R.layout.toolbar_spinner,
        toolbar, false);
ActionBar.LayoutParams lp = new ActionBar.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
toolbar.addView(spinnerContainer, lp);

YourObjectSpinnerAdapter spinnerAdapter = new YourObjectSpinnerAdapter();
spinnerAdapter.addItems(getMyObjectSpinnerData());

Spinner spinner = (Spinner) spinnerContainer.findViewById(R.id.toolbar_spinner);
spinner.setAdapter(spinnerAdapter);

Result

Material Spinner

KitKat Spinner

Xyloid answered 2/1, 2015 at 19:52 Comment(12)
It is not to late :). I would like to add that toolbar_spinner.xml is not neccesary. You can put <Spinner /> inside <Toolbar />. That way you dont need container inflation and additional traingle drawable. Spinner will use default drawable.Galangal
getLayoutInflater() doesn't seem to be recognized, how do you get a LayoutIinflater in the BaseAdapter?Platelet
I think this fails on Gingerbread with: ... Caused by: android.content.res.Resources$NotFoundException: Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x101030e a=2} and 0x101030e seems to be developer.android.com/reference/android/… - removing the usage of ?android:selectableItemBackground in styles.xml produces some UI problems though.Bes
That doesn't work well on lolipop. The backround there is dark :/Monocot
It's better to use ?attr/selectableItemBackground instead of ?android:selectableItemBackground, so the selected state doesn't blue on pre-kitkat devices.Tuatara
@Xylian: Add android:theme="@style/ThemeOverlay.AppCompat.Light" to your spinner component, that fixed it for me. I've edited the answer reflecting my last two comments.Tuatara
anybody knows about how to disable spinner for particular fragment? on onDetach() I have used spinner.setVisibility(View.INVISIBLE); works fine but fragment restarts in NavigationDrawer spinner.setVisibility(View.VISIBLE); is not working !! Failed re enable spinner which is injected to Toolbar !! any solutions? FYI I'm trying enable disable spinner on toolbar in different layout in Navigation drawer!Wiener
I got this error, android:overlapanchor requires api 21 (current min is 15). Is that really true? It only works when min api is 21 and above?Observatory
@RockLee The app will still compile and that will only be used on API 21, you can leave it as it is, or make a different layout-v21 if you want to get rid of the error.Xyloid
While using in NavigationDrawer i made this by inflating the spinner view in DrawerActivity and set as public static Spinner spinner; to reference to other fragments. To clear the spinner or disable you need to remove the toolbar in your specific fragment, attach a new new toolbar. that's itGotcher
The answer divine and Immaculate! Thanks a lot! I am becoming more understood when it comes to material design. I thought they were just a bunch of widgets but it turns out those are guides on how to make it look like so using the existing widgets. I just really find that too cumbersome and hoped that they just added it as xml elements and be done with it. For example, I ended up writing my own custom layout for the divider with subheader. I am afraid with all these questions, soon, I may have to implement it similarly to other non-lollipop looking widgets.Roose
The spinner_triangle drawable link is broken. Would you mind updating that part?Neusatz
S
7

Don't implement Spinner in Xml

final ArrayAdapter spinnerAdapter = ArrayAdapter.createFromResource(getSupportActionBar().getThemedContext(),
            R.array.main_navigation_list, R.layout.spinner_text);
    spinnerAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
    mNavigationTags = getResources().getStringArray(R.array.main_navigation_list);


    mNavigationSpinner = new Spinner(getSupportActionBar().getThemedContext());
    mNavigationSpinner.setAdapter(spinnerAdapter);

    mNavigationSpinner.setOnItemSelectedListener(this);
    mToolbar.addView(mNavigationSpinner);

This way the icon next to spinner will be white

Sur answered 5/12, 2014 at 6:40 Comment(1)
THIS is the Way to go!Godman
D
6

Sorry for my poor English. :) I think it is better to directly create the spinner in Toolbar.

Here is a example in my fragment.

public class Testfragment1 extends Fragment {

    Toolbar mToolbar;
    Spinner mSpinner;
    .....

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
        .......                  
        mToolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
        //you can also set the style with the constructor
        mSpinner = new Spinner(getActivity());
        String[] frags = new String[]{
                "category1",
                "category2",
                "category3",
        };
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1,frags);
        mSpinner.setAdapter(arrayAdapter);
        mToolbar.addView(mSpinner);
        return inflater.inflate(R.layout.fragment_testfragment1, container, false);
    }

    .........

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (mToolbar != null && mSpinner != null) {
            mToolbar.removeView(mSpinner);
        }
    }
}

It looks fine on my android-4.1-device: android-4.1-spinner

Doityourself answered 9/11, 2014 at 13:14 Comment(8)
Thanks for your answer, I will give it a try. However, I believe that using internal widget implementations is not a good idea since it may be changed in appcompat without further notice. Additionally, in full solution I expect spinner popup to look like the one from Settins(white background with white text)Brinker
How did you get this to compile on Android 4.1? When using ToolBar it forces me to set the minSDK to 21 and therefore won't compile on anything lowerOptimism
TintSpinner is an internal widget and is going to change. The idea is to have internal widgets released as public ones, thus the API will suffer several modifications (For example, TintSpinner will be called simply Spinner). Please, avoid using this method at all costs unless you plan to stick with your current AppCompat library version and all it's bugs.Ibo
These classes don't exist in appcompat v22.2Wiener
Once you did this mToolbar.removeView(mSpinner); are you able to view it again on Toolbar? (when using in fragment of navigation drawer)Wiener
@Wiener It is designed for navigation drawer, you won't see the spinner when you changed it to another fragment.Doityourself
@Doityourself yes !! but failed make visible again when same fragment is clicked again, I have injected the spinner layout to Toolbar toolbar.addView(spinnerContainer, lp); (Ref Daniel B Ans) in this case it doesn't works , post you the github code link very soon, ThanksWiener
@Wiener oh.... Here is the sample code, good luck.Doityourself
P
3

I am struggling with the exact same problem.

Try to change the dropdown view resource. At least, this fixed the text color issue for me - however the arrow icon color is still dark. So this is just a partial workaround.

setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Parament answered 5/11, 2014 at 13:53 Comment(2)
I already tried that with half-way success. Anyway, I am looking for full solution. I actually have an idea to try. I will post it here if it works.Brinker
I found that setting 'colorControlNormal' change filter icon to that color. However, it also changes other controls in the app content. So the challenge now is to apply that property to the spinner on the toolbar. Applying that property to Toolbar style do nothing.Brinker
P
3

A simple way that isn't perfect, but uniform enough for both 4.x and 5.0

img

I removed the <Spinner> from the layout files and added it programmatically - that allowed for the white triangle to show up properly.

I also created a dropdown item layout using the appcompat required color.

layout/spinner_dropdown_item.xml, note the android:background="@color/primaryColor"

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@android:id/text1"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textAppearance="?android:attr/textAppearanceListItemSmall"
      android:gravity="center_vertical"
      android:paddingLeft="12dp"
      android:paddingRight="12dp"
      android:background="@color/primaryColor"
      android:minHeight="?android:attr/listPreferredItemHeightSmall" />

And in the activity:

    SpinnerAdapter spinnerAdapter = ArrayAdapter.createFromResource(getApplicationContext(), R.array.your_array, R.layout.spinner_dropdown_item);
    Spinner navigationSpinner = new Spinner(getSupportActionBar().getThemedContext());
    navigationSpinner.setAdapter(spinnerAdapter);
    toolbar.addView(navigationSpinner, 0);

It's not perfect and the items don't highlight when you click on them, but it's good enough while we wait for the future appcompat libraries to fix these problems (here's hoping anyway).

Platelet answered 1/3, 2015 at 13:8 Comment(0)
A
3

I spent two days on this problem, but now after reading many answers, I can post my solution. I've implemented two custom layouts for the spinner item and popup. Setting this attribute for spinner: android:background="?android:selectableItemBackground" the default spinner black arrow is hidden and we can use what we prefer. I used the method setDropDownVerticalOffset(int) to manage the popup position on pre Lollipop Android versions.

My app global theme is

<style name="AppTheme" parent="AppTheme.Base">

</style>

<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/primary</item>
    <item name="colorPrimaryDark">@color/primary_dark</item>
    <item name="colorAccent">@color/accent</item>
    <item name="android:windowBackground">@color/window_background</item>
</style>

Now, the activity layout that contains the toolbar and the spinner:

activity_main.xml

<RelativeLayout
    android:layout_width="match_parent" 
    android:layout_height="match_parent"

    android:clickable="true" >

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:elevation="4dp"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" >

            <Spinner 
                android:id="@+id/spinner_rss"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:theme="@style/ThemeOverlay.AppCompat.Light"
                android:background="?android:selectableItemBackground" />

         </android.support.v7.widget.Toolbar>
</RelativeLayout>

custom_spinner_toolbar.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

<TextView
    android:id="@+id/spinner_item_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:singleLine="true"
    android:textColor="@android:color/white"
    android:textAppearance="@style/TextAppearance.AppCompat.Title"
     />

<ImageView
    android:contentDescription="@string/content_description_arrow_dropdown"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toRightOf="@+id/spinner_item_text"
    android:layout_toEndOf="@+id/spinner_item_text"
    android:paddingTop="6dp"
    android:src="@drawable/ic_arrow_drop_down_white_24dp" />

</RelativeLayout>

custom_spinner_dropdown_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <CheckedTextView
        android:id="@+id/spinner_item_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:singleLine="true"
        android:textColor="@android:color/black"
        android:textSize="16sp" />

</LinearLayout>

SpinnerAdapter.java

public class SpinnerAdapter extends BaseAdapter
{
   private Context mContext;
   private List<String> mValuesList;

   public SpinnerAdapter(Context mContext, List<String> mValuesList)
   {
       this.mContext = mContext;
       this.mValuesList = mValuesList;
   }

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

   @Override
   public Object getItem(int position) 
   {
       return mValuesList.get(position);
   }

   @Override
   public long getItemId(int position) {
       // TODO Auto-generated method stub
       return 0;
   }

   @Override
   public View getDropDownView(int position, View view, ViewGroup parent) 
   {
      if (view == null || !view.getTag().toString().equals("DROPDOWN")) 
      {
         LayoutInflater inflater = LayoutInflater.from(mContext);
         view = inflater.inflate(R.layout.custom_spinner_dropdown_item, parent, false);
         view.setTag("DROPDOWN");
      }

      TextView textView = (TextView) view.findViewById(R.id.spinner_item_text);
      textView.setText(getTitle(position));

      return view;
  }

  @Override
  public View getView(int position, View view, ViewGroup parent) 
  { 
      if (view == null || !view.getTag().toString().equals("NON_DROPDOWN")) 
      {
         LayoutInflater inflater = LayoutInflater.from(mContext);
         view = inflater.inflate(R.layout.custom_spinner_toolbar, parent, false);
         view.setTag("NON_DROPDOWN");
      }

      TextView textView = (TextView) view.findViewById(R.id.spinner_item_text);
      textView.setText(getTitle(position));
      return view;
   }

   private String getTitle(int position) 
   {
      return position >= 0 && position < mValuesList.size() ?   mValuesList.get(position) : "";
   }
}

Finally, the relevant part of activity source code:

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mToolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(mToolbar);

    final ActionBar actionBar = getSupportActionBar();
    actionBar.setDisplayShowTitleEnabled(false);
    actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
    actionBar.setDisplayHomeAsUpEnabled(true);

    mSpinner = (Spinner) findViewById(R.id.spinner_rss);

    String[] items = getResources().getStringArray(R.array.spinner_rss_items);
    List<String> spinnerItems = new ArrayList<String>();

    for(int i = 0; i < items.length; i++)
    {
        spinnerItems.add(items[i]);
    }

    SpinnerAdapter adapter = new SpinnerAdapter(actionBar.getThemedContext(), spinnerItems);
    mSpinner.setAdapter(adapter);

    if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
    {
        mSpinner.setDropDownVerticalOffset(-116);
    }
}

These are the results on Lollipop and Kitkat:

enter image description here enter image description here enter image description here

Hope it helps! :)

Abusive answered 25/6, 2015 at 14:47 Comment(0)
P
2

Use android:dropDownVerticalOffset property inside spinner to give spacing from top.

<Spinner
        android:id="@+id/spnrLanguage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:background="@drawable/ic_dropdown"
        android:padding="5dp"
        android:spinnerMode="dropdown"
        android:dropDownVerticalOffset="50dp"
        />

Don't forgot to set android:spinnerMode="dropdown" though it won't work in spinnerMode= dialog

Perice answered 22/12, 2015 at 11:27 Comment(0)
B
1

Can you not do this?

Custom xml file for spinner item: your_spinner.xml:

<?xml version="1.0" encoding="utf-8"?>
<TextView  
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:textColor="#000"         
    android:background="#FFF"
    />

Use this to show spinner items:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.your_spinner,list);

Then remove drop down resource.

Bernardabernardi answered 12/11, 2014 at 21:9 Comment(1)
It's not working as I expect. It just changes text part and looks terribly bad. The look could be tweaked but filter icon remains unchanged.Brinker
O
1

Had the exact same issue with the spinner's

What i did was to add a custom theme to spinner

 <Spinner
                android:id="@+id/spinner1"
                android:layout_width="match_parent"
                android:layout_height="30sp"
                android:entries="@array/guest_type"
                android:prompt="@string/guesttype"
                android:theme="@style/AppTheme1"   />

styles.xml

  <style name="AppTheme1" parent="Theme.AppCompat.Light">
    <item name="android:spinnerDropDownItemStyle">@style/mySpinnerItemStyle</item>
</style>

<style name="mySpinnerItemStyle" parent="@android:style/Widget.Holo.DropDownItem.Spinner">
    <item name="android:textColor">#000000</item>
</style>
Odo answered 8/12, 2014 at 10:36 Comment(1)
sp is for text size, so => android:layout_height="30dp" or better android:layout_height="@dimen/my_size"Variegation
G
0

For correct Spinner icon tinting you can also just inflate the spinner from code:

spinner_toolbar.xml:

<?xml version="1.0" encoding="utf-8"?>
<Spinner xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/spinner_toolbar"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"/>

Then you have to attach the Spinner to the Toolbar in your Activity:

ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getSupportActionBar().getThemedContext(),
            R.array.planets_array, R.layout.support_simple_spinner_dropdown_item);
adapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item);
spinner.setAdapter(adapter);

// we inflate the spinner with the themed Toolbar context -> correct icon tinting
LayoutInflater.from(getSupportActionBar().getThemedContext()).inflate(R.layout.spinner_toolbar, tb, true);

Spinner spinner = (Spinner) toolbar.findViewById(R.id.spinner_toolbar);
spinner.setAdapter(adapter);

However, this uses the app:theme instead of the app:popupTheme for the whole Spinner, including the dropdown menu. Hence, the Spinner icon and text will be colored correctly, but the dropdown menu also has the style of the toolbar and not of the popupTheme.

So if you want to have a dark Toolbar and a light dropdown menu, you would need to fix the dropdown style somehow, for example by creating a custom style for the spinner that specifies a white background and a custom dropdown view with a dark text color.

Maybe somebody else has a better solution on how the app:popupTheme can be propagated to the Spinner dropdown menu.

Gerundive answered 27/11, 2014 at 18:27 Comment(0)
P
0

You can fix dropdown position (will show on the top of toolbar, like menu) for Android 4 using this code:

<Spinner
        android:id="@+id/spinner"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:dropDownVerticalOffset="-56dp"/>
Perilymph answered 27/11, 2014 at 22:21 Comment(0)
H
0

To pick up on this, I was having similar problems. My main problem was the text in my toolbar was smaller than the usual title dimensions and the wrong colour. Screenshot here http://s27.postimg.org/v24x1aw43/Screen_Shot_2015_01_11_at_13_36_04.png

The dropdown menu was ok, but I will go through the customisation of that as well.

Let me also make clear this fix is mostly based on @Daniel B's fix, however does not require the custom adapter, as far as I can tell nothing is broken, but I give no guarantees!

  1. Add a normal spinner item into the XML layout file (within the toolbar).
<android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:elevation="5dp"
        android:minHeight="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        app:theme="@style/GalaxyZooThemeToolbarDarkOverflow"
        app:popupTheme="@style/Theme.AppCompat"
        >

    <Spinner
        android:id="@+id/spinner_nav"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>


    </android.support.v7.widget.Toolbar>
  1. Create new layout file toolbar_spinner_item_actionbar.xml (This will be the stuff showing for the spinner in the toolbar)
<?xml version="1.0" encoding="utf-8"?>

<TextView
    android:id="@android:id/text1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:drawablePadding="20dp"
    android:fontFamily="sans-serif"
    android:paddingLeft="@dimen/abc_action_bar_default_padding_material"
    android:paddingRight="4dp"
    android:textColor="@color/colorDark"
    android:textSize="@dimen/abc_text_size_title_material_toolbar"
    xmlns:android="http://schemas.android.com/apk/res/android"/>

    <!-- android:drawableRight="@drawable/spinner_triangle" -->
  1. The adapter for your spinner remains pretty much the same, however switch the layout from the standard android.R.layout.simple_spinner_dropdown_item to R.layout.toolbar_spinner_item_actionbar. This will apply your custom look for the toolbar text.

In this example I have set the adapter.setDropDownViewResource to android.R.layout.simple_spinner_dropdown_item, this applies the standard theme defaults for the drop down list, which I am happy with.

ArrayAdapter<String> set1Adapter = new ArrayAdapter<String>(RoutineDetailsActivity.this, R.layout.toolbar_spinner_item_actionbar, set1Actual);
        set1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        mWeekSpinner.setAdapter(set1Adapter);

That's basically it, result here [can't attach image or add another link as my rep is too low! Will add in comment] . You could stop here, however you may want to change the colour of the dropdown arrow.

Technically it is the correct tinting for my app, however, as my primary colour is already the colour for the toolbar, it would make sense to customise the arrow.

Setup custom arrow drawable

  1. Add this line drawable line 'android:drawableRight="@drawable/spinner_triangle' into the toolbar_spinner_item_actionbar.xml made earlier. Now this could be any image, for now you could use Daniel B's white arrow resource here https://raw.githubusercontent.com/google/iosched/master/android/src/main/res/drawable-xxhdpi/spinner_triangle.png.

Running this will result in two arrows, the white arrow and the theme default. To solve this add the style below. Again this is pulled from Daniel B's code and could probably be abridged, but for now it works....

    <style name="Widget.MyApp.HeaderBar.Spinner" parent="Widget.AppCompat.Light.Spinner.DropDown.ActionBar">
        <item name="android:background">?android:selectableItemBackground</item>
        <item name="android:dropDownSelector">?android:selectableItemBackground</item>
        <item name="android:divider">@null</item>
        <item name="android:overlapAnchor">true</item>
    </style>
  1. Apply the created style to the spinner...
<android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:elevation="5dp"
        android:minHeight="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        app:theme="@style/GalaxyZooThemeToolbarDarkOverflow"
        app:popupTheme="@style/Theme.AppCompat"
        >

    <Spinner
        android:id="@+id/spinner_nav"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@style/Widget.MyApp.HeaderBar.Spinner"/>


    </android.support.v7.widget.Toolbar>

The result will be something like this [again can't attach or link, will add to comment]. The padding can be set from the file setup earlier, in my case I would need to change the arrow to match the icons.

Hope that makes some sort of sense.

Hufford answered 11/1, 2015 at 14:35 Comment(1)
Image 2 - s27.postimg.org/vhg6ubi1f/… Image 3 - s27.postimg.org/h9qi5o5cj/…Hufford
K
0

When i used spinner it crashed (Android 2.3.3 - 2.3.7).

So i try to use TintSpinner now it's not crashing, Try your self as a Optional solution

 <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.v7.internal.widget.TintSpinner
            android:id="@+id/toolbar_spinner"
            style="@style/HeaderBar.Spinner"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"/>
    </LinearLayout>

And use below code to cast your toolbar

 View spinnerContainer = LayoutInflater.from(this).inflate(R.layout.toolbar_spinner, toolbarTop, false);
        ActionBar.LayoutParams lp = new ActionBar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
        toolbarTop.addView(spinnerContainer, lp);

        ToolBarSpinnerAdapter spinnerAdapter = new ToolBarSpinnerAdapter(getLayoutInflater());
        String[] items = getResources().getStringArray(R.array.action_dropdown);
        spinnerAdapter.addItems(items);

        TintSpinner mNavigationSpinner = (TintSpinner) spinnerContainer.findViewById(R.id.toolbar_spinner);
        mNavigationSpinner.setAdapter(spinnerAdapter);
Kashgar answered 5/2, 2015 at 14:37 Comment(2)
I discourage anyone using this approach. TintSpinner is an internal widget and its going to change pretty soon. The idea is to have internal widgets released as public ones, thus the API will suffer several modifications (For example, TintSpinner will be called simply Spinner). Please, avoid using this method at all costs unless you plan to stick with your current AppCompat library version and all it's bugsIbo
@Ibo , Thanks for your explained answer but when i am using Spinner my application crashed in (Android 2.3.3 - 2.3.7). But when i used TintSpinner it's not crashing in (Android 2.3.3 - 2.3.7). Still i didn't understand why its happening , here i just try to give an optional solution.Kashgar
L
0

I've wasted hours on this issue. As far as I can tell, the above solutions all require copy/pasting large chunks of appcompat style code to reimplement basic details like touch states.

A relatively easy way to get native-like behaviour is to inflate the view programmatically to ensure it gets the correct theme, e.g.:

// Activity has context with 'Theme.AppCompat.Light.NoActionBar'
spinner = new AppCompatSpinner(getActivity());
toolbar.addView(spinner);

To get the triangle to be white rather than colorControlNormal, I've applied a ColorStateList tint to the background:

ViewCompat.setBackgroundTintList(spinner, resources.getColorStateList(R.drawable.bg_toolbar_spinner)

bg_toolbar_spinner.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/accent" android:state_pressed="true"/>
    <item android:color="@android:color/white"/>
</selector>
Linda answered 17/7, 2015 at 10:2 Comment(0)
D
0

I solved it by creating new values for version 21 and 23 and adding new attribute in the spinner style android:dropDownVerticalOffset and delete it from the default style file. (my case is not related to toolbar) it's for normal spinner.

Add this style in folders 23 and 21

<style name="spinner_style">
    <item name="android:background">@drawable/background_spinner</item>
    <item name="android:dropDownVerticalOffset">30dip</item>
</style>

It's working perfectly on all versions. Hope this works with you!

Doublehung answered 27/3, 2016 at 7:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.