Spinner inner padding is larger on Android 6.0.1
S

2

18

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:

  1. The one on the top is taken on a Nexus 5 device running on Android 6.0
  2. The one below is also taken on a Nexus 5 device BUT running on Android 6.0.1

screenshot

  • EDIT 1

Using AppCompatSpinner from the support library does not change the behaviour. Support library version used is 23.1.1

Serviceberry answered 16/12, 2015 at 15:37 Comment(4)
We had to add more padding around the down caret to avoid a bug when displaying the ripple effect. If you need a constant size, copy the background out of the framework and use that, or use AppCompat.Overgrowth
I do use AppCompat :). Could you tell me what's the exact dimension of that padding? Seems to me like it is around 8 or 10?Serviceberry
It's 12dp of end padding and a constant 48dp end-aligned gap, which is effectively 12dp of start padding. You can check directly in the Android SDK directory under platforms/android-23/data/res/drawable/spinner_background_material.xml.Overgrowth
Thanks for your response, @alanv. I'll take it from here.Serviceberry
S
7

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!

Serviceberry answered 21/12, 2015 at 22:40 Comment(1)
The link for bg_spinner_assets are redirecting to download Backstreet_Boys mp3 file. Can you please look into this? ThanksLeavy
A
4

I had the same issue and my plan was to rollback the 6.0.1 update for v23 only.

  1. Make sure your 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"/>
  1. Create (if already does not exist) 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? :)

  1. Bring in 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.

  1. Changes above will not compile as more files are needed to be brought in for they will be reffered by the files above.

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.

Alysonalysoun answered 4/1, 2016 at 12:3 Comment(2)
Thanks for posting this svennu. You saved me a bunch of time with the helpful explanation!Gerontocracy
On 2nd thought. This doesn't work well on API 24 when trying to hide the caret.Gerontocracy

© 2022 - 2024 — McMap. All rights reserved.