Intro:
With the new release of Android 6.0.1, seems like Android made some changes on the Spinner component because by default, the inner padding around the down carrot is a bit bigger.
I noticed this on an app where I haven't modified anything in the code, but simply updated the OS on the device and yet the spinners have different sizes.
Situation:
I have 2 spinners one next to the other in a RelativeLayout
(mind the rest of the components, I added everything so you can see this part of the layout - removed the totally unnecessary properties or view ids)
<RelativeLayout
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/container_for_buttons_on_the_right"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true">
<!-- Buttons here-->
</LinearLayout>
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/spinner_1"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<ViewSwitcher
android:id="@+id/spinner_switch"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_toEndOf="@id/spinner_1"
android:layout_toLeftOf="@id/container_for_buttons_on_the_right"
android:layout_toRightOf="@id/spinner_1"
android:layout_toStartOf="@id/container_for_buttons_on_the_right"
android:inAnimation="@anim/fade_in"
android:outAnimation="@anim/fade_out">
<android.support.v7.widget.AppCompatSpinner
android:layout_width="wrap_content"
android:layout_height="match_parent" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!-- ImageView properties are incomplete but I need it there.-->
</ViewSwitcher>
</RelativeLayout>
The layout used by the Spinner adapter for the getView()
method is this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:paddingLeft="8dp"
android:paddingRight="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="center_vertical"
android:singleLine="true"
tools:text="Test" />
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0"
android:gravity="center"
android:paddingLeft="4dp"
android:singleLine="true"
android:textColor="@color/text_primary"
android:textSize="@dimen/text_size_body"
tools:ignore="RtlHardcoded,RtlSymmetry"
tools:text="7%" />
</LinearLayout>
Exemplified:
The screenshot is combined of 2 separate screenshots taken:
Using AppCompatSpinner from the support library does not change the behaviour. Support library version used is 23.1.1
With minimal effort I was able to fix this by building a custom background for the spinner.
Using AppCompatSpinner
I had to create 2 xmls for the background, let's call this spinner_background.xml
:
1. First one goes to the drawable
folder and looks like this, spinner_background.xml
:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:opacity="transparent">
<item
android:width="24dp"
android:height="24dp"
android:drawable="@drawable/selector_background_borderless"
android:gravity="end|center_vertical" />
<item android:drawable="@drawable/bg_spinner_anchor" />
</layer-list>
Where selector_background_borderless
is a plain selector like(I added the minimal items you need, you could explore it's ripple alternative for v21+. In fact I would recommend you to do so):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#19000000" android:state_pressed="true" />
<item android:drawable="@android:color/transparent" />
</selector>
And bg_spinner_anchor
is a 9patch PNG for the caret. I used these assets: bg_spinner_anchor
2. The second one goes to the drawable-v23
folder to properly support ripple and looks like this, spinner_background.xml
:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingEnd="16dp"
android:paddingLeft="0dp"
android:paddingMode="stack"
android:paddingRight="0dp"
android:paddingStart="0dp">
<item
android:width="24dp"
android:height="24dp"
android:drawable="@drawable/selector_background_borderless"
android:gravity="end|center_vertical" />
<item
android:width="24dp"
android:height="24dp"
android:drawable="@drawable/ic_spinner_caret"
android:gravity="end|center_vertical" />
</layer-list>
Where ic_spinner_caret
is a vector used from the Android source code looking like this. You should add also add this to your drawable-v23
folder:
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:pathData="M7,10l5,5,5-5z"
android:fillColor="#524e4a"/>
</vector>
Credits go to alanv from the Android UI toolkit for Guidance!
I had the same issue and my plan was to rollback the 6.0.1 update for v23 only.
Spinner
has a style attached to it. For example style named as Widget.Spinner
in example below:<Spinner
android:id="@+id/spinner_1"
style="@style/Widget.Spinner"
android:layout_width="64dp"
android:layout_height="64dp"/>
styles.xml
under values-v23
directory (for changes will be applied to API v23 only). For example, see Widget.Spinner
style definition example below:<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Widget.Spinner" parent="Widget.AppCompat.Spinner">
<item name="android:background">@drawable/spinner_background_material</item>
</style>
</resources>
The style's parent is Widget.AppCompat.Spinner
and it redefines it's android:background
with the one we will be rolling back from 6.0.1 source.
Note, that if you're targeting other versions too, you will need to add a default styles.xml
under values
directory with entry
<style name="Widget.Spinner" parent="Widget.AppCompat.Spinner"/>
for it is easier to define another generic style rather than different layout xml files and your project should have a generic styles.xml
under values
directory anyway, right? :)
spinner_background_material.xml
from https://android.googlesource.com/platform/frameworks/base.git/+/android-6.0.1_r3/core/res/res/drawable/. Save it under drawable-v23
for again, we will just make sure we're changing API v23 only.File's default content is:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingMode="stack"
android:paddingStart="0dp"
android:paddingEnd="48dp"
android:paddingLeft="0dp"
android:paddingRight="0dp">
<item
android:gravity="end|fill_vertical"
android:width="48dp"
android:drawable="@drawable/control_background_40dp_material" />
<item
android:drawable="@drawable/ic_spinner_caret"
android:gravity="end|center_vertical"
android:width="24dp"
android:height="24dp"
android:end="12dp" />
</layer-list>
Now, this is the file you might want to tweak. I made changes to this file for tweaking the caret position:
a) set layer-list
's android:paddingEnd
equal to 0dp
b) halved first item's android:width
to 24dp
c) removed the second item's android:end
attribute
The changes made background thinner, by stripping it's sides but the approach retained the ripple effects. Feel free to play around with your own custom values, if needed.
Download into drawable-v23
(see link above):
a) control_background_40dp_material.xml
b) ic_spinner_caret.xml
Download into color-v23
:
a) control_highlight_material.xml
from https://android.googlesource.com/platform/frameworks/base.git/+/android-6.0.1_r3/core/res/res/color/ (this file can probably reside under drawable-v23
too, but lets follow the pattern of original source locations for now). Note, that file's @dimen/highlight_alpha_material_colored
is picked up from appcompat-v7
, if you use one :) If not, you can reffer it's value from it:
<item format="float" name="highlight_alpha_material_colored" type="dimen">0.26</item>
The solution is not the best as you need to bring over files you don't originally own. Also, you might want to monitor the possible updates to v23 for any future changes. But at least the changes are contained to v23 only.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With