Home | History | Annotate | Download | only in widget
      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 
     40     public YearPickerView(Context context, AttributeSet attrs) {
     41         this(context, attrs, R.attr.listViewStyle);
     42     }
     43 
     44     public YearPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
     45         this(context, attrs, defStyleAttr, 0);
     46     }
     47 
     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 
     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      */
     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 
     98     public void setSelectionCentered(int position) {
     99         final int offset = mViewSize / 2 - mChildSize / 2;
    100         setSelectionFromTop(position, offset);
    101     }
    102 
    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 
    120         public YearAdapter(Context context) {
    121             mInflater = LayoutInflater.from(context);
    122         }
    123 
    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 
    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
    145         public int getCount() {
    146             return mCount;
    147         }
    148 
    149         @Override
    150         public Integer getItem(int position) {
    151             return getYearForPosition(position);
    152         }
    153 
    154         @Override
    155         public long getItemId(int position) {
    156             return getYearForPosition(position);
    157         }
    158 
    159         public int getPositionForYear(int year) {
    160             return year - mMinYear;
    161         }
    162 
    163         public int getYearForPosition(int position) {
    164             return mMinYear + position;
    165         }
    166 
    167         @Override
    168         public boolean hasStableIds() {
    169             return true;
    170         }
    171 
    172         @Override
    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
    201         public int getItemViewType(int position) {
    202             return 0;
    203         }
    204 
    205         @Override
    206         public int getViewTypeCount() {
    207             return 1;
    208         }
    209 
    210         @Override
    211         public boolean isEmpty() {
    212             return false;
    213         }
    214 
    215         @Override
    216         public boolean areAllItemsEnabled() {
    217             return true;
    218         }
    219 
    220         @Override
    221         public boolean isEnabled(int position) {
    222             return true;
    223         }
    224     }
    225 
    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
    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          */
    256         void onYearChanged(YearPickerView view, int year);
    257     }
    258 }