自定义时间选择器

文章目录

  • 自定义时间选择器
    • 第一章 效果演示
      • 第01节 效果图
      • 第02节 主要文件
    • 第二章 案例代码
      • 第01节 核心文件 WheelPicker
      • 第02节 实体类 WheelBean
      • 第03节 接口类 IWheelPicker
      • 第04节 原子时间类 DateTimePickerView
      • 第05节 原子时间类 PickerYear
      • 第06节 原子时间类 PickerMonth
      • 第07节 原子时间类 PickerDay
      • 第08节 原子时间类 PickerHour
      • 第09节 原子时间类 PickerMinute
      • 第10节 原子时间类 PickerSecond
      • 第11节 测试Activity
      • 第12节 布局文件
      • 第13节 属性文件

第一章 效果演示

第01节 效果图

第02节 主要文件

1、来自于 Java 的类文件A. 核心文件src/java/view.wheel.WheelPicker.javaB. 实体类和接口src/java/view.wheel.WheelBean.javasrc/java/view.wheel.IWheelPicker.javaC. 原子时间类src/java/view.wheel.atom.time.DateTimePickerView.javasrc/java/view.wheel.atom.time.PickerDay.javasrc/java/view.wheel.atom.time.PickerHour.javasrc/java/view.wheel.atom.time.PickerMinute.javasrc/java/view.wheel.atom.time.PickerMonth.javasrc/java/view.wheel.atom.time.PickerSecond.javasrc/java/view.wheel.atom.time.PickerYear.javaD. 测试Activitysrc/java/DemoActivity.java2、来自于资源文件的类A. 布局文件res/layout/view_picker_time_date.xmlres/layout/activity_demo.xmlB. 属性文件res/values/attrs.xml

第二章 案例代码

第01节 核心文件 WheelPicker

位置

src/java/view.wheel.WheelPicker.java

代码

