自定义时间选择器

自定义时间选择器

文章目录

  • 自定义时间选择器
    • 第一章 效果演示
      • 第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

代码

<?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.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

代码

<?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.DateTimePickerViewandroid: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>








本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/227673.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx的location与rewrite

目录 一.location 二.rewrite rewrite跳转实现&#xff1a; 语法格式&#xff1a;rewrite [flag]; flag标记说明&#xff1a; 三.基于域名跳转 四.基于ip跳转 五.基于旧域名跳转到新域名后面加目录 六.基于参数匹配的跳转 可以同过全局变量来匹配&#xff1a; 基于目…

linux常见错误

1.E45: ‘readonly‘ option is set (add ! to override) 首先使用以下命令从Vim编辑器中出来&#xff1a;:qa!(强制退出) 接下来&#xff0c;使用sudo vim filename和更高版本&#xff1a;:wq 2.Bash script – "/bin/bash^M: bad interpreter: No such file or direc…

鸿蒙4.0开发 - DevEco Studio如何使用Previewer窗口预览器报错

DevEco Studio预览器概况在HarmonyOS应用开发过程中&#xff0c;通过使用预览器&#xff0c;可以查看应用的UI效果&#xff0c;方便开发者实时查看应用的运行效果&#xff0c;随时调整代码。 1.正常启动 打开预览器的位置在DevEco Studio编辑界面的右上角部分&#xff0c;竖排…

Linux 高级管理,安装MySQL数据库

1.准备工作 &#xff08;1&#xff09;为了避免发生端口冲突&#xff0c;程序冲突等现象&#xff0c;建议先查询MySQL软件的安装情况&#xff0c;确认没有 使用以RPM方式安装的mysql-server、mysql软件包&#xff0c;否则建议将其卸载。 [rootnode01 ~]# rpm -q mysql-server…

FastAdmin后台安装出现2054错误的解决办法

用Navicat修改密码验证方式。MySQL Workbench的Server菜单中的Users and Privileges菜单中似乎不支持此项修改。 修改完毕以后也许会报错&#xff1a; Access denied for user ‘root‘‘localhost‘ (using password: YES) 用以下命令无密进入mysql。 C:\Program Files\MySQ…

小米路由器4A千兆版如何刷OpenWRT并使用固定地址远程访问

文章目录 前言1. 安装Python和需要的库2. 使用 OpenWRTInvasion 破解路由器3. 备份当前分区并刷入新的Breed4. 安装cpolar内网穿透4.1 注册账号4.2 下载cpolar客户端4.3 登录cpolar web ui管理界面4.4 创建公网地址 5. 固定公网地址访问 前言 OpenWRT是一个高度模块化、高度自…

Ps:形状工具 - 描边选项

在形状工具的工具选项栏或“属性”面板中&#xff0c;单击“设置形状描边类型” Set shape stroke type菜单图标可打开“描边选项” Stroke Options面板。 描边预设 Stroke Type 默认列出了实线、虚线和点线三种类型的描边&#xff0c;单击可应用。 自己创建并存储的描边类型&a…

CTF竞赛密码学题目解析

CTF&#xff08;Capture The Flag&#xff09;竞赛是一个有趣的挑战。密码学是CTF竞赛中的核心元素之一&#xff0c;通常涉及解密、破译密码、理解加密算法等技能。以下是30个题目及答案&#xff0c;新入行的可以看看鸭。 题目及答案 1. Caesar Cipher 描述&#xff1a;给出一…

前端传递参数,后端如何接收

目录 简单参数 传递方式 获取方式一 获取方式二 相关注解 实体参数 数组集合参数 传递方式 相关注解 获取方式一 获取方式二 日期参数 传递方式 相关注解 获取方式 json参数 传递方式 相关注解 获取方式 路径参数 传递方式 相关注解 获取方式 传递多个…

时序预测 | Python实现CNN电力需求预测

