自定义时间选择器
文章目录
- 自定义时间选择器
- 第一章 效果演示
- 第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.java
B. 实体类和接口
src/java/view.wheel.WheelBean.java
src/java/view.wheel.IWheelPicker.java
C. 原子时间类
src/java/view.wheel.atom.time.DateTimePickerView.java
src/java/view.wheel.atom.time.PickerDay.java
src/java/view.wheel.atom.time.PickerHour.java
src/java/view.wheel.atom.time.PickerMinute.java
src/java/view.wheel.atom.time.PickerMonth.java
src/java/view.wheel.atom.time.PickerSecond.java
src/java/view.wheel.atom.time.PickerYear.java
D. 测试Activity
src/java/DemoActivity.java
2、来自于资源文件的类
A. 布局文件
res/layout/view_picker_time_date.xml
res/layout/activity_demo.xml
B. 属性文件
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转px
private 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
@Override
public 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());
}
@Override
public 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;
@Override
protected 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
代码
<?xml version="1.0" encoding="utf-8"?>
<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.PickerYear
android:id="@+id/picker_year"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:wheel_label="年" />
<view.wheel.atom.time.PickerMonth
android:id="@+id/picker_month"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:wheel_label="月" />
<view.wheel.atom.time.PickerDay
android:id="@+id/picker_day"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:wheel_label="日" />
<view.wheel.atom.time.PickerHour
android:id="@+id/picker_hour"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:wheel_label="时" />
<view.wheel.atom.time.PickerMinute
android:id="@+id/picker_minute"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:wheel_label="分" />
<view.wheel.atom.time.PickerSecond
android: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
代码
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<view.wheel.atom.time.DateTimePickerView
android:id="@+id/date_time_picker_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
第13节 属性文件
位置
res/values/attrs.xml
代码
<?xml version="1.0" encoding="utf-8"?>
<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>