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.widget; 18 19import android.content.Context; 20import android.content.res.Resources; 21import android.util.AttributeSet; 22import android.view.View; 23import android.view.ViewGroup; 24import android.view.accessibility.AccessibilityEvent; 25 26import java.util.Calendar; 27 28import com.android.internal.R; 29 30/** 31 * Displays a selectable list of years. 32 */ 33class YearPickerView extends ListView implements AdapterView.OnItemClickListener, 34 OnDateChangedListener { 35 private final Calendar mMinDate = Calendar.getInstance(); 36 private final Calendar mMaxDate = Calendar.getInstance(); 37 38 private final YearAdapter mAdapter; 39 private final int mViewSize; 40 private final int mChildSize; 41 42 private DatePickerController mController; 43 44 private int mSelectedPosition = -1; 45 private int mYearSelectedCircleColor; 46 47 public YearPickerView(Context context) { 48 this(context, null); 49 } 50 51 public YearPickerView(Context context, AttributeSet attrs) { 52 this(context, attrs, R.attr.listViewStyle); 53 } 54 55 public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr) { 56 this(context, attrs, defStyleAttr, 0); 57 } 58 59 public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 60 super(context, attrs, defStyleAttr, defStyleRes); 61 62 final LayoutParams frame = new LayoutParams( 63 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 64 setLayoutParams(frame); 65 66 final Resources res = context.getResources(); 67 mViewSize = res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height); 68 mChildSize = res.getDimensionPixelOffset(R.dimen.datepicker_year_label_height); 69 70 setVerticalFadingEdgeEnabled(true); 71 setFadingEdgeLength(mChildSize / 3); 72 73 final int paddingTop = res.getDimensionPixelSize( 74 R.dimen.datepicker_year_picker_padding_top); 75 setPadding(0, paddingTop, 0, 0); 76 77 setOnItemClickListener(this); 78 setDividerHeight(0); 79 80 mAdapter = new YearAdapter(getContext(), R.layout.year_label_text_view); 81 setAdapter(mAdapter); 82 } 83 84 public void setRange(Calendar min, Calendar max) { 85 mMinDate.setTimeInMillis(min.getTimeInMillis()); 86 mMaxDate.setTimeInMillis(max.getTimeInMillis()); 87 88 updateAdapterData(); 89 } 90 91 public void init(DatePickerController controller) { 92 mController = controller; 93 mController.registerOnDateChangedListener(this); 94 95 updateAdapterData(); 96 97 onDateChanged(); 98 } 99 100 public void setYearSelectedCircleColor(int color) { 101 if (color != mYearSelectedCircleColor) { 102 mYearSelectedCircleColor = color; 103 } 104 requestLayout(); 105 } 106 107 public int getYearSelectedCircleColor() { 108 return mYearSelectedCircleColor; 109 } 110 111 private void updateAdapterData() { 112 mAdapter.clear(); 113 114 final int maxYear = mMaxDate.get(Calendar.YEAR); 115 for (int year = mMinDate.get(Calendar.YEAR); year <= maxYear; year++) { 116 mAdapter.add(year); 117 } 118 } 119 120 @Override 121 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 122 mController.tryVibrate(); 123 if (position != mSelectedPosition) { 124 mSelectedPosition = position; 125 mAdapter.notifyDataSetChanged(); 126 } 127 mController.onYearSelected(mAdapter.getItem(position)); 128 } 129 130 void setItemTextAppearance(int resId) { 131 mAdapter.setItemTextAppearance(resId); 132 } 133 134 private class YearAdapter extends ArrayAdapter<Integer> { 135 int mItemTextAppearanceResId; 136 137 public YearAdapter(Context context, int resource) { 138 super(context, resource); 139 } 140 141 @Override 142 public View getView(int position, View convertView, ViewGroup parent) { 143 TextViewWithCircularIndicator v = (TextViewWithCircularIndicator) 144 super.getView(position, convertView, parent); 145 v.setTextAppearance(getContext(), mItemTextAppearanceResId); 146 v.requestLayout(); 147 int year = getItem(position); 148 boolean selected = mController.getSelectedDay().get(Calendar.YEAR) == year; 149 v.setDrawIndicator(selected); 150 if (selected) { 151 v.setCircleColor(mYearSelectedCircleColor); 152 } 153 return v; 154 } 155 156 public void setItemTextAppearance(int resId) { 157 mItemTextAppearanceResId = resId; 158 } 159 } 160 161 public void postSetSelectionCentered(final int position) { 162 postSetSelectionFromTop(position, mViewSize / 2 - mChildSize / 2); 163 } 164 165 public void postSetSelectionFromTop(final int position, final int offset) { 166 post(new Runnable() { 167 168 @Override 169 public void run() { 170 setSelectionFromTop(position, offset); 171 requestLayout(); 172 } 173 }); 174 } 175 176 public int getFirstPositionOffset() { 177 final View firstChild = getChildAt(0); 178 if (firstChild == null) { 179 return 0; 180 } 181 return firstChild.getTop(); 182 } 183 184 @Override 185 public void onDateChanged() { 186 updateAdapterData(); 187 mAdapter.notifyDataSetChanged(); 188 postSetSelectionCentered( 189 mController.getSelectedDay().get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR)); 190 } 191 192 @Override 193 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 194 super.onInitializeAccessibilityEvent(event); 195 196 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 197 event.setFromIndex(0); 198 event.setToIndex(0); 199 } 200 } 201}