Android:时间选择器(最下面有效果图)

1.创建DateUtil类

/**
 * Created by wangshuai on 2024/11/19.
 */
public class DateUtil {
	public final static String PATTERN_ALL="yyyy-MM-dd HH:mm:ss";
	public final static String PATTERN_DEFAULT="yyyy-MM-dd";
    /**
     * 获取当前时间
     * @return yyyy-MM-dd
     */
    public static String getNowDate(){
        Date date=new Date();
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return  format.format(date);
    }

    /**
     * 上一个月时间
     * @param date 时间
     * @return
     */
    public static String getPreDate(String date){
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String value = "";
        try {
            Date now_date = df.parse(date);
            Calendar g = Calendar.getInstance();
            g.setTime(now_date);
            g.add(Calendar.MONTH,-1);
            Date pre_date = g.getTime();
            value = df.format(pre_date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return value;
    }

    /**
     * 时间字符串转换格式
     * @param date 时间
     * @param oldPattern 当前模式
     * @param newPattern 转换模式
     * @return
     */
    public static String formatDate(String date,String oldPattern, String newPattern){
        DateFormat sdf_old = new SimpleDateFormat(oldPattern);
        DateFormat sdf_new = new SimpleDateFormat(newPattern);
        String value = "";
        try {
            Date date1 =  sdf_old.parse(date);
            value = sdf_new.format(date1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return value;
    }
    /**
     * 时间字符串转换格式
     * @param date 时间
     * @param oldPattern 当前模式
     * @param newPattern 转换模式
     * @return
     */
    public static Date formatDate(String date, String pattern){
        DateFormat sdf = new SimpleDateFormat(pattern);
        Date ret_date =null;
        try {
        	ret_date =  sdf.parse(date);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret_date;
    }
    /**
     * 时间字符串转换格式
     * @param date 时间
     * @param pattern 转换模式
     * @return
     */
    public static String formatDate(Date date, String pattern) {
        String returnValue = "";
        if (date != null) {
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            returnValue = df.format(date);
        }
        return (returnValue);
    }

    /**
     * 判断选择的日期是否是本周
     * @param time
     * @return
     */
    public static boolean isThisWeek(String time){
        Calendar calendar = Calendar.getInstance();
        int currentWeek = calendar.get(Calendar.WEEK_OF_YEAR);
        calendar.setTime(new Date(time));
        int paramWeek = calendar.get(Calendar.WEEK_OF_YEAR);
        if(paramWeek==currentWeek){
            return true;
        }
        return false;
    }

    /**
     * 字符串转时间
     * @param date
     * @return
     */
   public static Date str2Date(String date){
       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
       try {
           return sdf.parse(date);
       } catch (ParseException e) {
           e.printStackTrace();
       }
       return null;
   }
    /**
     * 字符串转时间
     * @param date
     * @return
     */
    public static Date str2Date(String date, String pattern){
        if (StringUtil.isEmpty(date)) {
            return null;
        }
        try {
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            return df.parse(date);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 判断选择的日期是否是今天
     * @param date
     * @return
     */
    public static boolean isToday(String date) {
    	 date = date.replaceAll(" ","");
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
         String now = sdf.format(new Date());//当前时间
         if(date.equals(now)){
             return true;
         }
         return false;
    }
    /**
     * 判断选择的日期是否是本月
     * @param time
     * @return
     */
    public static boolean isThisMonth(String time) {
        Date date = str2Date(time);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        String param = sdf.format(date);//参数时间
        String now = sdf.format(new Date());//当前时间
        if(param.equals(now)){
            return true;
        }
        return false;
    }
    /**
     * 增加分钟
     * @param date
     * @param addMin
     * @return
     */
    public static String addMin(Date date,int addMin){
    	 String returnValue = "";
    	 if(date!=null){
    		 try {
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(date);
				calendar.add(Calendar.MINUTE,addMin);
				Date ret_date = calendar.getTime();
				returnValue = formatDate(ret_date, "yyyy-MM-dd HH:mm");
			} catch (Exception e) {
				// TODO: handle exception
			}
    	 }
    	 return returnValue;
    }
    /**
     * 比较两个时间
     * @param firstDate
     * @param secDate
     * @return
     */
    public static boolean isBefore(Date firstDate,Date secDate){
    	return firstDate.before(secDate);
    }
    /**
     * 比较两个时间
     * @param firstDate
     * @param secDate
     * @return
     */
    public static boolean isBefore(String firstDate,String secDate,String pattern){
    	try {
    	   SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			Date tmp_first = sdf.parse(firstDate);
			Date tmp_sec = sdf.parse(secDate);
			return tmp_first.before(tmp_sec);
		} catch (Exception e) {
			// TODO: handle exception
		}
    	return false;
    }
    /**
     * 比较两个时间
     * @param firstDate
     * @param secDate
     * @return
     */
    public static boolean isBeforeAequals(String firstDate,String secDate,String pattern){
    	try {
    		if(firstDate.equals(secDate)){return true;}
    	   SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			Date tmp_first = sdf.parse(firstDate);
			Date tmp_sec = sdf.parse(secDate);
			return tmp_first.before(tmp_sec);
		} catch (Exception e) {
			// TODO: handle exception
		}
    	return false;
    }
    
    public static int getYear(String date,String pattern){
    	try {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(formatDate(date, pattern));
			return calendar.get(Calendar.YEAR);
		} catch (Exception e) {
			String da="";
		}
    	return -1;
    }
    
    public static int getMonth(String date,String pattern){
    	try {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(formatDate(date, pattern));
			return  calendar.get(Calendar.MONTH)+1;
		} catch (Exception e) {
			// TODO: handle exception
		}
    	return -1;
    }
    public static int getDay(String date,String pattern){
    	try {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(formatDate(date, pattern));
			return  calendar.get(Calendar.DATE);
		} catch (Exception e) {
			// TODO: handle exception
		}
    	return -1;
    }
    public static int getDayOfMonth(String date,String pattern){
    	try {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(formatDate(date, pattern));
			calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
			return  calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
		} catch (Exception e) {
			// TODO: handle exception
		}
    	return -1;
    }
    public static int getHour(String date,String pattern){
    	try {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(formatDate(date, pattern));
			return  calendar.get(Calendar.HOUR_OF_DAY);
		} catch (Exception e) {
			// TODO: handle exception
		}
    	return -1;
    }
    public static int getMinute(String date,String pattern){
    	try {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(formatDate(date, pattern));
			return  calendar.get(Calendar.MINUTE);
		} catch (Exception e) {
			// TODO: handle exception
		}
    	return -1;
    } 
    public static int getSecond(String date,String pattern){
    	try {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(formatDate(date, pattern));
			return  calendar.get(Calendar.SECOND);
		} catch (Exception e) {
			// TODO: handle exception
		}
    	return -1;
    } 
}

2.创建DecimalUtil

import java.text.DecimalFormat;
/**
 * Created by wangshuai on 2024/11/19.
 */
public class DecimalUtil {

	public static String keep2zero_head(String str){
		try {
			   DecimalFormat df=new DecimalFormat("00");
			   return df.format(Integer.parseInt(str));
		} catch (Exception e) {
			// TODO: handle exception
		}
		return null;
	}
}

3.创建PickerView

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Paint.Style;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 滚动选择器 更多详解见博客http://blog.csdn.net/zhongkejingwang/article/details/38513301
 * 
 * @author wangshuai
 * 
 */
public class PickerView extends View
{

	public static final String TAG = "PickerView";
	/**
	 * text之间间距和minTextSize之比
	 */
	public static final float MARGIN_ALPHA = 2.8f;
	/**
	 * 自动回滚到中间的速度
	 */
	public static final float SPEED = 2;

	private List<String> mDataList;
	/**
	 * 选中的位置,这个位置是mDataList的中心位置,一直不变
	 */
	private int mCurrentSelected;
	private Paint mPaint;

	private float mMaxTextSize = 80;
	private float mMinTextSize = 40;

	private float mMaxTextAlpha = 255;
	private float mMinTextAlpha = 120;

	private int mColorText = 0x333333;

	private int mViewHeight;
	private int mViewWidth;

	private float mLastDownY;
	/**
	 * 滑动的距离
	 */
	private float mMoveLen = 0;
	private boolean isInit = false;
	private onSelectListener mSelectListener;
	private Timer timer;
	private MyTimerTask mTask;

	Handler updateHandler = new Handler()
	{

		@Override
		public void handleMessage(Message msg)
		{
			if (Math.abs(mMoveLen) < SPEED)
			{
				mMoveLen = 0;
				if (mTask != null)
				{
					mTask.cancel();
					mTask = null;
					performSelect();
				}
			} else
				// 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚
				mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED;
			invalidate();
		}

	};

	public PickerView(Context context)
	{
		super(context);
		init();
	}

	public PickerView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		init();
	}

	public void setOnSelectListener(onSelectListener listener)
	{
		mSelectListener = listener;
	}

	private void performSelect()
	{
		if (mSelectListener != null)
			mSelectListener.onSelect(mDataList.get(mCurrentSelected));
	}

	public void setData(List<String> datas)
	{
		mDataList = datas;
		mCurrentSelected = datas.size() / 2;
		invalidate();
	}

	/**
	 * 选择选中的item的index
	 * 
	 * @param selected
	 */
	public void setSelected(int selected)
	{
		mCurrentSelected = selected;
		int distance = mDataList.size() / 2 - mCurrentSelected;
		if (distance < 0)
			for (int i = 0; i < -distance; i++)
			{
				moveHeadToTail();
				mCurrentSelected--;
			}
		else if (distance > 0)
			for (int i = 0; i < distance; i++)
			{
				moveTailToHead();
				mCurrentSelected++;
			}
		invalidate();
	}

	/**
	 * 选择选中的内容
	 * 
	 * @param mSelectItem
	 */
	public void setSelected(String mSelectItem)
	{
		for (int i = 0; i < mDataList.size(); i++)
			if (mDataList.get(i).equals(mSelectItem))
			{
				setSelected(i);
				break;
			}
	}
	//获取当前选择
	public String getSelected(){
		try {
			return mDataList.get(mCurrentSelected);
		} catch (Exception e) {
			// TODO: handle exception
		}
		return null;
	}
	private void moveHeadToTail()
	{
		String head = mDataList.get(0);
		mDataList.remove(0);
		mDataList.add(head);
	}

	private void moveTailToHead()
	{
		String tail = mDataList.get(mDataList.size() - 1);
		mDataList.remove(mDataList.size() - 1);
		mDataList.add(0, tail);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mViewHeight = getMeasuredHeight();
		mViewWidth = getMeasuredWidth();
		// 按照View的高度计算字体大小
		mMaxTextSize = mViewHeight/7f;
		mMinTextSize = mMaxTextSize / 2.2f;
		isInit = true;
		invalidate();
	}

	private void init()
	{
		timer = new Timer();
		mDataList = new ArrayList<String>();
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaint.setStyle(Style.FILL);
		mPaint.setTextAlign(Align.CENTER);
		mPaint.setColor(mColorText);
	}

	@Override
	protected void onDraw(Canvas canvas)
	{
		super.onDraw(canvas);
		// 根据index绘制view
		if (isInit)
			drawData(canvas);
	}

	private void drawData(Canvas canvas)
	{
		// 先绘制选中的text再往上往下绘制其余的text
		float scale = parabola(mViewHeight / 4.0f, mMoveLen);
		float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;
		mPaint.setTextSize(size);
		mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));
		// text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标
		float x = (float) (mViewWidth / 2.0);
		float y = (float) (mViewHeight / 2.0 + mMoveLen);
		FontMetricsInt fmi = mPaint.getFontMetricsInt();
		float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));

		canvas.drawText(mDataList.get(mCurrentSelected), x, baseline, mPaint);
		// 绘制上方data
		for (int i = 1; (mCurrentSelected - i) >= 0; i++)
		{
			drawOtherText(canvas, i, -1);
		}
		// 绘制下方data
		for (int i = 1; (mCurrentSelected + i) < mDataList.size(); i++)
		{
			drawOtherText(canvas, i, 1);
		}

	}

	/**
	 * @param canvas
	 * @param position
	 *            距离mCurrentSelected的差值
	 * @param type
	 *            1表示向下绘制,-1表示向上绘制
	 */
	private void drawOtherText(Canvas canvas, int position, int type)
	{
		float d = (float) (MARGIN_ALPHA * mMinTextSize * position + type
				* mMoveLen);
		float scale = parabola(mViewHeight / 4.0f, d);
		float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;
		mPaint.setTextSize(size);
		mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));
		float y = (float) (mViewHeight / 2.0 + type * d);
		FontMetricsInt fmi = mPaint.getFontMetricsInt();
		float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));
		canvas.drawText(mDataList.get(mCurrentSelected + type * position),
				(float) (mViewWidth / 2.0), baseline, mPaint);
	}

	/**
	 * 抛物线
	 * 
	 * @param zero
	 *            零点坐标
	 * @param x
	 *            偏移量
	 * @return scale
	 */
	private float parabola(float zero, float x)
	{
		float f = (float) (1 - Math.pow(x / zero, 2));
		return f < 0 ? 0 : f;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		switch (event.getActionMasked())
		{
		case MotionEvent.ACTION_DOWN:
			doDown(event);
			break;
		case MotionEvent.ACTION_MOVE:
			doMove(event);
			break;
		case MotionEvent.ACTION_UP:
			doUp(event);
			break;
		}
		return true;
	}

	private void doDown(MotionEvent event)
	{
		if (mTask != null)
		{
			mTask.cancel();
			mTask = null;
		}
		mLastDownY = event.getY();
	}

	private void doMove(MotionEvent event)
	{

		mMoveLen += (event.getY() - mLastDownY);

		if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2)
		{
			// 往下滑超过离开距离
			moveTailToHead();
			mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize;
		} else if (mMoveLen < -MARGIN_ALPHA * mMinTextSize / 2)
		{
			// 往上滑超过离开距离
			moveHeadToTail();
			mMoveLen = mMoveLen + MARGIN_ALPHA * mMinTextSize;
		}

		mLastDownY = event.getY();
		invalidate();
	}

	private void doUp(MotionEvent event)
	{
		// 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置
		if (Math.abs(mMoveLen) < 0.0001)
		{
			mMoveLen = 0;
			return;
		}
		if (mTask != null)
		{
			mTask.cancel();
			mTask = null;
		}
		mTask = new MyTimerTask(updateHandler);
		timer.schedule(mTask, 0, 10);
	}

	class MyTimerTask extends TimerTask
	{
		Handler handler;

		public MyTimerTask(Handler handler)
		{
			this.handler = handler;
		}

		@Override
		public void run()
		{
			handler.sendMessage(handler.obtainMessage());
		}

	}

	public interface onSelectListener
	{
		void onSelect(String text);
	}
}

