自定义时间选择器

news2024/11/13 9:30:53

自定义时间选择器

文章目录

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








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

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

相关文章

比特币价格创新高:加密货币的崛起与未来

一、引言 近年来&#xff0c;比特币的价格一路上涨&#xff0c;引起了全球投资者和市场的广泛关注。作为最早一批区块链技术应用案例之一&#xff0c;比特币的成功带动了整个加密货币市场的兴起。本文将探讨比特币价格创新高的原因、加密货币的崛起以及未来发展趋势。 二、比特…

CV炼丹心得总结

1&#xff0c;ResNet的思想 yF(x)x 这个经验可帮助模型更快的收敛 class Block(nn.Module): # Encoder Blockdef __init__(self,dim, # 每个token的维度drop_rate0.1,switch_flagFalse,num_heads8):super(Block, self).__init__()self.switch_flag switch_flagself.…

驾龄不足三年如何注册网约车?刘师傅的反击之途!

刘师傅是个勤奋的司机。他想注册成为一名网约车司机&#xff0c;但由于驾龄不够三年&#xff0c;他一直被平台回绝。在多次尝试注册失败后&#xff0c;刘师傅慢慢四处求助。他咨询了多个渠道&#xff0c;但都没有得到有效的解决方案。当他在准备放弃的时候&#xff0c;他得知了…

从0创建并部署一个网页到服务器

创建一个页面 1 下载node.js 下载VScode 2 在Windows下找一个路径新建一个文件夹 例如&#xff1a;D:\study_project\PersonalWeb 3 VSCodee中打开文件夹 4 Windows下 管理员身份打开命令提示符&#xff0c;执行npm install -g vue/cli 5 VSCode下打开终端&#xff0c;执…

使用Audition录制电脑内部声音

在电脑上播放的媒体文件&#xff0c;包括视频和声音&#xff0c;很多是可以播放却无法保存的。例如一些网页播放的视频&#xff0c;或者在线播放的音乐。 视频的话&#xff0c;可以使用工具来截图&#xff0c;抓取GIF或录屏。 声音的话&#xff0c;也可以使用工具进行录制。这里…

【️Java是值传递还是引用传递?】

✅Java是值传递还是引用传递&#xff1f; ✅Java是值传递还是引用传递&#xff1f;✅典型理解 ✅增加知识仓✅Java的求值策略✅Java中的对象传递✅值传递和共享对象传递的现象冲突吗? ✅总结 ✅Java是值传递还是引用传递&#xff1f; ✅典型理解 编程语言中需要进行方法间的…

实战演示 H5 性能分析

W3C标准是浏览器标准&#xff0c;一般浏览器都支持W3C标准&#xff0c;它规定使用者可以通过api查询性能信息&#xff0c;可借用W3C协议完成自动化H5性能测试。 W3C官网&#xff1a;www.w3.org/TR/navigati… 使用chrome浏览器对webview进行手工查看&#xff0c;伴随着业务增多…

ChatGPT4 Excel 高级组合函数用法index+match完成实际需求

在Excel 函数用法中有一对组合函数使用是非常多的,那就是Index+match组合函数。 接下来我们用一个实际的需求让ChatGPT来帮我们实现一下。 我们给ChatGPT4发送一个prompt:有一个表格A2至A14为业务员B列至H列为1月至7月的销售额,请根据J2单元格的业务员与K2单元格的月份查找出…

【python】Debian安装miniconda、spyder、tushare

1. miniconda 安装 — 动手学深度学习 2.0.0 documentation中有安装Miniconda的一些说明。 Miniconda — miniconda documentation是Miniconda网站&#xff0c;里面也有安装说明。 Debian安装按照linux安装即可&#xff1a; mkdir -p ~/miniconda3 wget https://repo.anaco…

NoSQL 数据库有哪些典型应用?

前面的内容介绍了数据库读写分离和分库分表相关知识&#xff0c;都是针对关系型数据库的&#xff0c;即通常说的 RDBMS。除了关系型数据库&#xff0c;NoSQL 在项目开发中也有着越来越重要的作用&#xff0c;与此同时&#xff0c;NoSQL 相关的内容也是面试的常客。今天我们一起…

OSG中几何体的绘制(二)

5. 几何体操作 在本章的前言中就讲到&#xff0c;场景都是由基本的绘图基元构成的&#xff0c;基本的绘图基元构成简单的几何体,简单的几何体构成复杂的几何体&#xff0c;复杂的几何体最终构造成复杂的场景。当多个几何体组合时&#xff0c;可能存在多种降低场景渲染效率的原因…

基于linux系统的Tomcat+Mysql+Jdk环境搭建(二)jdk1.8 linux 上传到MobaXterm 工具的已有session里

【JDK安装】 1.首先下载一个JDK版本 官网地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载1.8版本&#xff0c;用红框标注出来了&#xff1a; 也许有的同学看到没有1.8版本&#xff0c;你可以随便下载一个linux的…

最强Pose模型RTMO开源 | 基于YOLO架构再设计,9MB+9ms性能完爆YOLO-Pose

实时多人在图像中的姿态估计面临着在速度和精度之间实现平衡的重大挑战。尽管两阶段的上下文方法在图像中人数增加时会减慢速度&#xff0c;但现有的单阶段方法往往无法同时实现高精度和实时性能。 本文介绍了RTMO&#xff0c;这是一个单阶段姿态估计框架&#xff0c;通过在YOL…

【十】我们都是面向spring注解开发的

spring 注解驱动开发 简介&#xff1a; 前面有写过spring框架的演进历程&#xff0c;得出一个结论就是我们都是面向spring编程的&#xff0c;这里讲另一个结论&#xff1a;我们都是面向spring注解开发的。spring框架的核心设计理念是简化java开发&#xff0c;而这一路的发展越…

超分辨率重建——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 …

TCP报文头(首部)详解

本篇文章基于 RFC 9293: Transmission Control Protocol (TCP) 对TCP报头进行讲解&#xff0c;部分内容会与旧版本有些许区别。 TCP协议传输的数据单元是报文段&#xff0c;一个报文段由TCP首部&#xff08;报文头&#xff09;和TCP数据两部分组成&#xff0c;其中TCP首部尤其重…

node.js mongoose简述

目录 官方文档 mongoose Schema Model Query document 关系 官方文档 Mongoose v8.0.3: Getting Started mongoose Mongoose 是一个 Node.js 环境下 MongoDB 的对象建模工具。它提供了一种在应用程序中与 MongoDB 数据库进行交互的方式&#xff0c;使得开发者能够使用…

怎么使用会声会影?2024年最新使用会声会影的具体步骤

一听说视频剪辑我们就不由得联想到电影、电视等一些高端的视频剪辑技术&#xff0c;大家都觉得视频剪辑是一个非常复杂而且需要很昂贵的设备才可以完成的技术活&#xff0c;这对很多“门外汉”来说都可望而不可及。实际上&#xff0c;使用会声会影剪辑视频不仅是很多人都可以操…

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

目录 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;没排过序。给一个无符号整数&…

Java 基础学习(十二)文本I/O、日期与时间API

1 文本 I/O 1.1 字符流 1.1.1 什么是字符流 在Java中&#xff0c;字符流是指提供了基于字符的I/O能力的API。 Java 1.0中提供的基于字节的I/O流API只能支持8位字节流&#xff0c;无法妥善地处理16位Unicode字符。由于需要支持Unicode处理国际化字符&#xff0c;因此Java 1.…