YearPickerView.java revision 50eb025c2fea7e364e0be951ce8ba6ca605f901a
10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch/* 20529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * Copyright (C) 2014 The Android Open Source Project 30529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * 40529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * Licensed under the Apache License, Version 2.0 (the "License"); 5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * you may not use this file except in compliance with the License. 6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * You may obtain a copy of the License at 70529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * 80529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * http://www.apache.org/licenses/LICENSE-2.0 946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * 10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Unless required by applicable law or agreed to in writing, software 110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * distributed under the License is distributed on an "AS IS" BASIS, 120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * See the License for the specific language governing permissions and 14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * limitations under the License. 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */ 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochpackage android.widget; 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuimport android.content.Context; 200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.content.res.Resources; 210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.util.AttributeSet; 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import android.view.View; 23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import android.view.ViewGroup; 24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import android.view.accessibility.AccessibilityEvent; 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport java.util.Calendar; 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport com.android.internal.R; 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Displays a selectable list of years. 320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch */ 33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class YearPickerView extends ListView implements AdapterView.OnItemClickListener, 34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) OnDateChangedListener { 35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private final Calendar mMinDate = Calendar.getInstance(); 36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private final Calendar mMaxDate = Calendar.getInstance(); 37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private final YearAdapter mAdapter; 39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private final int mViewSize; 400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch private final int mChildSize; 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private DatePickerController mController; 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch private int mSelectedPosition = -1; 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private int mYearSelectedCircleColor; 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public YearPickerView(Context context) { 48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this(context, null); 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public YearPickerView(Context context, AttributeSet attrs) { 520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch this(context, attrs, R.attr.listViewStyle); 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr) { 560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch this(context, attrs, defStyleAttr, 0); 57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch super(context, attrs, defStyleAttr, defStyleRes); 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci final LayoutParams frame = new LayoutParams( 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci setLayoutParams(frame); 65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci final Resources res = context.getResources(); 670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch mViewSize = res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height); 68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch mChildSize = res.getDimensionPixelOffset(R.dimen.datepicker_year_label_height); 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) setVerticalFadingEdgeEnabled(true); 7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) setFadingEdgeLength(mChildSize / 3); 72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) final int paddingTop = res.getDimensionPixelSize( 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) R.dimen.datepicker_year_picker_padding_top); 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) setPadding(0, paddingTop, 0, 0); 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci setOnItemClickListener(this); 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) setDividerHeight(0); 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mAdapter = new YearAdapter(getContext(), R.layout.year_label_text_view); 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci setAdapter(mAdapter); 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void setRange(Calendar min, Calendar max) { 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mMinDate.setTimeInMillis(min.getTimeInMillis()); 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mMaxDate.setTimeInMillis(max.getTimeInMillis()); 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) updateAdapterData(); 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public void init(DatePickerController controller) { 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) mController = controller; 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mController.registerOnDateChangedListener(this); 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci updateAdapterData(); 96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) onDateChanged(); 98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public void setYearSelectedCircleColor(int color) { 1010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (color != mYearSelectedCircleColor) { 1020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch mYearSelectedCircleColor = color; 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci requestLayout(); 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public int getYearSelectedCircleColor() { 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return mYearSelectedCircleColor; 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private void updateAdapterData() { 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) mAdapter.clear(); 1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci final int maxYear = mMaxDate.get(Calendar.YEAR); 1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (int year = mMinDate.get(Calendar.YEAR); year <= maxYear; year++) { 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mAdapter.add(year); 1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mController.tryVibrate(); 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (position != mSelectedPosition) { 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mSelectedPosition = position; 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mAdapter.notifyDataSetChanged(); 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mController.onYearSelected(mAdapter.getItem(position)); 128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci void setItemTextAppearance(int resId) { 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mAdapter.setItemTextAppearance(resId); 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 13346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private class YearAdapter extends ArrayAdapter<Integer> { 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int mItemTextAppearanceResId; 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public YearAdapter(Context context, int resource) { 1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci super(context, resource); 1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public View getView(int position, View convertView, ViewGroup parent) { 1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci TextViewWithCircularIndicator v = (TextViewWithCircularIndicator) 1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci super.getView(position, convertView, parent); 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) v.setTextAppearance(getContext(), mItemTextAppearanceResId); 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci v.requestLayout(); 1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int year = getItem(position); 1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci boolean selected = mController.getSelectedDay().get(Calendar.YEAR) == year; 1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu v.setDrawIndicator(selected); 150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (selected) { 1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) v.setCircleColor(mYearSelectedCircleColor); 152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return v; 1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public void setItemTextAppearance(int resId) { 1570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch mItemTextAppearanceResId = resId; 1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) public void postSetSelectionCentered(final int position) { 1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) postSetSelectionFromTop(position, mViewSize / 2 - mChildSize / 2); 163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) public void postSetSelectionFromTop(final int position, final int offset) { 1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) post(new Runnable() { 1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void run() { 1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci setSelectionFromTop(position, offset); 1716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) requestLayout(); 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) }); 1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch public int getFirstPositionOffset() { 1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) final View firstChild = getChildAt(0); 1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (firstChild == null) { 1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return 0; 1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return firstChild.getTop(); 1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) @Override 1850de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles) public void onDateChanged() { 1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) updateAdapterData(); 1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mAdapter.notifyDataSetChanged(); 1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci postSetSelectionCentered( 1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mController.getSelectedDay().get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR)); 1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) @Override 1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) super.onInitializeAccessibilityEvent(event); 1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch event.setFromIndex(0); 19846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) event.setToIndex(0); 19946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 20046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 20146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}