• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.widget;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.icu.util.Calendar;
22 import android.util.AttributeSet;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.view.accessibility.AccessibilityEvent;
27 
28 import com.android.internal.R;
29 
30 /**
31  * Displays a selectable list of years.
32  */
33 class YearPickerView extends ListView {
34     private final YearAdapter mAdapter;
35     private final int mViewSize;
36     private final int mChildSize;
37 
38     private OnYearSelectedListener mOnYearSelectedListener;
39 
YearPickerView(Context context, AttributeSet attrs)40     public YearPickerView(Context context, AttributeSet attrs) {
41         this(context, attrs, R.attr.listViewStyle);
42     }
43 
YearPickerView(Context context, AttributeSet attrs, int defStyleAttr)44     public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
45         this(context, attrs, defStyleAttr, 0);
46     }
47 
YearPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)48     public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
49         super(context, attrs, defStyleAttr, defStyleRes);
50 
51         final LayoutParams frame = new LayoutParams(
52                 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
53         setLayoutParams(frame);
54 
55         final Resources res = context.getResources();
56         mViewSize = res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height);
57         mChildSize = res.getDimensionPixelOffset(R.dimen.datepicker_year_label_height);
58 
59         setOnItemClickListener(new OnItemClickListener() {
60             @Override
61             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
62                 final int year = mAdapter.getYearForPosition(position);
63                 mAdapter.setSelection(year);
64 
65                 if (mOnYearSelectedListener != null) {
66                     mOnYearSelectedListener.onYearChanged(YearPickerView.this, year);
67                 }
68             }
69         });
70 
71         mAdapter = new YearAdapter(getContext());
72         setAdapter(mAdapter);
73     }
74 
setOnYearSelectedListener(OnYearSelectedListener listener)75     public void setOnYearSelectedListener(OnYearSelectedListener listener) {
76         mOnYearSelectedListener = listener;
77     }
78 
79     /**
80      * Sets the currently selected year. Jumps immediately to the new year.
81      *
82      * @param year the target year
83      */
setYear(final int year)84     public void setYear(final int year) {
85         mAdapter.setSelection(year);
86 
87         post(new Runnable() {
88             @Override
89             public void run() {
90                 final int position = mAdapter.getPositionForYear(year);
91                 if (position >= 0 && position < getCount()) {
92                     setSelectionCentered(position);
93                 }
94             }
95         });
96     }
97 
setSelectionCentered(int position)98     public void setSelectionCentered(int position) {
99         final int offset = mViewSize / 2 - mChildSize / 2;
100         setSelectionFromTop(position, offset);
101     }
102 
setRange(Calendar min, Calendar max)103     public void setRange(Calendar min, Calendar max) {
104         mAdapter.setRange(min, max);
105     }
106 
107     private static class YearAdapter extends BaseAdapter {
108         private static final int ITEM_LAYOUT = R.layout.year_label_text_view;
109         private static final int ITEM_TEXT_APPEARANCE =
110                 R.style.TextAppearance_Material_DatePicker_List_YearLabel;
111         private static final int ITEM_TEXT_ACTIVATED_APPEARANCE =
112                 R.style.TextAppearance_Material_DatePicker_List_YearLabel_Activated;
113 
114         private final LayoutInflater mInflater;
115 
116         private int mActivatedYear;
117         private int mMinYear;
118         private int mCount;
119 
YearAdapter(Context context)120         public YearAdapter(Context context) {
121             mInflater = LayoutInflater.from(context);
122         }
123 
setRange(Calendar minDate, Calendar maxDate)124         public void setRange(Calendar minDate, Calendar maxDate) {
125             final int minYear = minDate.get(Calendar.YEAR);
126             final int count = maxDate.get(Calendar.YEAR) - minYear + 1;
127 
128             if (mMinYear != minYear || mCount != count) {
129                 mMinYear = minYear;
130                 mCount = count;
131                 notifyDataSetInvalidated();
132             }
133         }
134 
setSelection(int year)135         public boolean setSelection(int year) {
136             if (mActivatedYear != year) {
137                 mActivatedYear = year;
138                 notifyDataSetChanged();
139                 return true;
140             }
141             return false;
142         }
143 
144         @Override
getCount()145         public int getCount() {
146             return mCount;
147         }
148 
149         @Override
getItem(int position)150         public Integer getItem(int position) {
151             return getYearForPosition(position);
152         }
153 
154         @Override
getItemId(int position)155         public long getItemId(int position) {
156             return getYearForPosition(position);
157         }
158 
getPositionForYear(int year)159         public int getPositionForYear(int year) {
160             return year - mMinYear;
161         }
162 
getYearForPosition(int position)163         public int getYearForPosition(int position) {
164             return mMinYear + position;
165         }
166 
167         @Override
hasStableIds()168         public boolean hasStableIds() {
169             return true;
170         }
171 
172         @Override
getView(int position, View convertView, ViewGroup parent)173         public View getView(int position, View convertView, ViewGroup parent) {
174             final TextView v;
175             final boolean hasNewView = convertView == null;
176             if (hasNewView) {
177                 v = (TextView) mInflater.inflate(ITEM_LAYOUT, parent, false);
178             } else {
179                 v = (TextView) convertView;
180             }
181 
182             final int year = getYearForPosition(position);
183             final boolean activated = mActivatedYear == year;
184 
185             if (hasNewView || v.isActivated() != activated) {
186                 final int textAppearanceResId;
187                 if (activated && ITEM_TEXT_ACTIVATED_APPEARANCE != 0) {
188                     textAppearanceResId = ITEM_TEXT_ACTIVATED_APPEARANCE;
189                 } else {
190                     textAppearanceResId = ITEM_TEXT_APPEARANCE;
191                 }
192                 v.setTextAppearance(textAppearanceResId);
193                 v.setActivated(activated);
194             }
195 
196             v.setText(Integer.toString(year));
197             return v;
198         }
199 
200         @Override
getItemViewType(int position)201         public int getItemViewType(int position) {
202             return 0;
203         }
204 
205         @Override
getViewTypeCount()206         public int getViewTypeCount() {
207             return 1;
208         }
209 
210         @Override
isEmpty()211         public boolean isEmpty() {
212             return false;
213         }
214 
215         @Override
areAllItemsEnabled()216         public boolean areAllItemsEnabled() {
217             return true;
218         }
219 
220         @Override
isEnabled(int position)221         public boolean isEnabled(int position) {
222             return true;
223         }
224     }
225 
getFirstPositionOffset()226     public int getFirstPositionOffset() {
227         final View firstChild = getChildAt(0);
228         if (firstChild == null) {
229             return 0;
230         }
231         return firstChild.getTop();
232     }
233 
234     /** @hide */
235     @Override
onInitializeAccessibilityEventInternal(AccessibilityEvent event)236     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
237         super.onInitializeAccessibilityEventInternal(event);
238 
239         // There are a bunch of years, so don't bother.
240         if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
241             event.setFromIndex(0);
242             event.setToIndex(0);
243         }
244     }
245 
246     /**
247      * The callback used to indicate the user changed the year.
248      */
249     public interface OnYearSelectedListener {
250         /**
251          * Called upon a year change.
252          *
253          * @param view The view associated with this listener.
254          * @param year The year that was set.
255          */
onYearChanged(YearPickerView view, int year)256         void onYearChanged(YearPickerView view, int year);
257     }
258 }