4.创建StringUtil

/**
 * Created by wangshuai on 2024/11/19.
 */
public class StringUtil {

    public static boolean isEmpty(Object obj){
        if(obj != null && !obj.toString().trim().isEmpty()&&!"null".equals(obj.toString())) {
            return false;
        }
        return true;
    }
}

5.创建布局文件popwin_picker_view

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llt_all"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="bottom"
    android:orientation="vertical">
	<LinearLayout 
	    android:layout_width="match_parent"
	    android:layout_height="60dp" 
	    android:orientation="horizontal"
	    android:background="#FFFFFF">
	    <com.ybgc.acceptanceofconcealedwork.divview.SupperTextView
	        android:id="@+id/tvw_cancel"
	        android:layout_width="0dp"
	        android:layout_height="match_parent"
	        android:layout_weight="1"
	        android:gravity="center"
	        android:textColor="#333333"
	        android:textSize="16sp"
	        android:text="取消"/>
	 <com.ybgc.acceptanceofconcealedwork.divview.SupperTextView
	    	 android:id="@+id/tvw_confirm"
	        android:layout_width="0dp"
	        android:layout_height="match_parent"
	        android:layout_weight="1"
	        android:gravity="center"
	        android:textColor="#333333"
	        android:textSize="16sp"
	        android:text="确定"/>
	</LinearLayout>
	<View 
	    android:layout_width="match_parent"
	    android:layout_height="0.5dp"
	    android:background="#E5E5E5"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="#ffffff" 
        android:padding="10dp"
        android:gravity="center_vertical"
        android:clickable="true">
 
         <com.ybgc.acceptanceofconcealedwork.timerpicker.PickerView
            android:id="@+id/pvw_year"
            android:layout_width="0dp"
            android:layout_height="160dp"
            android:layout_weight="3" />

        <com.ybgc.acceptanceofconcealedwork.divview.SupperTextView
            android:id="@+id/tvw_year"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1" 
            android:gravity="center"
            android:text="年"
            android:textColor="#333333"
            android:textSize="18sp"
            android:textStyle="bold" />
        
       <com.ybgc.acceptanceofconcealedwork.timerpicker.PickerView
            android:id="@+id/pvw_month"
            android:layout_width="0dp"
            android:layout_height="160dp"
            android:layout_weight="2" />

        <com.ybgc.acceptanceofconcealedwork.divview.SupperTextView
            android:id="@+id/tvw_month"
            android:layout_width="0dp"
            android:layout_height="match_parent"
             android:layout_weight="1"
              android:gravity="center"
            android:text="月"
            android:textColor="#333333"
            android:textSize="18sp"
            android:textStyle="bold" />
        
        <com.ybgc.acceptanceofconcealedwork.timerpicker.PickerView
            android:id="@+id/pvw_day"
            android:layout_width="0dp"
            android:layout_height="160dp"
            android:layout_weight="2" />

        <com.ybgc.acceptanceofconcealedwork.divview.SupperTextView
            android:id="@+id/tvw_day"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
             android:gravity="center"
            android:text="日"
            android:textColor="#333333"
            android:textSize="18sp"
            android:textStyle="bold" />
       
        <!--时分秒 -->
 
           <com.ybgc.acceptanceofconcealedwork.timerpicker.PickerView
            android:id="@+id/pvw_hour"
            android:layout_width="0dp"
            android:layout_height="160dp"
            android:layout_weight="2"
         />

        <com.ybgc.acceptanceofconcealedwork.divview.SupperTextView
            android:id="@+id/tvw_hour"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="时"
            android:textColor="#333333"
            android:textSize="18sp"
            android:textStyle="bold" 
           />
        
        <com.ybgc.acceptanceofconcealedwork.timerpicker.PickerView
            android:id="@+id/pvw_minute"
             android:layout_width="0dp"
            android:layout_height="160dp" 
            android:layout_weight="2"
            />

        <com.ybgc.acceptanceofconcealedwork.divview.SupperTextView
            android:id="@+id/tvw_minute"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" 
            android:text="分"
            android:textColor="#333333"
            android:textSize="18sp"
            android:textStyle="bold" 
           />

        <com.ybgc.acceptanceofconcealedwork.timerpicker.PickerView
            android:id="@+id/pvw_second"
             android:layout_width="0dp"
            android:layout_height="160dp"
            android:layout_weight="2" 
             />

        <com.ybgc.acceptanceofconcealedwork.divview.SupperTextView
            android:id="@+id/tvw_second"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" 
            android:text="秒"
            android:textColor="#333333"
            android:textSize="18sp"
            android:textStyle="bold" />
 
  		
    </LinearLayout>

