定义了一个通用的base adapter
package com.whuthm.picker;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
/**
* 基类adapter
*
* @author whuthm
* @date 2015-6-25
*/
public abstract class BaseAdapter<T> extends android.widget.BaseAdapter {
protected Context context;
protected List<T> list = null;
List<BaseAdapter.ViewHolder<T>> holders = new ArrayList<BaseAdapter.ViewHolder<T>>();
public BaseAdapter(Context context, List<T> list) {
this.context = context;
this.list = list;
}
@Override
public int getCount() {
return list != null ? list.size() : 0;
}
@Override
public Object getItem(int position) {
return list != null && position >= 0 && position < list.size() ? list
.get(position) : null;
}
@Override
public long getItemId(int position) {
return position;
}
@SuppressWarnings("unchecked")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder<T> holder;
if (convertView == null) {
convertView = createView(context, parent);
holder = createViewHolder();
convertView.setTag(holder);
holder.init(context, convertView);
holders.add(holder);
}
else {
holder = (ViewHolder<T>) convertView.getTag();
}
T data = list.get(position);
holder.position = position;
holder.update(context, data);
return convertView;
}
public abstract View createView(Context context, ViewGroup parent);
public abstract ViewHolder<T> createViewHolder();
/**
* 保存当前Item的view
*/
public static abstract class ViewHolder<T> {
public int position;
public abstract void init(Context context, View convertView);
public abstract void update(Context context, T data);
}
}
PickerView的实现
package com.whuthm.picker;
import java.util.ArrayList;
import java.util.List;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PorterDuff;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ListAdapter;
import android.widget.Scroller;
public class PickerView extends FrameLayout {
/**
* The coefficient by which to adjust (divide) the max fling velocity.
*/
private static final int SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 8;
/**
* The the duration for adjusting the selector wheel.
*/
private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 500;
private int mMinScrollY;
private int mMaxScrollY;
private int mSelectorIndex = 0;
private int mSelectorCount = 0;
private int mFixedWidth = 0;
private int mFixedHeight = 0;
private PickerInnerView mInnerView;
private ListAdapter mAdapter;
private int mVisibleStartIndex = -1;
private int mVisibleEndIndex = -1;
private int mPosition = -1;
private SparseArray<View> mVisibleViews = new SparseArray<View>();
private List<View> mScrapViews = new ArrayList<View>();
private Drawable mSelectorForeground;
/**
* Listener to be notified upon scroll state change.
*/
private OnScrollListener mOnScrollListener;
private Scroller mScroller;
/**
* The Y position of the last down event.
*/
private float mLastDownEventY;
/**
* The Y position of the last down or move event.
*/
private float mLastDownOrMoveEventY;
/**
* Determines speed during touch scrolling.
*/
private VelocityTracker mVelocityTracker;
/**
* @see ViewConfiguration#getScaledTouchSlop()
*/
private int mTouchSlop;
/**
* @see ViewConfiguration#getScaledMinimumFlingVelocity()
*/
private int mMinimumFlingVelocity;
/**
* @see ViewConfiguration#getScaledMaximumFlingVelocity()
*/
private int mMaximumFlingVelocity;
/**
* The current scroll state of the number picker.
*/
private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE;
/**
* Interface to listen for the picker scroll state.
*/
public interface OnScrollListener {
/**
* The view is not scrolling.
*/
public static int SCROLL_STATE_IDLE = 0;
/**
* The user is scrolling using the key, or adjust to right position
*/
public static int SCROLL_STATE_SCROLL = 2;
/**
* The user is scrolling using touch, and his finger is still on the
* screen.
*/
public static int SCROLL_STATE_TOUCH_SCROLL = 2;
/**
* The user had previously been scrolling using touch and performed a
* fling.
*/
public static int SCROLL_STATE_FLING_SCROLL = 3;
public void onScrollStateChange(PickerView view, int scrollState);
}
public interface OnPickerSelectedListener {
public void onPickerSelected(int position);
}
private OnPickerSelectedListener mPickerSelectedListener;
private Shader mShader;
private Paint mPaint;
private Matrix mMatrix;
public PickerView(Context context) {
this(context, null);
}
public PickerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PickerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setWillNotDraw(false);
final Resources res = getResources();
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PickerView);
mFixedWidth = a.getDimensionPixelSize(R.styleable.PickerView_fixedWidth,
res.getDimensionPixelSize(R.dimen.picker_item_default_fixed_width));
mFixedHeight = a.getDimensionPixelSize(R.styleable.PickerView_fixedHeight,
res.getDimensionPixelSize(R.dimen.picker_item_default_fixed_height));
mSelectorForeground = a.getDrawable(R.styleable.PickerView_selectorForeground);
if (mSelectorForeground == null) {
mSelectorForeground = res.getDrawable(R.drawable.picker_selector_foreground);
}
mSelectorCount = a.getInteger(R.styleable.PickerView_selectorCount, 0);
mSelectorCount = Math.max(0, mSelectorCount);
mSelectorIndex = a.getInteger(R.styleable.PickerView_selectorIndex, 0);
mSelectorIndex = Math.min(mSelectorCount - 1, mSelectorIndex);
mSelectorIndex = Math.max(0, mSelectorIndex);
a.recycle();
// initialize constants
ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity() / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT;
mScroller = new Scroller(getContext(), new DecelerateInterpolator(2.5f));
mMatrix = new Matrix();
mPaint = new Paint();
mShader = new LinearGradient(0, 0, 0, 1, 0xbb000000, 0x66000000, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
private DataSetObserver mDataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
notifyDataChange();
}
};
public void setOnScrollListener(OnScrollListener onScrollListener) {
mOnScrollListener = onScrollListener;
}
public void setOnPickerSelectedListener(OnPickerSelectedListener l) {
mPickerSelectedListener = l;
}
public void setAdapter(ListAdapter adapter) {
mAdapter = adapter;
adapter.registerDataSetObserver(mDataSetObserver);
mVisibleStartIndex = -1;
mVisibleEndIndex = -1;
mVisibleViews.clear();
mScrapViews.clear();
if (mInnerView != null) {
mInnerView.removeAllViews();
}
removeAllViewsInLayout();
mInnerView = new PickerInnerView(getContext());
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
addView(mInnerView, lp);
final int count = adapter.getCount();
mMinScrollY = 0;
mMaxScrollY = (count - 1) * mFixedHeight;
mMaxScrollY = Math.max(0, mMaxScrollY);
scrollTo(0, mPosition * mFixedHeight);
handleScroll(0, getScrollY(), 0, 0);
requestLayout();
}
public void notifyDataChange() {
if (mFixedHeight <= 0 || mInnerView == null) {
return;
}
int oldCount = mMaxScrollY / mFixedHeight;
final int count = mAdapter.getCount();
if (oldCount > count) {
for (int i = count; i < oldCount; i++) {
View view = mVisibleViews.get(i);
if (view != null) {
mVisibleViews.remove(i);
mInnerView.removeView(view);
mInnerView.removeDetachedView(view);
mScrapViews.add(view);
}
}
}
mMinScrollY = 0;
mMaxScrollY = (count - 1) * mFixedHeight;
mMaxScrollY = Math.max(0, mMaxScrollY);
scrollTo(0, mPosition * mFixedHeight);
handleScroll(0, getScrollY(), 0, 0);
mInnerView.requestLayout();
}
public int getPickerCount() {
return mAdapter != null ? mAdapter.getCount() : 0;
}
public void setCurrentItem(int position) {
if (isDataInvalid()) {
return;
}
int count = mAdapter.getCount();
if (position <= 0) {
position = 0;
} else if (position >= count) {
position = count - 1;
}
scrollTo(0, position * mFixedHeight);
mInnerView.requestLayout();
}
@Override
protected void dispatchDraw(Canvas canvas) {
if (isDataInvalid()) {
super.dispatchDraw(canvas);
} else {
final int width = getWidth();
final int scrollX = getScrollX();
final int scrollY = getScrollY();
int saveCount = canvas.getSaveCount();
int length = Math.max(mSelectorIndex * mFixedHeight, (mSelectorCount - 1 - mSelectorIndex) * mFixedHeight);
int left = scrollX + getPaddingLeft();
int top = scrollY + mSelectorIndex * mFixedHeight - length - getPaddingTop();
int right = left + width - getPaddingLeft() - getPaddingRight();
int bottom = top + 2 * length + mFixedHeight;
boolean drawTop = mSelectorIndex > 0;
boolean drawBottom = mSelectorIndex < mSelectorCount - 1;
final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
if (drawTop) {
canvas.saveLayer(left, top, right, top + length, null, flags);
}
if (drawBottom) {
canvas.saveLayer(left, bottom - length, right, bottom, null, flags);
}
super.dispatchDraw(canvas);
if (drawTop) {
mMatrix.setScale(1, length);
mMatrix.postTranslate(left, top);
mShader.setLocalMatrix(mMatrix);
mPaint.setShader(mShader);
canvas.drawRect(left, top, right, top + length, mPaint);
}
if (drawBottom) {
mMatrix.setScale(1, length);
mMatrix.postRotate(180);
mMatrix.postTranslate(left, bottom);
mShader.setLocalMatrix(mMatrix);
mPaint.setShader(mShader);
canvas.drawRect(left, bottom - length, right, bottom, mPaint);
}
canvas.restoreToCount(saveCount);
if (mSelectorForeground != null) {
canvas.save();
mSelectorForeground.setBounds(scrollX, scrollY + mSelectorIndex * mFixedHeight, width, scrollY
+ mSelectorIndex * mFixedHeight + mFixedHeight);
mSelectorForeground.draw(canvas);
canvas.restore();
}
}
}
@Override
protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
ViewGroup.LayoutParams lp = child.getLayoutParams();
int childWidthMeasureSpec;
int childHeightMeasureSpec;
childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, getPaddingLeft() + getPaddingRight(),
lp.width);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
@Override
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed) {
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, getPaddingLeft()
+ getPaddingRight() + lp.leftMargin + lp.rightMargin + widthUsed, lp.width);
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.topMargin + lp.bottomMargin,
MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int newWidthMeasureSpec = widthMeasureSpec;
int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(mFixedHeight * mSelectorCount + getPaddingTop()
+ getPaddingBottom(), MeasureSpec.EXACTLY);
if (widthSpecMode != MeasureSpec.EXACTLY) {
newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(mFixedWidth + getPaddingLeft() + getPaddingRight(),
MeasureSpec.EXACTLY);
}
super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
}
private boolean isDataInvalid() {
return mFixedWidth <= 0 || mFixedHeight <= 0 || mAdapter == null || mAdapter.getCount() <= 0;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (!isEnabled() || isDataInvalid()) {
return false;
}
final int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastDownOrMoveEventY = mLastDownEventY = event.getY();
if (!mScroller.isFinished()) {
mScroller.forceFinished(true);
}
onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
return true;
}
return false;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled() || isDataInvalid()) {
return false;
}
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_MOVE:
float currentMoveY = event.getY();
if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY);
if (deltaDownY > mTouchSlop) {
onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
}
} else {
int deltaMoveY = (int) ((currentMoveY - mLastDownOrMoveEventY));
scrollBy(0, -deltaMoveY);
invalidate();
}
mLastDownOrMoveEventY = currentMoveY;
break;
case MotionEvent.ACTION_UP:
if (mScrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
int initialVelocity = (int) velocityTracker.getYVelocity();
// 当速度不够(小于mMinimumFlingVelocity)时,调整至适当的Value
// 当速度足够时,fling
if (Math.abs(initialVelocity) >= mMinimumFlingVelocity) {
fling(initialVelocity);
} else {
ensureScrollWheelAdjusted();
}
} else {
ensureScrollWheelAdjusted();
}
mVelocityTracker.recycle();
mVelocityTracker = null;
break;
}
return true;
}
// **************************************************************************************
/**
* 三种非Touch 滚动 1 滑动后有扔的动作(fling) 2
* 滑动后没有扔的动作,自动调整到最近的位置(adjustToClosestPosition) 3
* 点击选中某一位置:上下按键,已经Touch选中某一项(moveToSelectedPosition)
*/
/**
* Flings the selector with the given <code>velocityY</code>.
*/
private void fling(int velocityY) {
if (!isDataInvalid()) {
final int curScrollY = getScrollY();
final int fixedHeight = mFixedHeight;
if (velocityY > 0) {
mScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
} else {
mScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
}
int duration = mScroller.getDuration();
int distance = mScroller.getStartY() - mScroller.getFinalY();
int finalY = distance + curScrollY;
int halfFixedHeight = fixedHeight / 2;
int remainder = finalY % fixedHeight;
if (remainder == 0) {
// do nothing
} else if (remainder > halfFixedHeight) {
finalY += fixedHeight - remainder;
} else if (-remainder > halfFixedHeight) {
finalY += -remainder - fixedHeight;
} else {
finalY += -remainder;
}
finalY = Math.min(mMaxScrollY, Math.max(mMinScrollY, finalY));
mScroller.startScroll(0, getScrollY(), 0, finalY - curScrollY, duration);
if (mScroller.getStartY() != mScroller.getFinalY()) {
invalidate();
onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING_SCROLL);
} else {
mScroller.abortAnimation();
ensureScrollWheelAdjusted();
}
}
}
private void ensureScrollWheelAdjusted() {
if (!isDataInvalid()) {
final int curScrollY = getScrollY();
final int fixedHeight = mFixedHeight;
int halfFixedHeight = fixedHeight / 2;
int remainder = curScrollY % mFixedHeight;
int deltaY;
if (remainder == 0) {
// do nothing
deltaY = 0;
} else if (remainder > halfFixedHeight) {
deltaY = fixedHeight - remainder;
} else if (-remainder > halfFixedHeight) {
deltaY = -remainder - fixedHeight;
} else {
deltaY = -remainder;
}
if (deltaY != 0) {
mScroller.startScroll(0, curScrollY, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS);
onScrollStateChange(OnScrollListener.SCROLL_STATE_SCROLL);
invalidate();
} else {
onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
}
}
}
private void onPickerSelectedChange(int position) {
if (mPosition == position) {
return;
}
mPosition = position;
if (mPickerSelectedListener != null) {
mPickerSelectedListener.onPickerSelected(position);
}
}
/**
* Handles transition to a given <code>scrollState</code>
*/
private void onScrollStateChange(int scrollState) {
if (mScrollState == scrollState) {
return;
}
mScrollState = scrollState;
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChange(this, scrollState);
}
}
@Override
protected void onScrollChanged(int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
super.onScrollChanged(scrollX, scrollY, oldScrollX, oldScrollY);
handleScroll(scrollX, scrollY, oldScrollX, oldScrollY);
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, Math.min(mMaxScrollY, Math.max(mMinScrollY, y)));
if (!isDataInvalid()) {
onPickerSelectedChange(getScrollY() / mFixedHeight);
}
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
int oldX = getScrollX();
int oldY = getScrollY();
int x = mScroller.getCurrX();
int y = mScroller.getCurrY();
if (oldX != x || oldY != y) {
scrollTo(x, y);
}
postInvalidate();
} else {
onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
}
}
private void handleScroll(int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if (isDataInvalid()) {
return;
}
final int count = mAdapter.getCount();
int multipleCount = scrollY / mFixedHeight;
int remainderCount = scrollY % mFixedHeight;
int newStartIndex = multipleCount - mSelectorIndex;
int newEndIndex = remainderCount > 0 ? newStartIndex + mSelectorCount : newStartIndex + mSelectorCount - 1;
newStartIndex = Math.max(newStartIndex, 0);
newEndIndex = Math.min(newEndIndex, count - 1);
if (mVisibleStartIndex != newStartIndex || mVisibleEndIndex != newEndIndex) {
mVisibleStartIndex = newStartIndex;
mVisibleEndIndex = newEndIndex;
mInnerView.requestLayout();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mPickerSelectedListener = null;
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
mDataSetObserver = null;
}
mAdapter = null;
mVisibleStartIndex = -1;
mVisibleEndIndex = -1;
mVisibleViews.clear();
mScrapViews.clear();
}
private class PickerInnerView extends ViewGroup {
public PickerInnerView(Context context) {
this(context, null);
}
public PickerInnerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PickerInnerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int newWidth = 0;
int newHeight = 0;
int count = mAdapter.getCount();
if (mFixedWidth > 0 && mFixedHeight > 0 && count > 0 && mSelectorCount > 0) {
newWidth = mFixedWidth;
newHeight = mFixedHeight * (count + mSelectorCount - 1);
}
setMeasuredDimension(newWidth, newHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = mAdapter.getCount();
int left = 0;
int top = mSelectorIndex * mFixedHeight;
for (int i = 0; i < count; i++) {
View view = mVisibleViews.get(i);
if (i >= mVisibleStartIndex && i <= mVisibleEndIndex) {
if (view == null) {
int size = mScrapViews.size();
if (size > 0) {
view = mScrapViews.remove(0);
}
view = mAdapter.getView(i, view, this);
addView(view);
view.measure(MeasureSpec.makeMeasureSpec(mFixedWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mFixedHeight, MeasureSpec.EXACTLY));
mVisibleViews.put(i, view);
}
view.layout(left, top, left + mFixedWidth, top + mFixedHeight);
} else {
if (view != null) {
mVisibleViews.remove(i);
removeView(view);
removeDetachedView(view, false);
mScrapViews.add(view);
}
}
top += mFixedHeight;
}
}
void removeDetachedView(View view) {
removeDetachedView(view, false);
}
}
}
DatePicker实现日期选择器
package com.whuthm.picker;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import com.whuthm.picker.PickerView.OnPickerSelectedListener;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
public class DatePicker extends LinearLayout {
enum DateType {
YEAR, MONTH, DAY
}
private PickerView mYearPicker;
private PickerView mMonthPicker;
private PickerView mDayPicker;
private int mYear;
private int mMonth;
private int mDay;
private int mMinYear;
private int mMaxYear;
private List<Integer> mDayDats = new ArrayList<Integer>();
public DatePicker(Context context) {
this(context, null);
}
public DatePicker(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(HORIZONTAL);
final LayoutInflater inflater = LayoutInflater.from(context);
LayoutParams lp;
mYearPicker = (PickerView) inflater.inflate(R.layout.view_date_picker, this, false);
lp = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1);
addView(mYearPicker, lp);
mYearPicker.setOnPickerSelectedListener(mYearSelectedListener);
mMonthPicker = (PickerView) inflater.inflate(R.layout.view_date_picker, this, false);
lp = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1);
addView(mMonthPicker, lp);
mMonthPicker.setOnPickerSelectedListener(mMonthSelectedListener);
mDayPicker = (PickerView) inflater.inflate(R.layout.view_date_picker, this, false);
lp = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1);
addView(mDayPicker, lp);
mDayPicker.setOnPickerSelectedListener(mDaySelectedListener);
}
public void setDate(int year, int minYear, int maxYear) {
setDate(year, 1, 1, minYear, maxYear);
}
public void setDate(int year, int month, int day, int minYear, int maxYear) {
if (maxYear < minYear) {
throw new RuntimeException("maxYear < minYear");
}
mMaxYear = maxYear;
mMinYear = minYear;
if (year < minYear) {
mYear = minYear;
} else if (year > maxYear) {
mYear = maxYear;
} else {
mYear = year;
}
mMonth = month;
mDay = day;
mDayPicker.setAdapter(createDayAdapter(year, month));
mDayPicker.setCurrentItem(day - 1);
mMonthPicker.setAdapter(createMonthAdapter());
mMonthPicker.setCurrentItem(month - 1);
mYearPicker.setAdapter(createYearAdapter());
mYearPicker.setCurrentItem(year - mMinYear);
}
public int getYear() {
return mYear;
}
public int getMonth() {
return mMonth;
}
public int getDay() {
return mDay;
}
private OnPickerSelectedListener mYearSelectedListener = new OnPickerSelectedListener() {
@Override
public void onPickerSelected(int position) {
mYear = position + mMinYear;
int monthDays = getMonthDays(mYear, mMonth);
Log.e("whuthm", "mYearSelectedListener " + mYear + " monthDays = " + monthDays);
if (monthDays != mDayPicker.getPickerCount()) {
setupDayDatas(monthDays);
mDayPicker.notifyDataChange();
mDayPicker.setCurrentItem(mDay - 1);
}
}
};
private OnPickerSelectedListener mMonthSelectedListener = new OnPickerSelectedListener() {
@Override
public void onPickerSelected(int position) {
mMonth = position + 1;
int monthDays = getMonthDays(mYear, mMonth);
Log.e("whuthm", "mMonthSelectedListener " + mMonth + " monthDays = " + monthDays);
if (monthDays != mDayPicker.getPickerCount()) {
setupDayDatas(monthDays);
mDayPicker.notifyDataChange();
mDayPicker.setCurrentItem(mDay - 1);
}
}
};
private OnPickerSelectedListener mDaySelectedListener = new OnPickerSelectedListener() {
@Override
public void onPickerSelected(int position) {
mDay = position + 1;
Log.e("whuthm", "mDaySelectedListener " + mDay);
}
};
DateAdapter createYearAdapter() {
List<Integer> datas = new ArrayList<Integer>();
for (int i = mMinYear; i <= mMaxYear; i++) {
datas.add(i);
}
return new DateAdapter(getContext(), datas, DateType.YEAR);
}
DateAdapter createMonthAdapter() {
List<Integer> datas = new ArrayList<Integer>();
for (int i = 1; i <= 12; i++) {
datas.add(i);
}
return new DateAdapter(getContext(), datas, DateType.MONTH);
}
DateAdapter createDayAdapter(int year, int month) {
return createDayAdapter(getMonthDays(year, month));
}
DateAdapter createDayAdapter(int monthDays) {
mDayDats.clear();
for (int i = 1; i <= monthDays; i++) {
mDayDats.add(i);
}
return new DateAdapter(getContext(), mDayDats, DateType.DAY);
}
private void setupDayDatas(int monthDays) {
mDayDats.clear();
for (int i = 1; i <= monthDays; i++) {
mDayDats.add(i);
}
}
static class DateAdapter extends BaseAdapter<Integer> {
private DateType mType;
public DateAdapter(Context context, List<Integer> list, DateType type) {
super(context, list);
mType = type;
}
@Override
public View createView(Context context, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.item_date_picker, parent, false);
}
@Override
public com.whuthm.picker.BaseAdapter.ViewHolder<Integer> createViewHolder() {
return new DateHolder();
}
class DateHolder extends com.whuthm.picker.BaseAdapter.ViewHolder<Integer> {
TextView textView;
@Override
public void init(Context context, View convertView) {
textView = (TextView) convertView;
}
@Override
public void update(Context context, Integer data) {
textView.setText(getDateText(data, mType));
}
}
public static String getDateText(int data, DateType type) {
StringBuilder sb = new StringBuilder(Integer.toString(data));
if (type != null) {
sb.append(" ");
switch (type) {
case YEAR:
sb.append("年");
break;
case MONTH:
sb.append("月");
break;
case DAY:
sb.append("日");
break;
default:
break;
}
}
return sb.toString();
}
}
public static int getMonthDays(int year, int month) {
Calendar c = Calendar.getInstance(Locale.getDefault());
c.clear();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, 1);
return c.getActualMaximum(Calendar.DAY_OF_MONTH);
}
}
<declare-styleable name="PickerView">
<attr name="selectorIndex" format="integer" />
<attr name="selectorCount" format="integer" />
<attr name="selectorForeground" format="reference" />
<attr name="fixedWidth" format="dimension|reference" />
<attr name="fixedHeight" format="dimension|reference" />
</declare-styleable>