package view.wheel;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Camera;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.Paint.Align;import android.graphics.Paint.Style;import android.graphics.Rect;import android.graphics.Region.Op;import android.graphics.Typeface;import android.os.Build.VERSION;import android.os.Handler;import android.text.TextUtils;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.widget.Scroller;import androidx.annotation.NonNull;import java.util.ArrayList;import java.util.List;public class WheelPicker extends View implements IWheelPicker, Runnable {private final Handler mHandler;private Paint mPaint;private Scroller mScroller;private VelocityTracker mTracker;private WheelPicker.OnItemSelectedListener mOnItemSelectedListener;private WheelPicker.OnWheelChangeListener mOnWheelChangeListener;private Rect mRectDrawn;private Rect mRectIndicatorHead;private Rect mRectIndicatorFoot;private Rect mRectCurrentItem;private Camera mCamera;private Matrix mMatrixRotate;private Matrix mMatrixDepth;private List<WheelBean> mData;private String mMaxWidthText;protected String label;private int mVisibleItemCount;private int mDrawnItemCount;private int mHalfDrawnItemCount;private int mTextMaxWidth;private int mTextMaxHeight;private int mItemTextColor;private int mSelectedItemTextColor;private int mItemTextSize;private int mIndicatorSize;private int mIndicatorColor;private int mCurtainColor;private int mItemSpace;private int mItemAlign;private int mItemHeight;private int mHalfItemHeight;private int mHalfWheelHeight;private int mSelectedItemPosition;private int mCurrentItemPosition;private int mMinFlingY;private int mMaxFlingY;private int mMinimumVelocity;private int mMaximumVelocity;private int mWheelCenterX;private int mWheelCenterY;private int mDrawnCenterX;private int mDrawnCenterY;private int mScrollOffsetY;private int mTextMaxWidthPosition;private int mLastPointY;private int mDownPointY;private int mTouchSlop;private boolean hasSameWidth;private boolean hasIndicator;private boolean hasCurtain;private boolean hasAtmospheric;private boolean isCyclic;private boolean isCurved;private boolean isClick;private boolean isForceFinishScroll;private int centerRectColor;// 中间矩形的颜色private int centerLineColor;// 中间线的颜色private int centerLineWidth;// 中间线的粗细private boolean centerLineIsShow;// 中间线是否展示private boolean centerRectIsShow;// 中间线是否展示public WheelPicker(Context context) {this(context, null);}public WheelPicker(Context context, AttributeSet attrs) {super(context, attrs);this.mHandler = new Handler();this.mMinimumVelocity = 50;this.mMaximumVelocity = 8000;this.mTouchSlop = 8;TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WheelPicker);this.mData = new ArrayList<>();this.mItemTextSize = typedArray.getDimensionPixelSize(R.styleable.WheelPicker_wheel_item_text_size, dp2px(context, 18));this.mVisibleItemCount = typedArray.getInt(R.styleable.WheelPicker_wheel_visible_item_count, 7);this.mSelectedItemPosition = typedArray.getInt(R.styleable.WheelPicker_wheel_selected_item_position, 0);this.hasSameWidth = typedArray.getBoolean(R.styleable.WheelPicker_wheel_same_width, false);this.mTextMaxWidthPosition = typedArray.getInt(R.styleable.WheelPicker_wheel_maximum_width_text_position, -1);this.mMaxWidthText = typedArray.getString(R.styleable.WheelPicker_wheel_maximum_width_text);this.label = typedArray.getString(R.styleable.WheelPicker_wheel_label);this.mSelectedItemTextColor = typedArray.getColor(R.styleable.WheelPicker_wheel_selected_item_text_color, -1);this.mItemTextColor = typedArray.getColor(R.styleable.WheelPicker_wheel_item_text_color, -7829368);this.mItemSpace = typedArray.getDimensionPixelSize(R.styleable.WheelPicker_wheel_item_space, dp2px(context, 12));this.isCyclic = typedArray.getBoolean(R.styleable.WheelPicker_wheel_cyclic, false);this.hasIndicator = typedArray.getBoolean(R.styleable.WheelPicker_wheel_indicator, false);this.mIndicatorColor = typedArray.getColor(R.styleable.WheelPicker_wheel_indicator_color, -1166541);this.mIndicatorSize = typedArray.getDimensionPixelSize(R.styleable.WheelPicker_wheel_indicator_size, dp2px(context, 2));this.hasCurtain = typedArray.getBoolean(R.styleable.WheelPicker_wheel_curtain, false);this.mCurtainColor = typedArray.getColor(R.styleable.WheelPicker_wheel_curtain_color, -1996488705);this.hasAtmospheric = typedArray.getBoolean(R.styleable.WheelPicker_wheel_atmospheric, false);this.isCurved = typedArray.getBoolean(R.styleable.WheelPicker_wheel_curved, false);this.mItemAlign = typedArray.getInt(R.styleable.WheelPicker_wheel_item_align, 0);typedArray.recycle();this.updateVisibleItemCount();this.mPaint = new Paint(69);this.mPaint.setTextSize((float) this.mItemTextSize);this.updateItemTextAlign();this.computeTextSize();this.mScroller = new Scroller(this.getContext());if (VERSION.SDK_INT >= 4) {ViewConfiguration conf = ViewConfiguration.get(this.getContext());this.mMinimumVelocity = conf.getScaledMinimumFlingVelocity();this.mMaximumVelocity = conf.getScaledMaximumFlingVelocity();this.mTouchSlop = conf.getScaledTouchSlop();}if (TextUtils.isEmpty(label)) {label = "";}this.mRectDrawn = new Rect();this.mRectIndicatorHead = new Rect();this.mRectIndicatorFoot = new Rect();this.mRectCurrentItem = new Rect();this.mCamera = new Camera();this.mMatrixRotate = new Matrix();this.mMatrixDepth = new Matrix();}private void updateVisibleItemCount() {if (this.mVisibleItemCount < 2) {throw new ArithmeticException("Wheel's visible item count can not be less than 2!");} else {if (this.mVisibleItemCount % 2 == 0) {this.mVisibleItemCount++;}this.mDrawnItemCount = this.mVisibleItemCount + 2;this.mHalfDrawnItemCount = this.mDrawnItemCount / 2;}}private void computeTextSize() {this.mTextMaxWidth = this.mTextMaxHeight = 0;if (this.hasSameWidth) {this.mTextMaxWidth = (int) this.mPaint.measureText(String.valueOf(this.mData.get(0)));} else if (this.isPosInRang(this.mTextMaxWidthPosition)) {this.mTextMaxWidth = (int) this.mPaint.measureText(String.valueOf(this.mData.get(this.mTextMaxWidthPosition)));} else {if (!TextUtils.isEmpty(this.mMaxWidthText)) {this.mTextMaxWidth = (int) this.mPaint.measureText(this.mMaxWidthText);} else {for (WheelBean bean : this.mData) {String text = String.valueOf(bean);this.mTextMaxWidth = (int) Math.max(mTextMaxWidth, mPaint.measureText(text));}}}Paint.FontMetrics metrics = this.mPaint.getFontMetrics();this.mTextMaxHeight = (int) (metrics.bottom - metrics.top);}private void updateItemTextAlign() {switch (this.mItemAlign) {case 1:this.mPaint.setTextAlign(Align.LEFT);break;case 2:this.mPaint.setTextAlign(Align.RIGHT);break;default:this.mPaint.setTextAlign(Align.CENTER);}}protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int modeWidth = MeasureSpec.getMode(widthMeasureSpec);int modeHeight = MeasureSpec.getMode(heightMeasureSpec);int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);int resultWidth = this.mTextMaxWidth;int resultHeight = this.mTextMaxHeight * this.mVisibleItemCount + this.mItemSpace * (this.mVisibleItemCount - 1);if (this.isCurved) {resultHeight = (int) ((double) (2 * resultHeight) / Math.PI);}resultWidth += this.getPaddingLeft() + this.getPaddingRight();resultHeight += this.getPaddingTop() + this.getPaddingBottom();resultWidth = this.measureSize(modeWidth, sizeWidth, resultWidth);resultHeight = this.measureSize(modeHeight, sizeHeight, resultHeight);this.setMeasuredDimension(resultWidth, resultHeight);}private int measureSize(int mode, int sizeExpect, int sizeActual) {int realSize;if (mode == 1073741824) {realSize = sizeExpect;} else {realSize = sizeActual;if (mode == Integer.MIN_VALUE) {realSize = Math.min(sizeActual, sizeExpect);}}return realSize;}protected void onSizeChanged(int w, int h, int oldW, int oldH) {this.mRectDrawn.set(this.getPaddingLeft(), this.getPaddingTop(), this.getWidth() - this.getPaddingRight(), this.getHeight() - this.getPaddingBottom());this.mWheelCenterX = this.mRectDrawn.centerX();this.mWheelCenterY = this.mRectDrawn.centerY();this.computeDrawnCenter();this.mHalfWheelHeight = this.mRectDrawn.height() / 2;this.mItemHeight = this.mRectDrawn.height() / this.mVisibleItemCount;this.mHalfItemHeight = this.mItemHeight / 2;this.computeFlingLimitY();this.computeIndicatorRect();this.computeCurrentItemRect();}private void computeDrawnCenter() {switch (this.mItemAlign) {case 1:this.mDrawnCenterX = this.mRectDrawn.left;break;case 2:this.mDrawnCenterX = this.mRectDrawn.right;break;default:this.mDrawnCenterX = this.mWheelCenterX;}this.mDrawnCenterY = (int) ((float) this.mWheelCenterY - (this.mPaint.ascent() + this.mPaint.descent()) / 2.0F);}private void computeFlingLimitY() {int currentItemOffset = this.mSelectedItemPosition * this.mItemHeight;this.mMinFlingY = this.isCyclic " />Integer.MIN_VALUE : -this.mItemHeight * (this.mData.size() - 1) + currentItemOffset;this.mMaxFlingY = this.isCyclic ? Integer.MAX_VALUE : currentItemOffset;}private void computeIndicatorRect() {if (this.hasIndicator) {int halfIndicatorSize = this.mIndicatorSize / 2;int indicatorHeadCenterY = this.mWheelCenterY + this.mHalfItemHeight;int indicatorFootCenterY = this.mWheelCenterY - this.mHalfItemHeight;this.mRectIndicatorHead.set(this.mRectDrawn.left, indicatorHeadCenterY - halfIndicatorSize, this.mRectDrawn.right, indicatorHeadCenterY + halfIndicatorSize);this.mRectIndicatorFoot.set(this.mRectDrawn.left, indicatorFootCenterY - halfIndicatorSize, this.mRectDrawn.right, indicatorFootCenterY + halfIndicatorSize);}}private void computeCurrentItemRect() {if (this.hasCurtain || this.mSelectedItemTextColor != -1) {this.mRectCurrentItem.set(this.mRectDrawn.left, this.mWheelCenterY - this.mHalfItemHeight, this.mRectDrawn.right, this.mWheelCenterY + this.mHalfItemHeight);}}protected void onDraw(@NonNull Canvas canvas) {if (null != this.mOnWheelChangeListener) {this.mOnWheelChangeListener.onWheelScrolled(this.mScrollOffsetY);}int drawnDataStartPos = -this.mScrollOffsetY / this.mItemHeight - this.mHalfDrawnItemCount;int drawnDataPos = drawnDataStartPos + this.mSelectedItemPosition;for (int drawnOffsetPos = -this.mHalfDrawnItemCount; drawnDataPos < drawnDataStartPos + this.mSelectedItemPosition + this.mDrawnItemCount; ++drawnOffsetPos) {// 绘制中间的矩形drawCenterRect(canvas, drawnOffsetPos);String data = "";int mDrawnItemCenterY;if (this.isCyclic) {mDrawnItemCenterY = drawnDataPos % this.mData.size();mDrawnItemCenterY = mDrawnItemCenterY < 0 ? mDrawnItemCenterY + this.mData.size() : mDrawnItemCenterY;data = String.valueOf(this.mData.get(mDrawnItemCenterY));} else if (this.isPosInRang(drawnDataPos)) {data = String.valueOf(this.mData.get(drawnDataPos));}this.mPaint.setColor(this.mItemTextColor);this.mPaint.setStyle(Style.FILL);mDrawnItemCenterY = this.mDrawnCenterY + drawnOffsetPos * this.mItemHeight + this.mScrollOffsetY % this.mItemHeight;int distanceToCenter = 0;int lineCenterY;if (this.isCurved) {float ratio = (float) (this.mDrawnCenterY - Math.abs(this.mDrawnCenterY - mDrawnItemCenterY) - this.mRectDrawn.top) * 1.0F / (float) (this.mDrawnCenterY - this.mRectDrawn.top);lineCenterY = 0;if (mDrawnItemCenterY > this.mDrawnCenterY) {lineCenterY = 1;} else if (mDrawnItemCenterY < this.mDrawnCenterY) {lineCenterY = -1;}float degree = -(1.0F - ratio) * 90.0F * (float) lineCenterY;if (degree < -90.0F) {degree = -90.0F;}if (degree > 90.0F) {degree = 90.0F;}distanceToCenter = this.computeSpace((int) degree);int transX = this.mWheelCenterX;switch (this.mItemAlign) {case 1:transX = this.mRectDrawn.left;break;case 2:transX = this.mRectDrawn.right;}int transY = this.mWheelCenterY - distanceToCenter;this.mCamera.save();this.mCamera.rotateX(degree);this.mCamera.getMatrix(this.mMatrixRotate);this.mCamera.restore();this.mMatrixRotate.preTranslate((float) (-transX), (float) (-transY));this.mMatrixRotate.postTranslate((float) transX, (float) transY);this.mCamera.save();this.mCamera.translate(0.0F, 0.0F, (float) this.computeDepth((int) degree));this.mCamera.getMatrix(this.mMatrixDepth);this.mCamera.restore();this.mMatrixDepth.preTranslate((float) (-transX), (float) (-transY));this.mMatrixDepth.postTranslate((float) transX, (float) transY);this.mMatrixRotate.postConcat(this.mMatrixDepth);}int drawnCenterY;if (this.hasAtmospheric) {drawnCenterY = (int) ((float) (this.mDrawnCenterY - Math.abs(this.mDrawnCenterY - mDrawnItemCenterY)) * 1.0F / (float) this.mDrawnCenterY * 255.0F);drawnCenterY = Math.max(drawnCenterY, 0);this.mPaint.setAlpha(drawnCenterY);}drawnCenterY = this.isCurved ? this.mDrawnCenterY - distanceToCenter : mDrawnItemCenterY;if (this.mSelectedItemTextColor != -1) {canvas.save();if (this.isCurved) {canvas.concat(this.mMatrixRotate);}canvas.clipRect(this.mRectCurrentItem, Op.DIFFERENCE);canvas.drawText(data, (float) this.mDrawnCenterX, (float) drawnCenterY, this.mPaint);canvas.restore();this.mPaint.setColor(this.mSelectedItemTextColor);canvas.save();if (this.isCurved) {canvas.concat(this.mMatrixRotate);}canvas.clipRect(this.mRectCurrentItem);canvas.drawText(data, (float) this.mDrawnCenterX, (float) drawnCenterY, this.mPaint);canvas.restore();} else {canvas.save();canvas.clipRect(this.mRectDrawn);if (this.isCurved) {canvas.concat(this.mMatrixRotate);}canvas.drawText(data, (float) this.mDrawnCenterX, (float) drawnCenterY, this.mPaint);canvas.restore();}// 绘制中间线drawCenterLine(canvas, drawnOffsetPos);drawnDataPos++;}if (this.hasCurtain) {this.mPaint.setColor(this.mCurtainColor);this.mPaint.setStyle(Style.FILL);canvas.drawRect(this.mRectCurrentItem, this.mPaint);}if (this.hasIndicator) {this.mPaint.setColor(this.mIndicatorColor);this.mPaint.setStyle(Style.FILL);canvas.drawRect(this.mRectIndicatorHead, this.mPaint);canvas.drawRect(this.mRectIndicatorFoot, this.mPaint);}}// 绘制中间选择线private void drawCenterRect(Canvas canvas, int drawnOffsetPos) {if (!centerRectIsShow) {return;}if (drawnOffsetPos == 0) {canvas.save();canvas.clipRect(this.mRectDrawn);this.mPaint.setColor(centerRectColor);this.mPaint.setStyle(Style.FILL);this.mPaint.setStrokeWidth(centerLineWidth);float startY = mWheelCenterY - this.mHalfItemHeight;float endY = mWheelCenterY - this.mHalfItemHeight + this.mItemHeight;canvas.drawRect((float) this.mRectDrawn.left, startY, (float) this.mRectDrawn.right, endY, this.mPaint);canvas.restore();}}// 绘制中间选择线private void drawCenterLine(Canvas canvas, int drawnOffsetPos) {if (!centerLineIsShow) {return;}if (drawnOffsetPos == 0) {canvas.save();canvas.clipRect(this.mRectDrawn);this.mPaint.setColor(centerLineColor);this.mPaint.setStyle(Style.STROKE);this.mPaint.setStrokeWidth(centerLineWidth);float startY = mWheelCenterY - this.mHalfItemHeight;float endY = mWheelCenterY - this.mHalfItemHeight + this.mItemHeight;canvas.drawLine((float) this.mRectDrawn.left, startY, (float) this.mRectDrawn.right, startY, this.mPaint);canvas.drawLine((float) this.mRectDrawn.left, endY, (float) this.mRectDrawn.right, endY, this.mPaint);canvas.restore();}}private boolean isPosInRang(int position) {return position >= 0 && position < this.mData.size();}private int computeSpace(int degree) {return (int) (Math.sin(Math.toRadians(degree)) * (double) this.mHalfWheelHeight);}private int computeDepth(int degree) {return (int) ((double) this.mHalfWheelHeight - Math.cos(Math.toRadians((double) degree)) * (double) this.mHalfWheelHeight);}public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (null != this.getParent()) {this.getParent().requestDisallowInterceptTouchEvent(true);}if (null == this.mTracker) {this.mTracker = VelocityTracker.obtain();} else {this.mTracker.clear();}this.mTracker.addMovement(event);if (!this.mScroller.isFinished()) {this.mScroller.abortAnimation();this.isForceFinishScroll = true;}this.mDownPointY = this.mLastPointY = (int) event.getY();break;case MotionEvent.ACTION_UP:if (null != this.getParent()) {this.getParent().requestDisallowInterceptTouchEvent(false);}if (!this.isClick) {this.mTracker.addMovement(event);if (VERSION.SDK_INT >= 4) {this.mTracker.computeCurrentVelocity(1000, (float) this.mMaximumVelocity);} else {this.mTracker.computeCurrentVelocity(1000);}this.isForceFinishScroll = false;int velocity = (int) this.mTracker.getYVelocity();if (Math.abs(velocity) > this.mMinimumVelocity) {this.mScroller.fling(0, this.mScrollOffsetY, 0, velocity, 0, 0, this.mMinFlingY, this.mMaxFlingY);this.mScroller.setFinalY(this.mScroller.getFinalY() + this.computeDistanceToEndPoint(this.mScroller.getFinalY() % this.mItemHeight));} else {this.mScroller.startScroll(0, this.mScrollOffsetY, 0, this.computeDistanceToEndPoint(this.mScrollOffsetY % this.mItemHeight));}if (!this.isCyclic) {if (this.mScroller.getFinalY() > this.mMaxFlingY) {this.mScroller.setFinalY(this.mMaxFlingY);} else if (this.mScroller.getFinalY() < this.mMinFlingY) {this.mScroller.setFinalY(this.mMinFlingY);}}this.mHandler.post(this);if (null != this.mTracker) {this.mTracker.recycle();this.mTracker = null;}}// 这里是否需要移动一段距离, 距离修正float moveFixUp = event.getY() - (float) this.mLastPointY;if (!(Math.abs(moveFixUp) < 1.0F)) {this.mScrollOffsetY = (int) ((float) this.mScrollOffsetY + moveFixUp);this.mLastPointY = (int) event.getY();this.invalidate();}break;case MotionEvent.ACTION_MOVE:if (Math.abs((float) this.mDownPointY - event.getY()) < (float) this.mTouchSlop) {this.isClick = true;} else {this.isClick = false;this.mTracker.addMovement(event);if (null != this.mOnWheelChangeListener) {this.mOnWheelChangeListener.onWheelScrollStateChanged(1);}// 这里是否需要移动一段距离, 距离修正float moveFixMove = event.getY() - (float) this.mLastPointY;if (!(Math.abs(moveFixMove) < 1.0F)) {this.mScrollOffsetY = (int) ((float) this.mScrollOffsetY + moveFixMove);this.mLastPointY = (int) event.getY();this.invalidate();}}break;case MotionEvent.ACTION_CANCEL:if (null != this.getParent()) {this.getParent().requestDisallowInterceptTouchEvent(false);}if (null != this.mTracker) {this.mTracker.recycle();this.mTracker = null;}}return true;}public void setCenterLineColor(int centerLineColor) {this.centerLineColor = centerLineColor;}public void setCenterRectColor(int centerRectColor) {this.centerRectColor = centerRectColor;}public void setCenterLineWidth(int centerLineWidth) {this.centerLineWidth = centerLineWidth;}public void setCenterLineIsShow(boolean centerLineIsShow) {this.centerLineIsShow = centerLineIsShow;}public void setCenterRectIsShow(boolean centerRectIsShow) {this.centerRectIsShow = centerRectIsShow;}private int computeDistanceToEndPoint(int remainder) {if (Math.abs(remainder) > this.mHalfItemHeight) {return this.mScrollOffsetY < 0 ? -this.mItemHeight - remainder : this.mItemHeight - remainder;} else {return -remainder;}}public void run() {if (null != this.mData && this.mData.size() != 0) {if (this.mScroller.isFinished() && !this.isForceFinishScroll) {if (this.mItemHeight == 0) {return;}int position = (-this.mScrollOffsetY / this.mItemHeight + this.mSelectedItemPosition) % this.mData.size();position = position < 0 ? position + this.mData.size() : position;this.mCurrentItemPosition = position;if (null != this.mOnItemSelectedListener) {this.mOnItemSelectedListener.onItemSelected(this, this.mData.get(position), position);}if (null != this.mOnWheelChangeListener) {this.mOnWheelChangeListener.onWheelSelected(position);this.mOnWheelChangeListener.onWheelScrollStateChanged(0);}}if (this.mScroller.computeScrollOffset()) {if (null != this.mOnWheelChangeListener) {this.mOnWheelChangeListener.onWheelScrollStateChanged(2);}this.mScrollOffsetY = this.mScroller.getCurrY();this.postInvalidate();this.mHandler.postDelayed(this, 16L);}}}// dp转pxprivate int dp2px(Context context, float value) {float scale = context.getResources().getDisplayMetrics().density;return (int) (value * scale + 0.5f);}public int getVisibleItemCount() {return this.mVisibleItemCount;}public void setVisibleItemCount(int count) {this.mVisibleItemCount = count;this.updateVisibleItemCount();this.requestLayout();}public boolean isCyclic() {return this.isCyclic;}public void setCyclic(boolean isCyclic) {this.isCyclic = isCyclic;this.computeFlingLimitY();this.invalidate();}public void setLabel(String label) {this.label = label;}public void setOnItemSelectedListener(WheelPicker.OnItemSelectedListener listener) {this.mOnItemSelectedListener = listener;}public int getSelectedItemPosition() {return this.mSelectedItemPosition;}public void setSelectedItemPosition(int position) {position = Math.min(position, this.mData.size() - 1);position = Math.max(position, 0);this.mSelectedItemPosition = position;this.mCurrentItemPosition = position;this.mScrollOffsetY = 0;this.computeFlingLimitY();this.requestLayout();this.invalidate();}public int getCurrentItemPosition() {return this.mCurrentItemPosition;}public List<WheelBean> getData() {return this.mData;}public void setData(List<WheelBean> data) {if (null == data) {throw new NullPointerException("WheelPicker's data can not be null!");} else {this.mData = data;if (this.mSelectedItemPosition <= data.size() - 1 && this.mCurrentItemPosition <= data.size() - 1) {this.mSelectedItemPosition = this.mCurrentItemPosition;} else {this.mSelectedItemPosition = this.mCurrentItemPosition = data.size() - 1;}this.mScrollOffsetY = 0;this.computeTextSize();this.computeFlingLimitY();this.requestLayout();this.invalidate();}}public void setSameWidth(boolean hasSameWidth) {this.hasSameWidth = hasSameWidth;this.computeTextSize();this.requestLayout();this.invalidate();}public boolean hasSameWidth() {return this.hasSameWidth;}public void setOnWheelChangeListener(WheelPicker.OnWheelChangeListener listener) {this.mOnWheelChangeListener = listener;}public String getMaximumWidthText() {return this.mMaxWidthText;}public void setMaximumWidthText(String text) {if (null == text) {throw new NullPointerException("Maximum width text can not be null!");} else {this.mMaxWidthText = text;this.computeTextSize();this.requestLayout();this.invalidate();}}public int getMaximumWidthTextPosition() {return this.mTextMaxWidthPosition;}public void setMaximumWidthTextPosition(int position) {if (!this.isPosInRang(position)) {throw new ArrayIndexOutOfBoundsException("Maximum width text Position must in [0, " + this.mData.size() + "), but current is " + position);} else {this.mTextMaxWidthPosition = position;this.computeTextSize();this.requestLayout();this.invalidate();}}public int getSelectedItemTextColor() {return this.mSelectedItemTextColor;}public void setSelectedItemTextColor(int color) {this.mSelectedItemTextColor = color;this.computeCurrentItemRect();this.invalidate();}public int getItemTextColor() {return this.mItemTextColor;}public void setItemTextColor(int color) {this.mItemTextColor = color;this.invalidate();}public int getItemTextSize() {return this.mItemTextSize;}public void setItemTextSize(int size) {this.mItemTextSize = size;this.mPaint.setTextSize((float) this.mItemTextSize);this.computeTextSize();this.requestLayout();this.invalidate();}public int getItemSpace() {return this.mItemSpace;}public void setItemSpace(int space) {this.mItemSpace = space;this.requestLayout();this.invalidate();}public void setIndicator(boolean hasIndicator) {this.hasIndicator = hasIndicator;this.computeIndicatorRect();this.invalidate();}public boolean hasIndicator() {return this.hasIndicator;}public int getIndicatorSize() {return this.mIndicatorSize;}public void setIndicatorSize(int size) {this.mIndicatorSize = size;this.computeIndicatorRect();this.invalidate();}public int getIndicatorColor() {return this.mIndicatorColor;}public void setIndicatorColor(int color) {this.mIndicatorColor = color;this.invalidate();}public void setCurtain(boolean hasCurtain) {this.hasCurtain = hasCurtain;this.computeCurrentItemRect();this.invalidate();}public boolean hasCurtain() {return this.hasCurtain;}public int getCurtainColor() {return this.mCurtainColor;}public void setCurtainColor(int color) {this.mCurtainColor = color;this.invalidate();}public void setAtmospheric(boolean hasAtmospheric) {this.hasAtmospheric = hasAtmospheric;this.invalidate();}public boolean hasAtmospheric() {return this.hasAtmospheric;}public boolean isCurved() {return this.isCurved;}public void setCurved(boolean isCurved) {this.isCurved = isCurved;this.requestLayout();this.invalidate();}public int getItemAlign() {return this.mItemAlign;}public void setItemAlign(int align) {this.mItemAlign = align;this.updateItemTextAlign();this.computeDrawnCenter();this.invalidate();}public Typeface getTypeface() {return null != this.mPaint ? this.mPaint.getTypeface() : null;}public void setTypeface(Typeface tf) {if (null != this.mPaint) {this.mPaint.setTypeface(tf);}this.computeTextSize();this.requestLayout();this.invalidate();}public interface OnWheelChangeListener {void onWheelScrolled(int var1);void onWheelSelected(int var1);void onWheelScrollStateChanged(int var1);}public interface OnItemSelectedListener {void onItemSelected(WheelPicker wheelPicker, WheelBean wheelBean, int position);}}

第02节 实体类 WheelBean

位置

src/java/view.wheel.WheelBean.java

代码

package view.wheel;import androidx.annotation.NonNull;public class WheelBean {private int itemNumber;private String itemLabel;public WheelBean() {}public WheelBean(int itemNumber, String itemLabel) {this.itemNumber = itemNumber;this.itemLabel = itemLabel;}public int getItemNumber() {return itemNumber;}public void setItemNumber(int itemNumber) {this.itemNumber = itemNumber;}public String getItemLabel() {return itemLabel;}public void setItemLabel(String itemLabel) {this.itemLabel = itemLabel;}@NonNull@Overridepublic String toString() {return itemNumber + itemLabel;}}

第03节 接口类 IWheelPicker

位置

src/java/view.wheel.IWheelPicker.java

代码

package view.wheel;import android.graphics.Typeface;import java.util.List;public interface IWheelPicker {int getVisibleItemCount();void setVisibleItemCount(int var1);boolean isCyclic();void setCyclic(boolean var1);void setOnItemSelectedListener(WheelPicker.OnItemSelectedListener var1);void setSelectedItemPosition(int var1);int getCurrentItemPosition();List<WheelBean> getData();void setData(List<WheelBean> var1);void setMaximumWidthText(String var1);int getSelectedItemTextColor();void setSelectedItemTextColor(int var1);int getItemTextColor();void setItemTextColor(int var1);int getItemTextSize();void setItemTextSize(int var1);int getItemSpace();void setItemSpace(int var1);void setIndicator(boolean var1);boolean hasIndicator();int getIndicatorSize();void setIndicatorSize(int var1);void setIndicatorColor(int var1);void setCurtain(boolean var1);boolean hasCurtain();int getCurtainColor();void setCurtainColor(int var1);void setAtmospheric(boolean var1);boolean hasAtmospheric();boolean isCurved();void setCurved(boolean var1);int getItemAlign();void setItemAlign(int var1);Typeface getTypeface();void setTypeface(Typeface var1);}

第04节 原子时间类 DateTimePickerView

位置

src/java/view.wheel.atom.time.DateTimePickerView.java

代码

package view.wheel.atom.time;import android.content.Context;import android.graphics.Typeface;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.View;import android.widget.LinearLayout;import view.wheel.WheelBean;import view.wheel.WheelPicker;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import java.util.Locale;public class DateTimePickerView extends LinearLayout implements WheelPicker.OnItemSelectedListener {private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss", Locale.getDefault());private PickerYear mPickerYear;private PickerMonth mPickerMonth;private PickerDay mPickerDay;private PickerHour mPickerHour;private PickerMinute mPickerMinute;private PickerSecond mPickerSecond;private DateTimePickerView.OnDateSelectedListener onDateSelectedListener;private int mYear;private int mMonth;private int mDay;private int mHour;private int mMinute;private int mSecond;public void setOnDateSelectedListener(OnDateSelectedListener onDateSelectedListener) {this.onDateSelectedListener = onDateSelectedListener;}public DateTimePickerView(Context context) {this(context, null);}public DateTimePickerView(Context context, AttributeSet attrs) {super(context, attrs);LayoutInflater.from(context).inflate(R.layout.view_picker_time_date, this);this.mPickerYear = findViewById(R.id.picker_year);this.mPickerMonth = findViewById(R.id.picker_month);this.mPickerDay = findViewById(R.id.picker_day);this.mPickerHour = findViewById(R.id.picker_hour);this.mPickerMinute = findViewById(R.id.picker_minute);this.mPickerSecond = findViewById(R.id.picker_second);this.setMaximumWidthTextYear();this.mPickerMonth.setMaximumWidthText("00");this.mPickerDay.setMaximumWidthText("00");this.mPickerHour.setMaximumWidthText("00");this.mPickerMinute.setMaximumWidthText("00");this.mPickerSecond.setMaximumWidthText("00");this.mYear = this.mPickerYear.getCurrentYear();this.mMonth = this.mPickerMonth.getCurrentMonth();this.mDay = this.mPickerDay.getCurrentDay();this.mHour = this.mPickerHour.getCurrentHour();this.mMinute = this.mPickerMinute.getCurrentMinute();this.mSecond = this.mPickerSecond.getCurrentSecond();this.mPickerYear.setOnItemSelectedListener(this);this.mPickerMonth.setOnItemSelectedListener(this);this.mPickerDay.setOnItemSelectedListener(this);this.mPickerHour.setOnItemSelectedListener(this);this.mPickerMinute.setOnItemSelectedListener(this);this.mPickerSecond.setOnItemSelectedListener(this);}private void setMaximumWidthTextYear() {List<WheelBean> years = this.mPickerYear.getData();String lastYear = String.valueOf(years.get(years.size() - 1));StringBuilder sb = new StringBuilder();for (int i = 0; i < lastYear.length(); ++i) {sb.append("0");}this.mPickerYear.setMaximumWidthText(sb.toString());}@Overridepublic void onItemSelected(WheelPicker picker, WheelBean wheelBean, int position) {if (picker.getId() == R.id.picker_year) {this.mYear = this.mPickerYear.getCurrentYear();this.mPickerDay.setYear(this.mYear);} else if (picker.getId() == R.id.picker_month) {this.mMonth = this.mPickerMonth.getCurrentMonth();this.mPickerDay.setMonth(this.mMonth);} else if (picker.getId() == R.id.picker_day) {this.mDay = this.mPickerDay.getCurrentDay();} else if (picker.getId() == R.id.picker_hour) {this.mHour = this.mPickerHour.getCurrentHour();} else if (picker.getId() == R.id.picker_minute) {this.mMinute = this.mPickerMinute.getCurrentMinute();} else if (picker.getId() == R.id.picker_second) {this.mSecond = this.mPickerSecond.getCurrentSecond();}String dateTime = this.mYear + "年" + this.mMonth + "月" + this.mDay + "日 " + this.mHour + ":" + this.mMinute + ":" + this.mSecond;if (onDateSelectedListener != null) {try {onDateSelectedListener.onDateSelected(this, SDF.parse(dateTime), dateTime);} catch (ParseException parseException) {parseException.printStackTrace();}}}// 设置显示的类型public void setShowType(boolean[] array) {if (array == null || array.length != 6) {throw new IllegalArgumentException("数组的长度必须为6");}this.mPickerYear.setVisibility(array[0] ? View.VISIBLE : View.GONE);this.mPickerMonth.setVisibility(array[1] ? View.VISIBLE : View.GONE);this.mPickerDay.setVisibility(array[2] ? View.VISIBLE : View.GONE);this.mPickerHour.setVisibility(array[3] ? View.VISIBLE : View.GONE);this.mPickerMinute.setVisibility(array[4] ? View.VISIBLE : View.GONE);this.mPickerSecond.setVisibility(array[5] ? View.VISIBLE : View.GONE);}public void setVisibleItemCount(int count) {this.mPickerYear.setVisibleItemCount(count);this.mPickerMonth.setVisibleItemCount(count);this.mPickerDay.setVisibleItemCount(count);this.mPickerHour.setVisibleItemCount(count);this.mPickerMinute.setVisibleItemCount(count);this.mPickerSecond.setVisibleItemCount(count);}public boolean isCyclic() {boolean cyclicYear = this.mPickerYear.isCyclic();boolean cyclicMonth = this.mPickerMonth.isCyclic();boolean cyclicDay = this.mPickerDay.isCyclic();boolean cyclicHour = this.mPickerHour.isCyclic();boolean cyclicMinute = this.mPickerMinute.isCyclic();boolean cyclicSecond = this.mPickerSecond.isCyclic();boolean result = cyclicYear && cyclicMonth && cyclicDay && cyclicHour && cyclicMinute && cyclicSecond;return result;}public void setCenterLineColor(int centerLineColor) {this.mPickerYear.setCenterLineColor(centerLineColor);this.mPickerMonth.setCenterLineColor(centerLineColor);this.mPickerDay.setCenterLineColor(centerLineColor);this.mPickerHour.setCenterLineColor(centerLineColor);this.mPickerMinute.setCenterLineColor(centerLineColor);this.mPickerSecond.setCenterLineColor(centerLineColor);}// 这里需要设置透明度, 才能有效果。不能用全色, 否则UI效果异常public void setCenterRectColor(int centerRectColor) {this.mPickerYear.setCenterRectColor(centerRectColor);this.mPickerMonth.setCenterRectColor(centerRectColor);this.mPickerDay.setCenterRectColor(centerRectColor);this.mPickerHour.setCenterRectColor(centerRectColor);this.mPickerMinute.setCenterRectColor(centerRectColor);this.mPickerSecond.setCenterRectColor(centerRectColor);}public void setCenterRectIsShow(boolean centerRectIsShow) {this.mPickerYear.setCenterRectIsShow(centerRectIsShow);this.mPickerMonth.setCenterRectIsShow(centerRectIsShow);this.mPickerDay.setCenterRectIsShow(centerRectIsShow);this.mPickerHour.setCenterRectIsShow(centerRectIsShow);this.mPickerMinute.setCenterRectIsShow(centerRectIsShow);this.mPickerSecond.setCenterRectIsShow(centerRectIsShow);}public void setCenterLineWidth(int centerLineWidth) {this.mPickerYear.setCenterLineWidth(centerLineWidth);this.mPickerMonth.setCenterLineWidth(centerLineWidth);this.mPickerDay.setCenterLineWidth(centerLineWidth);this.mPickerHour.setCenterLineWidth(centerLineWidth);this.mPickerMinute.setCenterLineWidth(centerLineWidth);this.mPickerSecond.setCenterLineWidth(centerLineWidth);}public void setCenterLineIsShow(boolean centerLineIsShow) {this.mPickerYear.setCenterLineIsShow(centerLineIsShow);this.mPickerMonth.setCenterLineIsShow(centerLineIsShow);this.mPickerDay.setCenterLineIsShow(centerLineIsShow);this.mPickerHour.setCenterLineIsShow(centerLineIsShow);this.mPickerMinute.setCenterLineIsShow(centerLineIsShow);this.mPickerSecond.setCenterLineIsShow(centerLineIsShow);}public void setCyclic(boolean isCyclic) {this.mPickerYear.setCyclic(isCyclic);this.mPickerMonth.setCyclic(isCyclic);this.mPickerDay.setCyclic(isCyclic);this.mPickerHour.setCyclic(isCyclic);this.mPickerMinute.setCyclic(isCyclic);this.mPickerSecond.setCyclic(isCyclic);}public void setItemTextColorSelected(int color) {this.mPickerYear.setSelectedItemTextColor(color);this.mPickerMonth.setSelectedItemTextColor(color);this.mPickerDay.setSelectedItemTextColor(color);this.mPickerHour.setSelectedItemTextColor(color);this.mPickerMinute.setSelectedItemTextColor(color);this.mPickerSecond.setSelectedItemTextColor(color);}public void setItemTextColorUnSelect(int color) {this.mPickerYear.setItemTextColor(color);this.mPickerMonth.setItemTextColor(color);this.mPickerDay.setItemTextColor(color);this.mPickerHour.setItemTextColor(color);this.mPickerMinute.setItemTextColor(color);this.mPickerSecond.setItemTextColor(color);}public void setItemTextSize(int size) {this.mPickerYear.setItemTextSize(size);this.mPickerMonth.setItemTextSize(size);this.mPickerDay.setItemTextSize(size);this.mPickerHour.setItemTextSize(size);this.mPickerMinute.setItemTextSize(size);this.mPickerSecond.setItemTextSize(size);}public void setItemSpace(int space) {this.mPickerYear.setItemSpace(space);this.mPickerMonth.setItemSpace(space);this.mPickerDay.setItemSpace(space);this.mPickerHour.setItemSpace(space);this.mPickerMinute.setItemSpace(space);this.mPickerSecond.setItemSpace(space);}public void setIndicator(boolean hasIndicator) {this.mPickerYear.setIndicator(hasIndicator);this.mPickerMonth.setIndicator(hasIndicator);this.mPickerDay.setIndicator(hasIndicator);this.mPickerHour.setIndicator(hasIndicator);this.mPickerMinute.setIndicator(hasIndicator);this.mPickerSecond.setIndicator(hasIndicator);}public boolean hasIndicator() {boolean indicatorYear = this.mPickerYear.hasIndicator();boolean indicatorMonth = this.mPickerMonth.hasIndicator();boolean indicatorDay = this.mPickerDay.hasIndicator();boolean indicatorHour = this.mPickerHour.hasIndicator();boolean indicatorMinute = this.mPickerMinute.hasIndicator();boolean indicatorSecond = this.mPickerSecond.hasIndicator();boolean result = indicatorYear && indicatorMonth && indicatorDay && indicatorHour && indicatorMinute && indicatorSecond;return result;}public void setIndicatorSize(int size) {this.mPickerYear.setIndicatorSize(size);this.mPickerMonth.setIndicatorSize(size);this.mPickerDay.setIndicatorSize(size);this.mPickerHour.setIndicatorSize(size);this.mPickerMinute.setIndicatorSize(size);this.mPickerSecond.setIndicatorSize(size);}public void setIndicatorColor(int color) {this.mPickerYear.setIndicatorColor(color);this.mPickerMonth.setIndicatorColor(color);this.mPickerDay.setIndicatorColor(color);this.mPickerHour.setIndicatorColor(color);this.mPickerMinute.setIndicatorColor(color);this.mPickerSecond.setIndicatorColor(color);}public void setCurtain(boolean hasCurtain) {this.mPickerYear.setCurtain(hasCurtain);this.mPickerMonth.setCurtain(hasCurtain);this.mPickerDay.setCurtain(hasCurtain);this.mPickerHour.setCurtain(hasCurtain);this.mPickerMinute.setCurtain(hasCurtain);this.mPickerSecond.setCurtain(hasCurtain);}public boolean isCurtain() {boolean curtainYear = this.mPickerYear.hasCurtain();boolean curtainMonth = this.mPickerMonth.hasCurtain();boolean curtainDay = this.mPickerDay.hasCurtain();boolean curtainHour = this.mPickerHour.hasCurtain();boolean curtainMinute = this.mPickerMinute.hasCurtain();boolean curtainSecond = this.mPickerSecond.hasCurtain();boolean result = curtainYear && curtainMonth && curtainDay && curtainHour && curtainMinute && curtainSecond;return result;}public void setCurtainColor(int color) {this.mPickerYear.setCurtainColor(color);this.mPickerMonth.setCurtainColor(color);this.mPickerDay.setCurtainColor(color);this.mPickerHour.setCurtainColor(color);this.mPickerMinute.setCurtainColor(color);this.mPickerSecond.setCurtainColor(color);}public void setAtmospheric(boolean hasAtmospheric) {this.mPickerYear.setAtmospheric(hasAtmospheric);this.mPickerMonth.setAtmospheric(hasAtmospheric);this.mPickerDay.setAtmospheric(hasAtmospheric);this.mPickerHour.setAtmospheric(hasAtmospheric);this.mPickerMinute.setAtmospheric(hasAtmospheric);this.mPickerSecond.setAtmospheric(hasAtmospheric);}public boolean hasAtmospheric() {boolean hasAtmosphericYear = this.mPickerYear.hasAtmospheric();boolean hasAtmosphericMonth = this.mPickerMonth.hasAtmospheric();boolean hasAtmosphericDay = this.mPickerDay.hasAtmospheric();boolean hasAtmosphericHour = this.mPickerHour.hasAtmospheric();boolean hasAtmosphericMinute = this.mPickerMinute.hasAtmospheric();boolean hasAtmosphericSecond = this.mPickerSecond.hasAtmospheric();boolean result = hasAtmosphericYear && hasAtmosphericMonth && hasAtmosphericDay && hasAtmosphericHour && hasAtmosphericMinute && hasAtmosphericSecond;return result;}// 判断是否存在弧度public boolean isCurved() {boolean curvedYear = this.mPickerYear.isCurved();boolean curvedMonth = this.mPickerMonth.isCurved();boolean curvedDay = this.mPickerDay.isCurved();boolean curvedHour = this.mPickerHour.isCurved();boolean curvedMinute = this.mPickerMinute.isCurved();boolean curvedSecond = this.mPickerSecond.isCurved();boolean result = curvedYear && curvedMonth && curvedDay && curvedHour && curvedMinute && curvedSecond;return result;}// 设置是否存在弧度public void setCurved(boolean isCurved) {this.mPickerYear.setCurved(isCurved);this.mPickerMonth.setCurved(isCurved);this.mPickerDay.setCurved(isCurved);this.mPickerHour.setCurved(isCurved);this.mPickerMinute.setCurved(isCurved);this.mPickerSecond.setCurved(isCurved);}// 设置字体样式public void setTypeface(Typeface typeface) {this.mPickerYear.setTypeface(typeface);this.mPickerMonth.setTypeface(typeface);this.mPickerDay.setTypeface(typeface);this.mPickerHour.setTypeface(typeface);this.mPickerMinute.setTypeface(typeface);this.mPickerSecond.setTypeface(typeface);}public interface OnDateSelectedListener {void onDateSelected(DateTimePickerView view, Date date, String format);}}

第05节 原子时间类 PickerYear

位置

src/java/view.wheel.atom.time.PickerYear.java

代码

package view.wheel.atom.time;import android.content.Context;import android.util.AttributeSet;import view.wheel.WheelBean;import view.wheel.WheelPicker;import java.util.ArrayList;import java.util.Calendar;import java.util.List;// 选择器(年份)public class PickerYear extends WheelPicker {private int mYearStart;private int mYearEnd;private int mSelectedYear;public PickerYear(Context context) {this(context, null);}public PickerYear(Context context, AttributeSet attrs) {super(context, attrs);mYearStart = 1000;mYearEnd = 3000;updateYears();mSelectedYear = Calendar.getInstance().get(Calendar.YEAR);setSelectedItemPosition(mSelectedYear - this.mYearStart);}private void updateYears() {List<WheelBean> data = new ArrayList<>();for (int i = this.mYearStart; i <= this.mYearEnd; ++i) {WheelBean item = new WheelBean(i, label);data.add(item);}super.setData(data);}public int getYearStart() {return this.mYearStart;}public void setYearStart(int start) {this.mYearStart = start;this.mSelectedYear = this.getCurrentYear();this.updateYears();this.setSelectedItemPosition(this.mSelectedYear - this.mYearStart);}public int getCurrentYear() {return this.getData().get(this.getCurrentItemPosition()).getItemNumber();}}

第06节 原子时间类 PickerMonth

位置

src/java/view.wheel.atom.time.PickerMonth.java

代码

package view.wheel.atom.time;import android.content.Context;import android.util.AttributeSet;import view.wheel.WheelBean;import view.wheel.WheelPicker;import java.util.ArrayList;import java.util.Calendar;import java.util.List;// 选择器(月份)public class PickerMonth extends WheelPicker {private int mSelectedMonth;public PickerMonth(Context context) {this(context, null);}public PickerMonth(Context context, AttributeSet attrs) {super(context, attrs);List<WheelBean> data = new ArrayList<>();for (int i = 1; i <= 12; i++) {WheelBean item = new WheelBean(i, label);data.add(item);}super.setData(data);int mSelectedMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;setSelectedItemPosition(mSelectedMonth - 1);}public void setSelectedMonth(int month) {this.mSelectedMonth = month;this.setSelectedItemPosition(this.mSelectedMonth - 1);}public int getCurrentMonth() {return this.getData().get(this.getCurrentItemPosition()).getItemNumber();}}

第07节 原子时间类 PickerDay

位置

src/java/view.wheel.atom.time.PickerDay.java

代码

package view.wheel.atom.time;import android.content.Context;import android.util.AttributeSet;import view.wheel.WheelBean;import view.wheel.WheelPicker;import java.util.ArrayList;import java.util.Calendar;import java.util.HashMap;import java.util.List;import java.util.Map;// 选择器(日期)public class PickerDay extends WheelPicker {private static final Map<Integer, List<WheelBean>> mapData = new HashMap<>();private Calendar mCalendar;private int mYear;private int mMonth;private int mSelectedDay;public PickerDay(Context context) {this(context, null);}public PickerDay(Context context, AttributeSet attrs) {super(context, attrs);mCalendar = Calendar.getInstance();mYear = mCalendar.get(Calendar.YEAR);mMonth = mCalendar.get(Calendar.MONTH);updateMapData();mSelectedDay = this.mCalendar.get(Calendar.DAY_OF_MONTH);updateSelectedDay();}private void updateMapData() {this.mCalendar.set(Calendar.YEAR, this.mYear);this.mCalendar.set(Calendar.MONTH, this.mMonth);int mDate = this.mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH);List<WheelBean> dateList = mapData.get(mDate);if (null == dateList) {dateList = new ArrayList<>();for (int i = 1; i <= mDate; i++) {WheelBean item = new WheelBean(i, label);dateList.add(item);}mapData.put(mDate, dateList);}super.setData(dateList);}private void updateSelectedDay() {this.setSelectedItemPosition(this.mSelectedDay - 1);}public int getCurrentDay() {return this.getData().get(this.getCurrentItemPosition()).getItemNumber();}private void updateDays() {this.mCalendar.set(Calendar.YEAR, this.mYear);this.mCalendar.set(Calendar.MONTH, this.mMonth);int days = this.mCalendar.getActualMaximum(5);List<WheelBean> data = mapData.get(days);if (null == data) {data = new ArrayList<>();for (int i = 1; i <= days; ++i) {WheelBean item = new WheelBean(i, label);data.add(item);}mapData.put(days, data);}super.setData(data);}public void setYear(int year) {this.mYear = year;this.updateDays();}public void setMonth(int month) {this.mMonth = month - 1;this.updateDays();}}

第08节 原子时间类 PickerHour

位置

src/java/view.wheel.atom.time.PickerHour.java

代码

package view.wheel.atom.time;import android.content.Context;import android.util.AttributeSet;import view.wheel.WheelBean;import view.wheel.WheelPicker;import java.util.ArrayList;import java.util.Calendar;import java.util.List;// 选择器(小时)public class PickerHour extends WheelPicker {private int mHourStart;private int mHourEnd;private int mSelectedHour;public PickerHour(Context context) {this(context, null);}public PickerHour(Context context, AttributeSet attrs) {super(context, attrs);mHourStart = 0;mHourEnd = 23;updateHour();mSelectedHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);setSelectedItemPosition(mSelectedHour - this.mHourStart);}private void updateHour() {List<WheelBean> data = new ArrayList<>();for (int i = this.mHourStart; i <= this.mHourEnd; ++i) {WheelBean item = new WheelBean(i, label);data.add(item);}super.setData(data);}public int getHourStart() {return this.mHourStart;}public void setHourStart(int start) {this.mHourStart = start;this.mSelectedHour = this.getCurrentHour();this.updateHour();this.setSelectedItemPosition(this.mSelectedHour - this.mHourStart);}public int getCurrentHour() {return this.getData().get(this.getCurrentItemPosition()).getItemNumber();}}

第09节 原子时间类 PickerMinute

位置

src/java/view.wheel.atom.time.PickerMinute.java

代码

package view.wheel.atom.time;import android.content.Context;import android.util.AttributeSet;import view.wheel.WheelBean;import view.wheel.WheelPicker;import java.util.ArrayList;import java.util.Calendar;import java.util.List;// 选择器(分钟)public class PickerMinute extends WheelPicker {private int mMinuteStart;private int mMinuteEnd;private int mSelectedMinute;public PickerMinute(Context context) {this(context, null);}public PickerMinute(Context context, AttributeSet attrs) {super(context, attrs);mMinuteStart = 0;mMinuteEnd = 59;updateMinute();mSelectedMinute = Calendar.getInstance().get(Calendar.MINUTE);setSelectedItemPosition(mSelectedMinute - this.mMinuteStart);}private void updateMinute() {List<WheelBean> data = new ArrayList<>();for (int i = this.mMinuteStart; i <= this.mMinuteEnd; ++i) {WheelBean item = new WheelBean(i, label);data.add(item);}super.setData(data);}public int getMinuteStart() {return this.mMinuteStart;}public void setMinuteStart(int start) {this.mMinuteStart = start;this.mSelectedMinute = this.getCurrentMinute();this.updateMinute();this.setSelectedItemPosition(this.mSelectedMinute - this.mMinuteStart);}public int getCurrentMinute() {return this.getData().get(this.getCurrentItemPosition()).getItemNumber();}}

第10节 原子时间类 PickerSecond

位置

src/java/view.wheel.atom.time.PickerSecond.java

代码

package view.wheel.atom.time;import android.content.Context;import android.util.AttributeSet;import view.wheel.WheelBean;import view.wheel.WheelPicker;import java.util.ArrayList;import java.util.Calendar;import java.util.List;// 选择器(秒钟)public class PickerSecond extends WheelPicker {private int mSecondStart;private int mSecondEnd;private int mSelectedSecond;public PickerSecond(Context context) {this(context, null);}public PickerSecond(Context context, AttributeSet attrs) {super(context, attrs);mSecondStart = 0;mSecondEnd = 59;updateSecond();mSelectedSecond = Calendar.getInstance().get(Calendar.SECOND);setSelectedItemPosition(mSelectedSecond - this.mSecondStart);}private void updateSecond() {List<WheelBean> data = new ArrayList<>();for (int i = this.mSecondStart; i <= this.mSecondEnd; i++) {WheelBean item = new WheelBean(i, label);data.add(item);}super.setData(data);}public int getSecondStart() {return this.mSecondStart;}public void setSecondStart(int start) {this.mSecondStart = start;this.mSelectedSecond = this.getCurrentSecond();this.updateSecond();this.setSelectedItemPosition(this.mSelectedSecond - this.mSecondStart);}public int getCurrentSecond() {return this.getData().get(this.getCurrentItemPosition()).getItemNumber();}}

第11节 测试Activity

位置

src/java/DemoActivity.java

代码

public class DemoActivity extends AppCompatActivity {private DateTimePickerView mDateTimePickerView;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_demo);this.mDateTimePickerView = findViewById(R.id.date_time_picker_view);// 定义相关的属性状态mDateTimePickerView.setAtmospheric(true);// 条目颜色是否执行衔接处理, 效果更好mDateTimePickerView.setCurved(false);// 是否显示弧度mDateTimePickerView.setItemTextColorUnSelect(Color.BLUE); // 未选中的条目颜色mDateTimePickerView.setItemTextColorSelected(Color.RED); // 选中条目的颜色mDateTimePickerView.setCyclic(true);// 设置是否循环mDateTimePickerView.setCenterLineColor(Color.BLUE); // 设置中间线的颜色mDateTimePickerView.setCenterLineWidth(2);// 设置中间线的宽度mDateTimePickerView.setCenterLineIsShow(false);// 设置中间线是否显示mDateTimePickerView.setCenterRectColor(Color.parseColor("#66666666")); // 设置中间矩形的颜色mDateTimePickerView.setCenterRectIsShow(true);// 设置中间矩形是否显示// 设置显示的类型(数组的长度必须是6,分别表示 "年", "月", "日", "时", "分", "秒")boolean[] array = new boolean[]{true, true, true, true, true, false};mDateTimePickerView.setShowType(array);}}

第12节 布局文件

位置

res/layout/view_picker_time_date.xml

代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="horizontal"><view.wheel.atom.time.PickerYearandroid:id="@+id/picker_year"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"app:wheel_label="" /><view.wheel.atom.time.PickerMonthandroid:id="@+id/picker_month"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"app:wheel_label="" /><view.wheel.atom.time.PickerDayandroid:id="@+id/picker_day"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"app:wheel_label="" /><view.wheel.atom.time.PickerHourandroid:id="@+id/picker_hour"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"app:wheel_label="" /><view.wheel.atom.time.PickerMinuteandroid:id="@+id/picker_minute"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"app:wheel_label="" /><view.wheel.atom.time.PickerSecondandroid:id="@+id/picker_second"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"app:wheel_label="" /></LinearLayout>

位置

res/layout/activity_demo.xml

代码

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><view.wheel.atom.time.DateTimePickerViewandroid:id="@+id/date_time_picker_view"android:layout_width="match_parent"android:layout_height="match_parent" /></FrameLayout>

第13节 属性文件

位置

res/values/attrs.xml

代码

<resources><declare-styleable name="WheelPicker"><attr name="wheel_data" format="reference" /><attr name="wheel_selected_item_position" format="integer" /><attr name="wheel_item_text_size" format="dimension" /><attr name="wheel_item_text_color" format="color" /><attr name="wheel_selected_item_text_color" format="color" /><attr name="wheel_same_width" format="boolean" /><attr name="wheel_maximum_width_text" format="string" /><attr name="wheel_label" format="string" /><attr name="wheel_maximum_width_text_position" format="integer" /><attr name="wheel_visible_item_count" format="integer" /><attr name="wheel_item_space" format="dimension" /><attr name="wheel_cyclic" format="boolean" /><attr name="wheel_indicator" format="boolean" /><attr name="wheel_indicator_color" format="color" /><attr name="wheel_indicator_size" format="dimension" /><attr name="wheel_curtain" format="boolean" /><attr name="wheel_curtain_color" format="color" /><attr name="wheel_atmospheric" format="boolean" /><attr name="wheel_curved" format="boolean" /><attr name="wheel_item_align" format="enum"><enum name="center" value="0" /><enum name="left" value="1" /><enum name="right" value="2" /></attr></declare-styleable></resources>