</LinearLayout>

6.创建TimerPickerView

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.ybgc.acceptanceofconcealedwork.R;
import com.ybgc.acceptanceofconcealedwork.timerpicker.PickerView.onSelectListener;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;

/**
 * 时间选择控件
 *
 * @author wangshuai
 */
public class TimePickerView extends PopupWindow {

    public final static String DISPLAY_YMD = "yyyy-MM-dd";
    public final static String DISPLAY_YMDHMS = "yyyy-MM-dd HH:mm:ss";
    public final static String DISPLAY_YMDHM = "yyyy-MM-dd HH:mm";
    public final static String DISPLAY_HMS = "HH:mm:ss";
    public final static String DISPLAY_HM = "HH:mm";
    private final long ANIMATORDELAY = 200L;
    private final long CHANGEDELAY = 90L;
    private Context mContext;
    private PickerView pvw_year;
    private PickerView pvw_month;
    private PickerView pvw_day;
    private PickerView pvw_hour;
    private PickerView pvw_minute;
    private PickerView pvw_second;
    private TextView tvw_year;
    private TextView tvw_month;
    private TextView tvw_day;
    private TextView tvw_hour;
    private TextView tvw_minute;
    private TextView tvw_second;
    private List<String> year_list;
    private List<String> month_list;
    private List<String> day_list;
    private List<String> hour_list;
    private List<String> min_list;
    private List<String> sec_list;
    private String mode;//显示模式
    private String startTime = "1970-01-01 00:00:00";
    private String endTime = "2099-12-31 00:00:00";
    private String displayTime;//显示时间

