FileDocCategorySizeDatePackage
DayPickerView.javaAPI DocAndroid 5.1 API19186Thu Mar 12 22:22:10 GMT 2015android.widget

DayPickerView

public class DayPickerView extends ListView implements AbsListView.OnScrollListener
This displays a list of months in a calendar format with selectable days.

Fields Summary
private static final String
TAG
private static final int
GOTO_SCROLL_DURATION
private static final int
SCROLL_CHANGE_DELAY
private static final int
LIST_TOP_OFFSET
private final SimpleMonthAdapter
mAdapter
private final ScrollStateRunnable
mScrollStateChangedRunnable
private SimpleDateFormat
mYearFormat
private Calendar
mSelectedDay
private Calendar
mTempDay
private Calendar
mMinDate
private Calendar
mMaxDate
private Calendar
mTempCalendar
private OnDaySelectedListener
mOnDaySelectedListener
private int
mCurrentMonthDisplayed
private int
mPreviousScrollState
private int
mCurrentScrollState
private boolean
mPerformingScroll
private final SimpleMonthAdapter.OnDaySelectedListener
mProxyOnDaySelectedListener
Constructors Summary
public DayPickerView(android.content.Context context)


       
        super(context);

        setAdapter(mAdapter);
        setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        setDrawSelectorOnTop(false);
        setUpListView();

        goTo(mSelectedDay.getTimeInMillis(), false, false, true);

        mAdapter.setOnDaySelectedListener(mProxyOnDaySelectedListener);
    
Methods Summary
private java.util.CalendarfindAccessibilityFocus()
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 SimpleMonthView) {
                final Calendar focus = ((SimpleMonthView) child).getAccessibilityFocus();
                if (focus != null) {
                    return focus;
                }
            }
        }

        return null;
    
public longgetDate()

        return mSelectedDay.getTimeInMillis();
    
private intgetDiffMonths(java.util.Calendar start, java.util.Calendar end)

        final int diffYears = end.get(Calendar.YEAR) - start.get(Calendar.YEAR);
        final int diffMonths = end.get(Calendar.MONTH) - start.get(Calendar.MONTH) + 12 * diffYears;
        return diffMonths;
    
public intgetFirstDayOfWeek()

        return mAdapter.getFirstDayOfWeek();
    
public longgetMaxDate()

        return mMaxDate.getTimeInMillis();
    
public longgetMinDate()

        return mMinDate.getTimeInMillis();
    
private java.lang.StringgetMonthAndYearString(java.util.Calendar day)

        final StringBuilder sbuf = new StringBuilder();
        sbuf.append(day.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()));
        sbuf.append(" ");
        sbuf.append(mYearFormat.format(day.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;
    
private intgetPositionFromDay(long timeInMillis)

        final int diffMonthMax = getDiffMonths(mMinDate, mMaxDate);
        final int diffMonth = getDiffMonths(mMinDate, getTempCalendarForTime(timeInMillis));
        return MathUtils.constrain(diffMonth, 0, diffMonthMax);
    
private java.util.CalendargetTempCalendarForTime(long timeInMillis)

        if (mTempCalendar == null) {
            mTempCalendar = Calendar.getInstance();
        }
        mTempCalendar.setTimeInMillis(timeInMillis);
        return mTempCalendar;
    
private booleangoTo(long 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
day The day 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.setTimeInMillis(day);
        }

        mTempDay.setTimeInMillis(day);
        final int position = getPositionFromDay(day);

        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();
        } 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);
        }

        // 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;
    
protected voidlayoutChildren()

        final Calendar focusedDay = findAccessibilityFocus();
        super.layoutChildren();
        if (mPerformingScroll) {
            mPerformingScroll = false;
        } else {
            restoreAccessibilityFocus(focusedDay);
        }
    
protected voidonConfigurationChanged(android.content.res.Configuration newConfig)

        mYearFormat = new SimpleDateFormat("yyyy", Locale.getDefault());
    
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.AccessibilityAction.ACTION_SCROLL_FORWARD);
        info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
    
public voidonRangeChanged()
Handles changes to date range.

        mAdapter.setRange(mMinDate, mMaxDate);

        // Changing the min/max date changes the selection position since we
        // don't really have stable IDs. Jumps immediately to the new position.
        goTo(mSelectedDay.getTimeInMillis(), false, false, true);
    
public voidonScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
Updates the title and selected month if the view has moved to a new month.

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

        mPreviousScrollState = mCurrentScrollState;
    
public voidonScrollStateChanged(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.
        final int firstVisiblePosition = getFirstVisiblePosition();
        final int month = firstVisiblePosition % 12;
        final int year = firstVisiblePosition / 12 + mMinDate.get(Calendar.YEAR);
        final Calendar day = Calendar.getInstance();
        day.set(year, month, 1);

        // Scroll either forward or backward one month.
        if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) {
            day.add(Calendar.MONTH, 1);
            if (day.get(Calendar.MONTH) == 12) {
                day.set(Calendar.MONTH, 0);
                day.add(Calendar.YEAR, 1);
            }
        } 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.add(Calendar.MONTH, -1);
                if (day.get(Calendar.MONTH) == -1) {
                    day.set(Calendar.MONTH, 11);
                    day.add(Calendar.YEAR, -1);
                }
            }
        }

        // Go to that month.
        announceForAccessibility(getMonthAndYearString(day));
        goTo(day.getTimeInMillis(), 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);
    
private booleanrestoreAccessibilityFocus(java.util.Calendar 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 SimpleMonthView) {
                if (((SimpleMonthView) child).restoreAccessibilityFocus(day)) {
                    return true;
                }
            }
        }

        return false;
    
voidsetCalendarTextAppearance(int resId)

        mAdapter.setCalendarTextAppearance(resId);
    
voidsetCalendarTextColor(android.content.res.ColorStateList colors)

        mAdapter.setCalendarTextColor(colors);
    
public voidsetDate(long timeInMillis)
Sets the currently selected date to the specified timestamp. Jumps immediately to the new date. To animate to the new date, use {@link #setDate(long, boolean, boolean)}.

param
timeInMillis

        setDate(timeInMillis, false, true);
    
public voidsetDate(long timeInMillis, boolean animate, boolean forceScroll)

        goTo(timeInMillis, animate, true, forceScroll);
    
public voidsetFirstDayOfWeek(int firstDayOfWeek)

        mAdapter.setFirstDayOfWeek(firstDayOfWeek);
    
public voidsetMaxDate(long timeInMillis)

        mMaxDate.setTimeInMillis(timeInMillis);
        onRangeChanged();
    
public voidsetMinDate(long timeInMillis)

        mMinDate.setTimeInMillis(timeInMillis);
        onRangeChanged();
    
protected voidsetMonthDisplayed(java.util.Calendar date)
Sets the month displayed at the top of this view based on time. Override to add custom events when the title is changed.

        if (mCurrentMonthDisplayed != date.get(Calendar.MONTH)) {
            mCurrentMonthDisplayed = date.get(Calendar.MONTH);
            invalidateViews();
        }
    
public voidsetOnDaySelectedListener(android.widget.DayPickerView$OnDaySelectedListener listener)
Sets the listener to call when the user selects a day.

param
listener The listener to call.

        mOnDaySelectedListener = listener;
    
private 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());