AppCompatSpinner.java revision 351428cd6e15e6d19fe48ce698c994ad3e6f0501
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v7.widget;
18
19import android.annotation.TargetApi;
20import android.content.Context;
21import android.content.res.ColorStateList;
22import android.graphics.PorterDuff;
23import android.graphics.drawable.Drawable;
24import android.os.Build;
25import android.support.annotation.Nullable;
26import android.support.v4.view.TintableBackgroundView;
27import android.support.v7.appcompat.R;
28import android.support.v7.internal.widget.TintInfo;
29import android.support.v7.internal.widget.TintManager;
30import android.support.v7.internal.widget.TintTypedArray;
31import android.util.AttributeSet;
32import android.widget.ListPopupWindow;
33import android.widget.Spinner;
34
35import java.lang.reflect.Field;
36
37/**
38 * A tint aware {@link android.widget.Spinner}.
39 * <p>
40 * This will automatically be used when you use {@link android.widget.Spinner} in your
41 * layouts. You should only need to manually use this class when writing custom views.
42 */
43public class AppCompatSpinner extends Spinner implements TintableBackgroundView {
44
45    private static final int[] TINT_ATTRS = {
46            android.R.attr.background,
47            android.R.attr.popupBackground
48    };
49
50    private TintInfo mBackgroundTint;
51
52    public AppCompatSpinner(Context context) {
53        this(context, null);
54    }
55
56    public AppCompatSpinner(Context context, AttributeSet attrs) {
57        this(context, attrs, R.attr.spinnerStyle);
58    }
59
60    public AppCompatSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
61        super(context, attrs, defStyleAttr);
62
63        if (TintManager.SHOULD_BE_USED) {
64            TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
65                    TINT_ATTRS, defStyleAttr, 0);
66            if (a.hasValue(0)) {
67                ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1));
68                if (tint != null) {
69                    setSupportBackgroundTintList(tint);
70                }
71            }
72            if (a.hasValue(1)) {
73                final Drawable popupBackground = a.getDrawable(1);
74                if (Build.VERSION.SDK_INT >= 16) {
75                    setPopupBackgroundDrawable(popupBackground);
76                } else if (Build.VERSION.SDK_INT >= 11) {
77                    setPopupBackgroundDrawableV11(this, popupBackground);
78                }
79            }
80            a.recycle();
81        }
82    }
83
84    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
85    private static void setPopupBackgroundDrawableV11(Spinner view, Drawable background) {
86        try {
87            Field popupField = Spinner.class.getDeclaredField("mPopup");
88            popupField.setAccessible(true);
89
90            Object popup = popupField.get(view);
91
92            if (popup instanceof ListPopupWindow) {
93                ((ListPopupWindow) popup).setBackgroundDrawable(background);
94            }
95        } catch (NoSuchFieldException e) {
96            e.printStackTrace();
97        } catch (IllegalAccessException e) {
98            e.printStackTrace();
99        }
100    }
101
102    /**
103     * This should be accessed via
104     * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View,
105     * android.content.res.ColorStateList)}
106     *
107     * @hide
108     */
109    @Override
110    public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
111        if (mBackgroundTint == null) {
112            mBackgroundTint = new TintInfo();
113        }
114        mBackgroundTint.mTintList = tint;
115        mBackgroundTint.mHasTintList = true;
116
117        applySupportBackgroundTint();
118    }
119
120    /**
121     * This should be accessed via
122     * {@link android.support.v4.view.ViewCompat#getBackgroundTintList(android.view.View)}
123     *
124     * @hide
125     */
126    @Override
127    @Nullable
128    public ColorStateList getSupportBackgroundTintList() {
129        return mBackgroundTint != null ? mBackgroundTint.mTintList : null;
130    }
131
132    /**
133     * This should be accessed via
134     * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)}
135     *
136     * @hide
137     */
138    @Override
139    public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
140        if (mBackgroundTint == null) {
141            mBackgroundTint = new TintInfo();
142        }
143        mBackgroundTint.mTintMode = tintMode;
144        mBackgroundTint.mHasTintMode = true;
145
146        applySupportBackgroundTint();
147    }
148
149    /**
150     * This should be accessed via
151     * {@link android.support.v4.view.ViewCompat#getBackgroundTintMode(android.view.View)}
152     *
153     * @hide
154     */
155    @Override
156    @Nullable
157    public PorterDuff.Mode getSupportBackgroundTintMode() {
158        return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
159    }
160
161    @Override
162    protected void drawableStateChanged() {
163        super.drawableStateChanged();
164        applySupportBackgroundTint();
165    }
166
167    private void applySupportBackgroundTint() {
168        if (getBackground() != null && mBackgroundTint != null) {
169            TintManager.tintViewBackground(this, mBackgroundTint);
170        }
171    }
172
173}
174