    private String select_year;//年
    private String select_month;//月
    private String select_day;//日
    private String select_hour;//时
    private String select_minute;//分
    private String select_second;//秒
    private boolean isDisplayPastTime;//是否显示过去时间
    private onTimeSelectListener onTimeSelectListener;

    public TimePickerView(Context context) {
        this.mContext = context;
        this.isDisplayPastTime = true;
        initView();
    }

    private void initView() {
        View view = LayoutInflater.from(mContext).inflate(R.layout.popwin_picker_view, null);
        initShowView(view);
        setWidth(LayoutParams.MATCH_PARENT);
        setHeight(LayoutParams.MATCH_PARENT);
        setBackgroundDrawable(new ColorDrawable(0x80000000));
        setOutsideTouchable(false);
        setTouchable(true);
        setContentView(view);
    }

    private void initShowView(View view) {
        mode = DISPLAY_YMDHMS;
        LinearLayout llt_all = view.findViewById(R.id.llt_all);
        TextView tvw_cancel = view.findViewById(R.id.tvw_cancel);
        TextView tvw_confirm = view.findViewById(R.id.tvw_confirm);
        pvw_year = view.findViewById(R.id.pvw_year);
        pvw_month = view.findViewById(R.id.pvw_month);
        pvw_day = view.findViewById(R.id.pvw_day);
        pvw_hour = view.findViewById(R.id.pvw_hour);
        pvw_minute = view.findViewById(R.id.pvw_minute);
        pvw_second = view.findViewById(R.id.pvw_second);
        tvw_year = view.findViewById(R.id.tvw_year);
        tvw_month = view.findViewById(R.id.tvw_month);
        tvw_day = view.findViewById(R.id.tvw_day);
        tvw_hour = view.findViewById(R.id.tvw_hour);
        tvw_minute = view.findViewById(R.id.tvw_minute);
        tvw_second = view.findViewById(R.id.tvw_second);
        initDisplayMode();//设置显示效果
        llt_all.setOnClickListener(cancel_onClick);
        tvw_cancel.setOnClickListener(cancel_onClick);
        tvw_confirm.setOnClickListener(tvw_confirm_onClick);
        pvw_year.setOnSelectListener(year_onSelect);
        pvw_month.setOnSelectListener(month_onSelect);
        pvw_day.setOnSelectListener(day_onSelect);
        pvw_hour.setOnSelectListener(hour_onSelect);
        pvw_minute.setOnSelectListener(min_onSelect);
        pvw_second.setOnSelectListener(sec_onSelect);
    }

