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