FileDocCategorySizeDatePackage
DayPickerView.javaAPI DocAndroid 5.1 API18230Thu Mar 12 22:22:50 GMT 2015com.android.datetimepicker.date

DayPickerView

public abstract class DayPickerView extends android.widget.ListView implements android.widget.AbsListView.OnScrollListener, com.android.datetimepicker.date.DatePickerDialog.OnDateChangedListener
This displays a list of months in a calendar format with selectable days.

Fields Summary
private static final String
TAG
protected static final int
SCROLL_HYST_WEEKS
protected static final int
GOTO_SCROLL_DURATION
protected static final int
SCROLL_CHANGE_DELAY
public static final int
DAYS_PER_WEEK
public static int
LIST_TOP_OFFSET
protected int
mNumWeeks
protected boolean
mShowWeekNumber
protected int
mDaysPerWeek
private static SimpleDateFormat
YEAR_FORMAT
protected float
mFriction
protected android.content.Context
mContext
protected android.os.Handler
mHandler
protected com.android.datetimepicker.date.MonthAdapter.CalendarDay
mSelectedDay
protected MonthAdapter
mAdapter
protected com.android.datetimepicker.date.MonthAdapter.CalendarDay
mTempDay
protected int
mFirstDayOfWeek
protected CharSequence
mPrevMonthName
protected int
mCurrentMonthDisplayed
protected long
mPreviousScrollPosition
protected int
mPreviousScrollState
protected int
mCurrentScrollState
private DatePickerController
mController
private boolean
mPerformingScroll
protected ScrollStateRunnable
mScrollStateChangedRunnable
Constructors Summary
public DayPickerView(android.content.Context context, android.util.AttributeSet attrs)


         
        super(context, attrs);
        init(context);
    
public DayPickerView(android.content.Context context, DatePickerController controller)

        super(context);
        init(context);
        setController(controller);
    
Methods Summary
public abstract MonthAdaptercreateMonthAdapter(android.content.Context context, DatePickerController controller)

private com.android.datetimepicker.date.MonthAdapter.CalendarDayfindAccessibilityFocus()
Attempts to return the date that has accessibility focus.

return
The date that has accessibility focus, or {@code null} if no date has focus.

        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = getChildAt(i);
            if (child instanceof MonthView) {
                final CalendarDay focus = ((MonthView) child).getAccessibilityFocus();
                if (focus != null) {
                    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        // Clear focus to avoid ListView bug in Jelly Bean MR1.
                        ((MonthView) child).clearAccessibilityFocus();
                    }
                    return focus;
                }
            }
        }

        return null;
    
private static java.lang.StringgetMonthAndYearString(com.android.datetimepicker.date.MonthAdapter.CalendarDay day)

        Calendar cal = Calendar.getInstance();
        cal.set(day.year, day.month, day.day);

        StringBuffer sbuf = new StringBuffer();
        sbuf.append(cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()));
        sbuf.append(" ");
        sbuf.append(YEAR_FORMAT.format(cal.getTime()));
        return sbuf.toString();
    
public intgetMostVisiblePosition()
Gets the position of the view that is most prominently displayed within the list view.

        final int firstPosition = getFirstVisiblePosition();
        final int height = getHeight();

        int maxDisplayedHeight = 0;
        int mostVisibleIndex = 0;
        int i=0;
        int bottom = 0;
        while (bottom < height) {
            View child = getChildAt(i);
            if (child == null) {
                break;
            }
            bottom = child.getBottom();
            int displayedHeight = Math.min(bottom, height) - Math.max(0, child.getTop());
            if (displayedHeight > maxDisplayedHeight) {
                mostVisibleIndex = i;
                maxDisplayedHeight = displayedHeight;
            }
            i++;
        }
        return firstPosition + mostVisibleIndex;
    
public booleangoTo(com.android.datetimepicker.date.MonthAdapter.CalendarDay day, boolean animate, boolean setSelected, boolean forceScroll)
This moves to the specified time in the view. If the time is not already in range it will move the list so that the first of the month containing the time is at the top of the view. If the new time is already in view the list will not be scrolled unless forceScroll is true. This time may optionally be highlighted as selected as well.

param
time The time to move to
param
animate Whether to scroll to the given time or just redraw at the new location
param
setSelected Whether to set the given time as selected
param
forceScroll Whether to recenter even if the time is already visible
return
Whether or not the view animated to the new location


        // Set the selected day
        if (setSelected) {
            mSelectedDay.set(day);
        }

        mTempDay.set(day);
        final int position = (day.year - mController.getMinYear())
                * MonthAdapter.MONTHS_IN_YEAR + day.month;

        View child;
        int i = 0;
        int top = 0;
        // Find a child that's completely in the view
        do {
            child = getChildAt(i++);
            if (child == null) {
                break;
            }
            top = child.getTop();
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "child at " + (i - 1) + " has top " + top);
            }
        } while (top < 0);

        // Compute the first and last position visible
        int selectedPosition;
        if (child != null) {
            selectedPosition = getPositionForView(child);
        } else {
            selectedPosition = 0;
        }

        if (setSelected) {
            mAdapter.setSelectedDay(mSelectedDay);
        }

        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "GoTo position " + position);
        }
        // Check if the selected day is now outside of our visible range
        // and if so scroll to the month that contains it
        if (position != selectedPosition || forceScroll) {
            setMonthDisplayed(mTempDay);
            mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING;
            if (animate) {
                smoothScrollToPositionFromTop(
                        position, LIST_TOP_OFFSET, GOTO_SCROLL_DURATION);
                return true;
            } else {
                postSetSelection(position);
            }
        } else if (setSelected) {
            setMonthDisplayed(mSelectedDay);
        }
        return false;
    