    //初始化数据
    private void initData() {
        year_list = new ArrayList<String>();
        month_list = new ArrayList<String>();
        day_list = new ArrayList<String>();
        hour_list = new ArrayList<String>();
        min_list = new ArrayList<String>();
        sec_list = new ArrayList<String>();
        initYear();
        initMonth(false);
        initDay(false);
        initHour(false);
        initMinute(false);
        initSecond(false);

        sec_list.addAll(min_list);
        pvw_year.setData(year_list);
        pvw_month.setData(month_list);
        pvw_day.setData(day_list);
        pvw_hour.setData(hour_list);
        pvw_minute.setData(min_list);
        pvw_second.setData(sec_list);

    }

    //初始年
    private void initYear() {
        int start_year = DateUtil.getYear(startTime, DateUtil.PATTERN_ALL);
        int end_year = DateUtil.getYear(endTime, DateUtil.PATTERN_ALL);
        year_list.clear();
        for (int i = start_year; i <= end_year; i++) {
            year_list.add(i + "");
        }
    }

    //初始月
    private void initMonth(boolean isSlide) {
        int start_month = DateUtil.getMonth(startTime, DateUtil.PATTERN_ALL);
        int start_year = DateUtil.getYear(startTime, DateUtil.PATTERN_ALL);
        if (!select_year.equals(DecimalUtil.keep2zero_head(start_year + ""))) {
            start_month = 1;
        }
        month_list.clear();
        for (int i = start_month; i <= 12; i++) {
            month_list.add(DecimalUtil.keep2zero_head(i + ""));
        }
        if (isSlide) {
            pvw_month.invalidate();
            pvw_month.setSelected(0);
            select_month = pvw_month.getSelected();
            excuteAnimator(ANIMATORDELAY, pvw_month);
            pvw_month.postDelayed(new Runnable() {
                @Override
                public void run() {
                    initDay(true);
                }
            }, CHANGEDELAY);
        }
    }

    //初始日
    private void initDay(boolean isSlide) {
        int start_day = DateUtil.getDay(startTime, DateUtil.PATTERN_ALL);
        int day_of_month = DateUtil.getDayOfMonth(startTime, DateUtil.PATTERN_ALL);
        int start_year = DateUtil.getYear(startTime, DateUtil.PATTERN_ALL);
        int start_month = DateUtil.getMonth(startTime, DateUtil.PATTERN_ALL);
        String select_time = select_year + "-" + select_month;
        String start_time = start_year + "-" + DecimalUtil.keep2zero_head(start_month + "");
        //判断当前选择时间是否是开始时间
        if (!select_time.equals(start_time)) {
            start_day = 1;
        }
        String now_time = select_year + "-" + select_month + "-01 00:00:00";
        day_of_month = DateUtil.getDayOfMonth(now_time, DateUtil.PATTERN_ALL);
        day_list.clear();
        for (int i = start_day; i <= day_of_month; i++) {
            day_list.add(DecimalUtil.keep2zero_head(i + ""));
        }
        //滑动时执行
        if (isSlide) {
            pvw_day.invalidate();
            pvw_day.setSelected(0);
            select_day = pvw_day.getSelected();
            excuteAnimator(ANIMATORDELAY, pvw_day);
            pvw_day.postDelayed(new Runnable() {
                @Override
                public void run() {
                    initHour(true);
                }
            }, CHANGEDELAY);
        }
    }