时序预测 | Python实现CNN电力需求预测 目录 时序预测 | Python实现CNN电力需求预测预测效果基本描述程序设计参考资料预测效果 基本描述 该数据集因其每小时的用电量数据以及 TSO 对消耗和定价的相应预测而值得注意,从而可以将预期预测与当前最先进的行业预测进行比较。使用该…

[论文笔记] chatgpt系列 SparseMOE—GPT4的MOE结构

SparseMOE: 稀疏激活的MOE Swtich MOE,所有token要在K个专家网络中,选择一个专家网络。 显存增加。 Experts Choice:路由MOE:​​​​​​​ 由专家选择token。这样不同的专家都选择到某个token,也可以不选择该token。 由于FFN层的时间复杂度和attention层不同,FFN层的时…

[Verilog] Verilog 简介

主页&#xff1a; 元存储的博客 全文 2100 字。 文章目录 前言1. Verilog 简介2. 主要特性3. 应用领域总结 前言 Verilog HDL&#xff08;简称 Verilog &#xff09;是一种硬件描述语言&#xff0c;用于数字电路的系统设计。可对算法级、门级、开关级等多种抽象设计层次进行建…

杰理-音箱-flash配置

杰理-音箱-flash配置 注意配置io&#xff0c;双线或者4线的硬件连接方式&#xff0c;否则无法烧录UI资源

哈希扩展:位图与布隆过滤器

目录 1. 位图1.1 位图引入1.2 位图概念1.3 位图的模拟实现1.4 位图相关问题1.5 位图的应用 2. 布隆过滤器2.1 布隆过滤器概念2.2 模拟实现2.3 布隆过滤器相关问题2.3.1 哈希切分 1. 位图 1.1 位图引入 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&…

LabVIEW开发地铁运行安全监控系统

LabVIEW开发地铁运行安全监控系统 最近昌平线发生的故障事件引起了广泛关注&#xff0c;暴露了现有地铁运行监控系统在应对突发情况方面的不足。为了提高地铁系统的运行安全性&#xff0c;并防止类似事件再次发生&#xff0c;提出了一套全面的地铁运行安全监控系统方案。此方案…

MySQL数据库,变量、流程控制与游标

变量 系统变量 系统变量分为全局系统变量&#xff08;需要添加global关键字&#xff09;以及会话系统变量&#xff08;需要添加session关键字&#xff09;有时将全局系统变量简称为全局变量&#xff0c;将会话系统变量称为local变量。如果不写&#xff0c;默认会话级别。静态…

如何在页面中加入百度地图

官方文档&#xff1a;jspopularGL | 百度地图API SDK (baidu.com) 添加一下代码就可以实现 <!DOCTYPE html> <html> <head><meta name"viewport" content"initial-scale1.0, user-scalableno"/><meta http-equiv"Conten…

超分辨率重建——SAN训练自己数据集及推理测试(详细图文教程)

目录 一、源码包下载二、数据集准备三、预训练权重文件四、训练环境五、训练5.1 超参数修改5.2 训练模型5.2.1 命令方式训练5.2.2 Configuration配置参数方式训练 5.3 模型保存 六、推理测试6.1 超参数修改6.2 测试6.2.1 命令方式测试6.2.2 Configuration配置参数方式测试 6.3 …

响应者链概述

响应者链 iOS事件的3大类型 Touch Events(触摸事件)Motion Events(运动事件&#xff0c;比如重力感应和摇一摇等)Remote Events(远程事件&#xff0c;比如用耳机上得按键来控制手机) 触摸事件 处理触摸事件的两个步骤 寻找事件的最佳响应者事件的响应在响应链中的传递 寻…

Web UI 自动化 元素定位利器

序 元素定位&#xff0c;对于 Web UI 自动化而言&#xff0c;绝对是大家成长道路上的一道绊脚石。 很多初学者&#xff0c;都“死”在了元素定位上&#xff0c;从而失去了学习的兴趣。导致职业规划不得不半途而废~ 那么&#xff0c;今天&#xff0c;我们就使用 Katalon Stu…