public voidinit(android.content.Context context)

        mHandler = new Handler();
        setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        setDrawSelectorOnTop(false);

        mContext = context;
        setUpListView();
    
protected voidlayoutChildren()

        final CalendarDay focusedDay = findAccessibilityFocus();
        super.layoutChildren();
        if (mPerformingScroll) {
            mPerformingScroll = false;
        } else {
            restoreAccessibilityFocus(focusedDay);
        }
    
public voidonChange()

        refreshAdapter();
    
public voidonDateChanged()

        goTo(mController.getSelectedDay(), false, true, true);
    
public voidonInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)

        super.onInitializeAccessibilityEvent(event);
        event.setItemCount(-1);
   
public voidonInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo info)
Necessary for accessibility, to ensure we support "scrolling" forward and backward in the month list.

      super.onInitializeAccessibilityNodeInfo(info);
      info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
      info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
    
public voidonScroll(android.widget.AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
Updates the title and selected month if the view has moved to a new month.

        MonthView child = (MonthView) view.getChildAt(0);
        if (child == null) {
            return;
        }

        // Figure out where we are
        long currScroll = view.getFirstVisiblePosition() * child.getHeight() - child.getBottom();
        mPreviousScrollPosition = currScroll;
        mPreviousScrollState = mCurrentScrollState;
    
public voidonScrollStateChanged(android.widget.AbsListView view, int scrollState)

        // use a post to prevent re-entering onScrollStateChanged before it
        // exits
        mScrollStateChangedRunnable.doScrollStateChange(view, scrollState);
    
public booleanperformAccessibilityAction(int action, android.os.Bundle arguments)
When scroll forward/backward events are received, announce the newly scrolled-to month.

        if (action != AccessibilityNodeInfo.ACTION_SCROLL_FORWARD &&
                action != AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
            return super.performAccessibilityAction(action, arguments);
        }

        // Figure out what month is showing.
        int firstVisiblePosition = getFirstVisiblePosition();
        int month = firstVisiblePosition % 12;
        int year = firstVisiblePosition / 12 + mController.getMinYear();
        CalendarDay day = new CalendarDay(year, month, 1);

        // Scroll either forward or backward one month.
        if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) {
            day.month++;
            if (day.month == 12) {
                day.month = 0;
                day.year++;
            }
        } else if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
            View firstVisibleView = getChildAt(0);
            // If the view is fully visible, jump one month back. Otherwise, we'll just jump
            // to the first day of first visible month.
            if (firstVisibleView != null && firstVisibleView.getTop() >= -1) {
                // There's an off-by-one somewhere, so the top of the first visible item will
                // actually be -1 when it's at the exact top.
                day.month--;
                if (day.month == -1) {
                    day.month = 11;
                    day.year--;
                }
            }
        }

        // Go to that month.
        Utils.tryAccessibilityAnnounce(this, getMonthAndYearString(day));
        goTo(day, true, false, true);
        mPerformingScroll = true;
        return true;
    
public voidpostSetSelection(int position)

        clearFocus();
        post(new Runnable() {

            @Override
            public void run() {
                setSelection(position);
            }
        });
        onScrollStateChanged(this, OnScrollListener.SCROLL_STATE_IDLE);
    
protected voidrefreshAdapter()
Creates a new adapter if necessary and sets up its parameters. Override this method to provide a custom adapter.

        if (mAdapter == null) {
            mAdapter = createMonthAdapter(getContext(), mController);
        } else {
            mAdapter.setSelectedDay(mSelectedDay);
        }
        // refresh the view with the new parameters
        setAdapter(mAdapter);
    
private booleanrestoreAccessibilityFocus(com.android.datetimepicker.date.MonthAdapter.CalendarDay day)
Attempts to restore accessibility focus to a given date. No-op if {@code day} is {@code null}.

param
day The date that should receive accessibility focus
return
{@code true} if focus was restored

        if (day == null) {
            return false;
        }

        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = getChildAt(i);
            if (child instanceof MonthView) {
                if (((MonthView) child).restoreAccessibilityFocus(day)) {
                    return true;
                }
            }
        }

        return false;
    
public voidsetController(DatePickerController controller)

        mController = controller;
        mController.registerOnDateChangedListener(this);
        refreshAdapter();
        onDateChanged();
    
protected voidsetMonthDisplayed(com.android.datetimepicker.date.MonthAdapter.CalendarDay date)
Sets the month displayed at the top of this view based on time. Override to add custom events when the title is changed.

        mCurrentMonthDisplayed = date.month;
        invalidateViews();
    
protected voidsetUpListView()

        // Transparent background on scroll
        setCacheColorHint(0);
        // No dividers
        setDivider(null);
        // Items are clickable
        setItemsCanFocus(true);
        // The thumb gets in the way, so disable it
        setFastScrollEnabled(false);
        setVerticalScrollBarEnabled(false);
        setOnScrollListener(this);
        setFadingEdgeLength(0);
        // Make the scrolling behavior nicer
        setFriction(ViewConfiguration.getScrollFriction() * mFriction);