    //初始时
    private void initHour(boolean isSlide) {
        int start_hour = DateUtil.getHour(startTime, DateUtil.PATTERN_ALL);
        int start_year = DateUtil.getYear(startTime, DateUtil.PATTERN_ALL);
        int start_month = DateUtil.getMonth(startTime, DateUtil.PATTERN_ALL);
        int start_day = DateUtil.getDay(startTime, DateUtil.PATTERN_ALL);
        String select_time = select_year + "-" + select_month + "-" + select_day;
        String start_time = start_year + "-" + DecimalUtil.keep2zero_head(start_month + "") + "-"
                + DecimalUtil.keep2zero_head(start_day + "");
        if (!select_time.equals(start_time)) {
            start_hour = 0;
        }
        hour_list.clear();
        for (int i = start_hour; i < 24; i++) {
            hour_list.add(DecimalUtil.keep2zero_head(i + ""));
        }
        if (isSlide) {
            pvw_hour.invalidate();
            pvw_hour.setSelected(0);
            select_hour = pvw_hour.getSelected();
            excuteAnimator(ANIMATORDELAY, pvw_hour);
            pvw_hour.postDelayed(new Runnable() {
                @Override
                public void run() {
                    initMinute(true);
                }
            }, CHANGEDELAY);
        }
    }

    //初始分
    private void initMinute(boolean isSlide) {
        int start_min = DateUtil.getMinute(startTime, DateUtil.PATTERN_ALL);
        int start_year = DateUtil.getYear(startTime, DateUtil.PATTERN_ALL);
        int start_month = DateUtil.getMonth(startTime, DateUtil.PATTERN_ALL);
        int start_day = DateUtil.getDay(startTime, DateUtil.PATTERN_ALL);
        int start_hour = DateUtil.getHour(startTime, DateUtil.PATTERN_ALL);
        String select_time = select_year + "-" + select_month + "-" + select_day + " " + select_hour;
        String start_time = start_year + "-" + DecimalUtil.keep2zero_head(start_month + "") + "-"
                + DecimalUtil.keep2zero_head(start_day + "") + " " + DecimalUtil.keep2zero_head(start_hour + "");
        if (!select_time.equals(start_time)) {
            start_min = 0;
        }
        min_list.clear();
        for (int i = start_min; i < 60; i++) {
            min_list.add(DecimalUtil.keep2zero_head(i + ""));
        }
        if (isSlide) {
            pvw_minute.invalidate();
            pvw_minute.setSelected(0);
            select_minute = pvw_minute.getSelected();
            excuteAnimator(ANIMATORDELAY, pvw_minute);
            pvw_minute.postDelayed(new Runnable() {
                @Override
                public void run() {
                    initSecond(true);
                }
            }, CHANGEDELAY);
        }
    }

    //初始秒
    private void initSecond(boolean isSlide) {
        int start_sec = DateUtil.getSecond(startTime, DateUtil.PATTERN_ALL);
        int start_year = DateUtil.getYear(startTime, DateUtil.PATTERN_ALL);
        int start_month = DateUtil.getMonth(startTime, DateUtil.PATTERN_ALL);
        int start_day = DateUtil.getDay(startTime, DateUtil.PATTERN_ALL);
        int start_hour = DateUtil.getHour(startTime, DateUtil.PATTERN_ALL);
        int start_min = DateUtil.getMinute(startTime, DateUtil.PATTERN_ALL);
        String select_time = select_year + "-" + select_month + "-" + select_day + " " + select_hour + ":" + select_minute;
        String start_time = start_year + "-" + DecimalUtil.keep2zero_head(start_month + "") + "-"
                + DecimalUtil.keep2zero_head(start_day + "") + " " + DecimalUtil.keep2zero_head(start_hour + "") + ":"
                + DecimalUtil.keep2zero_head(start_min + "");
        if (!select_time.equals(start_time)) {
            start_sec = 0;
        }
        sec_list.clear();
        for (int i = start_sec; i < 60; i++) {
            sec_list.add(DecimalUtil.keep2zero_head(i + ""));
        }
        if (isSlide) {
            pvw_second.invalidate();
            pvw_second.setSelected(0);
            select_second = pvw_second.getSelected();
            excuteAnimator(ANIMATORDELAY, pvw_second);
        }
    }

