1/* 2 * Copyright (C) 2015 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 androidx.appcompat.widget; 18 19 20import android.content.Context; 21import android.content.res.Resources; 22import android.content.res.Resources.Theme; 23import android.view.LayoutInflater; 24import android.view.View; 25import android.view.ViewGroup; 26import android.widget.SpinnerAdapter; 27 28import androidx.annotation.NonNull; 29import androidx.annotation.Nullable; 30import androidx.appcompat.view.ContextThemeWrapper; 31 32/** 33 * An extension of SpinnerAdapter that is capable of inflating drop-down views 34 * against a different theme than normal views. 35 * <p> 36 * Classes that implement this interface should use the theme provided to 37 * {@link #setDropDownViewTheme(Theme)} when creating views in 38 * {@link SpinnerAdapter#getDropDownView(int, View, ViewGroup)}. 39 * 40 * <p>The {@link Helper} class is provided to aide implementation in a backwards compatible way. 41 * </p> 42 */ 43public interface ThemedSpinnerAdapter extends SpinnerAdapter { 44 /** 45 * Sets the {@link Resources.Theme} against which drop-down views are 46 * inflated. 47 * 48 * @param theme the context against which to inflate drop-down views, or 49 * {@code null} to use the default theme 50 * @see SpinnerAdapter#getDropDownView(int, View, ViewGroup) 51 */ 52 void setDropDownViewTheme(@Nullable Resources.Theme theme); 53 54 /** 55 * Returns the value previously set by a call to 56 * {@link #setDropDownViewTheme(Theme)}. 57 * 58 * @return the {@link Resources.Theme} against which drop-down views are 59 * inflated, or {@code null} if one has not been explicitly set 60 */ 61 @Nullable 62 Resources.Theme getDropDownViewTheme(); 63 64 /** 65 * A helper class which allows easy integration of {@link ThemedSpinnerAdapter} into existing 66 * {@link SpinnerAdapter}s in a backwards compatible way. 67 * 68 * <p>An example {@link android.widget.BaseAdapter BaseAdapter} implementation would be:</p> 69 * 70 * <pre> 71 * public class MyAdapter extends BaseAdapter implements ThemedSpinnerAdapter { 72 * private final ThemedSpinnerAdapter.Helper mDropDownHelper; 73 * 74 * public CheeseAdapter(Context context) { 75 * mDropDownHelper = new ThemedSpinnerAdapter.Helper(context); 76 * // ... 77 * } 78 * 79 * @Override 80 * public View getDropDownView(int position, View convertView, ViewGroup parent) { 81 * View view; 82 * 83 * if (convertView == null) { 84 * // Inflate the drop down using the helper's LayoutInflater 85 * LayoutInflater inflater = mDropDownHelper.getDropDownViewInflater(); 86 * view = inflater.inflate(R.layout.my_dropdown, parent, false); 87 * } 88 * 89 * // ... 90 * } 91 * 92 * @Override 93 * public void setDropDownViewTheme(@Nullable Resources.Theme theme) { 94 * // Pass the new theme to the helper 95 * mDropDownHelper.setDropDownViewTheme(theme); 96 * } 97 * 98 * @Override 99 * public Resources.Theme getDropDownViewTheme() { 100 * // Return the helper's value 101 * return mDropDownHelper.getDropDownViewTheme(); 102 * } 103 * } 104 * </pre> 105 */ 106 public final static class Helper { 107 private final Context mContext; 108 private final LayoutInflater mInflater; 109 private LayoutInflater mDropDownInflater; 110 111 public Helper(@NonNull Context context) { 112 mContext = context; 113 mInflater = LayoutInflater.from(context); 114 } 115 116 /** 117 * Should be called from your adapter's 118 * {@link ThemedSpinnerAdapter#setDropDownViewTheme(Theme)} 119 * 120 * @param theme the theme passed in to 121 * {@link ThemedSpinnerAdapter#setDropDownViewTheme(Theme)} 122 */ 123 public void setDropDownViewTheme(@Nullable Resources.Theme theme) { 124 if (theme == null) { 125 mDropDownInflater = null; 126 } else if (theme == mContext.getTheme()) { 127 mDropDownInflater = mInflater; 128 } else { 129 final Context context = new ContextThemeWrapper(mContext, theme); 130 mDropDownInflater = LayoutInflater.from(context); 131 } 132 } 133 134 /** 135 * Should be called from your adapter's {@link ThemedSpinnerAdapter#getDropDownViewTheme()}, 136 * returning the value returned from this method. 137 */ 138 @Nullable 139 public Resources.Theme getDropDownViewTheme() { 140 return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme(); 141 } 142 143 /** 144 * Returns the {@link LayoutInflater} which should be used when inflating any layouts 145 * from your {@link SpinnerAdapter#getDropDownView(int, View, ViewGroup)}. 146 * 147 * <p>The instance returned will have a correct theme, meaning that any inflated views 148 * will be created with the same theme.</p> 149 */ 150 @NonNull 151 public LayoutInflater getDropDownViewInflater() { 152 return mDropDownInflater != null ? mDropDownInflater : mInflater; 153 } 154 } 155} 156