    //初始化显示
    private void initDisplayMode() {
        pvw_year.setVisibility(View.VISIBLE);
        pvw_month.setVisibility(View.VISIBLE);
        pvw_day.setVisibility(View.VISIBLE);
        pvw_hour.setVisibility(View.VISIBLE);
        pvw_minute.setVisibility(View.VISIBLE);
        pvw_second.setVisibility(View.VISIBLE);
        tvw_year.setVisibility(View.VISIBLE);
        tvw_month.setVisibility(View.VISIBLE);
        tvw_day.setVisibility(View.VISIBLE);
        tvw_hour.setVisibility(View.VISIBLE);
        tvw_minute.setVisibility(View.VISIBLE);
        tvw_second.setVisibility(View.VISIBLE);
        switch (mode) {
            case DISPLAY_YMD:
                pvw_hour.setVisibility(View.GONE);
                pvw_minute.setVisibility(View.GONE);
                pvw_second.setVisibility(View.GONE);
                tvw_hour.setVisibility(View.GONE);
                tvw_minute.setVisibility(View.GONE);
                tvw_second.setVisibility(View.GONE);
                break;
            case DISPLAY_YMDHM:
                pvw_second.setVisibility(View.GONE);
                tvw_second.setVisibility(View.GONE);
                break;
            case DISPLAY_HMS:
                pvw_year.setVisibility(View.GONE);
                pvw_month.setVisibility(View.GONE);
                pvw_day.setVisibility(View.GONE);
                tvw_year.setVisibility(View.GONE);
                tvw_month.setVisibility(View.GONE);
                tvw_day.setVisibility(View.GONE);
                break;
            case DISPLAY_HM:
                pvw_year.setVisibility(View.GONE);
                pvw_month.setVisibility(View.GONE);
                pvw_day.setVisibility(View.GONE);
                pvw_second.setVisibility(View.GONE);
                tvw_year.setVisibility(View.GONE);
                tvw_month.setVisibility(View.GONE);
                tvw_day.setVisibility(View.GONE);
                tvw_second.setVisibility(View.GONE);
            default:
                break;
        }
    }

    //初始化显示数据
    private void initPickViewDisplayData() {
        try {
            if (StringUtil.isEmpty(displayTime)) {
                pvw_year.setSelected(0);
                pvw_month.setSelected(0);
                pvw_day.setSelected(0);
                pvw_hour.setSelected(0);
                pvw_minute.setSelected(0);
                pvw_second.setSelected(0);
                select_year = pvw_year.getSelected();
                select_month = pvw_month.getSelected();
                select_day = pvw_day.getSelected();
                select_hour = pvw_hour.getSelected();
                select_minute = pvw_minute.getSelected();
                select_second = pvw_second.getSelected();
            } else {
                Date date = DateUtil.str2Date(displayTime, mode);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(date);
                select_year = DateUtil.getYear(startTime, DateUtil.PATTERN_ALL) + "";
                select_month = DecimalUtil.keep2zero_head(DateUtil.getMonth(startTime, DateUtil.PATTERN_ALL) + "");
                select_day = DecimalUtil.keep2zero_head(DateUtil.getDay(startTime, DateUtil.PATTERN_ALL) + "");
                select_hour = DecimalUtil.keep2zero_head(DateUtil.getHour(startTime, DateUtil.PATTERN_ALL) + "");
                select_minute = DecimalUtil.keep2zero_head(DateUtil.getMinute(startTime, DateUtil.PATTERN_ALL) + "");
                select_second = DecimalUtil.keep2zero_head(DateUtil.getSecond(startTime, DateUtil.PATTERN_ALL) + "");
                switch (mode) {
                    case DISPLAY_YMDHMS://yyyy-MM-dd HH:mm:ss
                        select_year = calendar.get(Calendar.YEAR) + "";
                        select_month = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.MONTH) + 1));
                        select_day = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.DATE)));
                        select_hour = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.HOUR_OF_DAY)));
                        select_minute = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.MINUTE)));
                        select_second = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.SECOND)));
                        initData();
                        pvw_year.setSelected(select_year);
                        pvw_month.setSelected(select_month);
                        pvw_day.setSelected(select_day);
                        pvw_hour.setSelected(select_hour);
                        pvw_minute.setSelected(select_minute);
                        pvw_second.setSelected(select_second);
                        break;
                    case DISPLAY_YMDHM://yyyy-MM-dd HH:mm
                        select_year = calendar.get(Calendar.YEAR) + "";
                        select_month = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.MONTH) + 1));
                        select_day = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.DATE)));
                        select_hour = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.HOUR_OF_DAY)));
                        select_minute = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.MINUTE)));
                        initData();
                        pvw_year.setSelected(select_year);
                        pvw_month.setSelected(select_month);
                        pvw_day.setSelected(select_day);
                        pvw_hour.setSelected(select_hour);
                        pvw_minute.setSelected(select_minute);
                        break;
                    case DISPLAY_YMD://yyyy-MM-dd
                        select_year = calendar.get(Calendar.YEAR) + "";
                        select_month = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.MONTH) + 1));
                        select_day = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.DATE)));
                        initData();
                        pvw_year.setSelected(select_year);
                        pvw_month.setSelected(select_month);
                        pvw_day.setSelected(select_day);
                        break;
                    case DISPLAY_HMS://HH:mm:ss
                        select_hour = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.HOUR_OF_DAY)));
                        select_minute = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.MINUTE)));
                        select_second = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.SECOND)));
                        initData();
                        pvw_hour.setSelected(select_hour);
                        pvw_minute.setSelected(select_minute);
                        pvw_second.setSelected(select_second);
                        break;
                    case DISPLAY_HM://HH:mm:ss
                        select_hour = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.HOUR_OF_DAY)));
                        select_minute = DecimalUtil.keep2zero_head("" + (calendar.get(Calendar.MINUTE)));
                        initData();
                        pvw_hour.setSelected(select_hour);
                        pvw_minute.setSelected(select_minute);
                        break;
                    default:
                        break;
                }
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    //消失
    private OnClickListener cancel_onClick = new OnClickListener() {
        @Override
        public void onClick(View v) {
            dismiss();
        }
    };
    //确认
    private OnClickListener tvw_confirm_onClick = new OnClickListener() {
        @Override
        public void onClick(View v) {
            String select_time = "";
            switch (mode) {
                case DISPLAY_YMDHMS:
                    select_time = select_year + "-" + select_month + "-" + select_day + " " + select_hour + ":" + select_minute + ":" + select_second;
                    break;
                case DISPLAY_YMDHM:
                    select_time = select_year + "-" + select_month + "-" + select_day + " " + select_hour + ":" + select_minute;
                    break;
                case DISPLAY_YMD:
                    select_time = select_year + "-" + select_month + "-" + select_day;
                    break;
                case DISPLAY_HMS:
                    select_time = select_hour + ":" + select_minute + ":" + select_second;
                    break;
                case DISPLAY_HM:
                    select_time = select_hour + ":" + select_minute;
                    break;
                default:
                    break;
            }
            if (onTimeSelectListener != null) {
                onTimeSelectListener.onSelect(select_time);
            }
            dismiss();
        }
    };

    //设置显示模式
    public void setMode(String mode) {
        this.mode = mode;
        initDisplayMode();
    }

    //显示时间
    public void showPopWin(View view, String time) {
        displayTime = time;
        initPickViewDisplayData();
        showAtLocation(view, Gravity.BOTTOM, 0, 0);
    }

    //显示时间控件
    public void showPopWin(View view) {
        displayTime = null;
        initPickViewDisplayData();
        showAtLocation(view, Gravity.BOTTOM, 0, 0);
    }

    //显示当前时间
    public void showPopWinPresentTime(View view) {
        String displayTime = DateUtil.formatDate(new Date(), mode);
        showPopWin(view, displayTime);
    }

    //设置是否显示过去时间
    public void setIsDisplayPastTime(boolean isDisplayPastTime) {
        this.isDisplayPastTime = isDisplayPastTime;
        if (!isDisplayPastTime) {
            startTime = DateUtil.formatDate(new Date(), DISPLAY_YMDHMS);
        }
    }

    //年选择监听
    private onSelectListener year_onSelect = new onSelectListener() {
        @Override
        public void onSelect(String text) {
            select_year = text;
            initMonth(true);
        }
    };
    //月选择监听
    private onSelectListener month_onSelect = new onSelectListener() {
        @Override
        public synchronized void onSelect(String text) {
            select_month = text;
            initDay(true);
        }
    };
    //日选择监听
    private onSelectListener day_onSelect = new onSelectListener() {
        @Override
        public void onSelect(String text) {
            select_day = text;
            initHour(true);
        }
    };
    //时选择监听
    private onSelectListener hour_onSelect = new onSelectListener() {
        @Override
        public void onSelect(String text) {
            select_hour = text;
            initMinute(true);
        }
    };
    //分选择监听
    private onSelectListener min_onSelect = new onSelectListener() {
        @Override
        public void onSelect(String text) {
            select_minute = text;
            initSecond(true);
        }
    };
    //秒选择监听
    private PickerView.onSelectListener sec_onSelect = new onSelectListener() {
        @Override
        public void onSelect(String text) {
            select_second = text;
        }
    };

    //动画
    private void excuteAnimator(long ANIMATORDELAY, View view) {
        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f);
        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 1.3f, 1f);
        PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 1.3f, 1f);
        ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY, pvhZ).setDuration(ANIMATORDELAY).start();
    }

    //定义时间选择接口
    public interface onTimeSelectListener {
        void onSelect(String time);
    }

    public void setOnTimeSelectListener(onTimeSelectListener onTimeSelectListener) {
        this.onTimeSelectListener = onTimeSelectListener;
    }
}

7.页面中使用时间选择器(点击事件中调用时间选择器)

    /**
     * 初始化时间选择器
     */
    private TimePickerView timePickerView;//时间选择器
    private void initTimePickerView(View v) {
        if (timePickerView != null && !timePickerView.isShowing()) {
            timePickerView.dismiss();
            timePickerView = null;
        }
        timePickerView = new TimePickerView(ActivityLaunchApplication.this);
        timePickerView.setMode(TimePickerView.DISPLAY_YMDHM);
        //timePickerView.setIsDisplayPastTime(false);
        String time = "";
        if (StringUtil.isEmpty(time)) {
            time = DateUtil.formatDate(new Date(), TimePickerView.DISPLAY_YMDHM);
        }
        timePickerView.showPopWin(v, time);
        timePickerView.setOnTimeSelectListener(new TimePickerView.onTimeSelectListener() {
            @Override
            public void onSelect(String time) {//所选时间
                hopeAcceptDate = time;
                stvYsSj.setText(time);
            }
        });
    }

8.效果图

相关推荐
ZSYP-S6 分钟前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos9 分钟前
c++------------------函数
开发语言·c++
yuanbenshidiaos13 分钟前
C++----------函数的调用机制
java·c++·算法
程序员_三木21 分钟前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
是小崔啊31 分钟前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
tianmu_sama37 分钟前
[Effective C++]条款38-39 复合和private继承
开发语言·c++
黄公子学安全40 分钟前
Java的基础概念(一)
java·开发语言·python
liwulin050641 分钟前
【JAVA】Tesseract-OCR截图屏幕指定区域识别0.4.2
java·开发语言·ocr
jackiendsc1 小时前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
Yuan_o_1 小时前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端