Android 时间选择器(年月日不嵌套)

前言

  • 日期选择器(DatePickerView)
  • 如果这个效果不适合您,可以看看我之前写的另个选择器 链接
  • 在使用 DatePicker 控件显示日期时,通常是使用 < DatePickerView>标记在XML布局文件中配置,基本用法如下
     

 

接下来我们看下效果图:

在开发中我们可以根据自己写需求进行选择是否带有分秒样式,判断是否显示时和分

customDatePicker.showSpecificTime(true); // 不显示时和分        customDatePicker.setIsLoop(false); // 不允许循环滚动

废话不多说我们直接上代码:

首先我们看下CustomDatePicker:

import android.animation.ObjectAnimator;import android.animation.PropertyValuesHolder;import android.app.Dialog;import android.content.Context;import android.util.DisplayMetrics;import android.view.Gravity;import android.view.View;import android.view.Window;import android.view.WindowManager;import android.widget.TextView;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Calendar;import java.util.Locale;public class CustomDatePicker {    /**     * 定义结果回调接口     */    public interface ResultHandler {        void handle(String time);    }    public enum SCROLL_TYPE {        HOUR(1),        MINUTE(2);        SCROLL_TYPE(int value) {            this.value = value;        }        public int value;    }    private int scrollUnits = SCROLL_TYPE.HOUR.value + SCROLL_TYPE.MINUTE.value;    private ResultHandler handler;    private Context context;    private boolean canAccess = false;    private Dialog datePickerDialog;    private DatePickerView year_pv, month_pv, day_pv, hour_pv, minute_pv;    private static final int MAX_MINUTE = 59;    private static final int MAX_HOUR = 23;    private static final int MIN_MINUTE = 0;    private static final int MIN_HOUR = 0;    private static final int MAX_MONTH = 12;    private ArrayList year, month, day, hour, minute;    private int startYear, startMonth, startDay, startHour, startMinute, endYear, endMonth, endDay, endHour, endMinute;    private boolean spanYear, spanMon, spanDay, spanHour, spanMin;    private Calendar selectedCalender, startCalendar, endCalendar;    private TextView tv_cancle, tv_select, hour_text, minute_text;    public CustomDatePicker(Context context, ResultHandler resultHandler, String startDate, String endDate) {        if (isValidDate(startDate, "yyyy-MM-dd HH:mm") && isValidDate(endDate, "yyyy-MM-dd HH:mm")) {            canAccess = true;            this.context = context;            this.handler = resultHandler;            selectedCalender = Calendar.getInstance();            startCalendar = Calendar.getInstance();            endCalendar = Calendar.getInstance();            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.CHINA);            try {                startCalendar.setTime(sdf.parse(startDate));                endCalendar.setTime(sdf.parse(endDate));            } catch (ParseException e) {                e.printStackTrace();            }            initDialog();            initView();        }    }    private void initDialog() {        if (datePickerDialog == null) {            datePickerDialog = new Dialog(context, R.style.time_dialog);            datePickerDialog.setCancelable(false);            datePickerDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);            datePickerDialog.setContentView(R.layout.custom_date_picker);            Window window = datePickerDialog.getWindow();            window.setGravity(Gravity.BOTTOM);            WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);            DisplayMetrics dm = new DisplayMetrics();            manager.getDefaultDisplay().getMetrics(dm);            WindowManager.LayoutParams lp = window.getAttributes();            lp.width = dm.widthPixels;            window.setAttributes(lp);        }    }    private void initView() {        year_pv = (DatePickerView) datePickerDialog.findViewById(R.id.year_pv);        month_pv = (DatePickerView) datePickerDialog.findViewById(R.id.month_pv);        day_pv = (DatePickerView) datePickerDialog.findViewById(R.id.day_pv);        hour_pv = (DatePickerView) datePickerDialog.findViewById(R.id.hour_pv);        minute_pv = (DatePickerView) datePickerDialog.findViewById(R.id.minute_pv);        tv_cancle = (TextView) datePickerDialog.findViewById(R.id.tv_cancle);        tv_select = (TextView) datePickerDialog.findViewById(R.id.tv_select);        hour_text = (TextView) datePickerDialog.findViewById(R.id.hour_text);        minute_text = (TextView) datePickerDialog.findViewById(R.id.minute_text);        tv_cancle.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                datePickerDialog.dismiss();            }        });        tv_select.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.CHINA);                handler.handle(sdf.format(selectedCalender.getTime()));                datePickerDialog.dismiss();            }        });    }    private void initParameter() {        startYear = startCalendar.get(Calendar.YEAR);        startMonth = startCalendar.get(Calendar.MONTH) + 1;        startDay = startCalendar.get(Calendar.DAY_OF_MONTH);        startHour = startCalendar.get(Calendar.HOUR_OF_DAY);        startMinute = startCalendar.get(Calendar.MINUTE);        endYear = endCalendar.get(Calendar.YEAR);        endMonth = endCalendar.get(Calendar.MONTH) + 1;        endDay = endCalendar.get(Calendar.DAY_OF_MONTH);        endHour = endCalendar.get(Calendar.HOUR_OF_DAY);        endMinute = endCalendar.get(Calendar.MINUTE);        spanYear = startYear != endYear;        spanMon = (!spanYear) && (startMonth != endMonth);        spanDay = (!spanMon) && (startDay != endDay);        spanHour = (!spanDay) && (startHour != endHour);        spanMin = (!spanHour) && (startMinute != endMinute);        selectedCalender.setTime(startCalendar.getTime());    }    private void initTimer() {        initArrayList();        if (spanYear) {            for (int i = startYear; i <= endYear; i++) {                year.add(String.valueOf(i));            }            for (int i = startMonth; i <= MAX_MONTH; i++) {                month.add(formatTimeUnit(i));            }            for (int i = startDay; i <= startCalendar.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {                day.add(formatTimeUnit(i));            }            if ((scrollUnits & SCROLL_TYPE.HOUR.value) != SCROLL_TYPE.HOUR.value) {                hour.add(formatTimeUnit(startHour));            } else {                for (int i = startHour; i <= MAX_HOUR; i++) {                    hour.add(formatTimeUnit(i));                }            }            if ((scrollUnits & SCROLL_TYPE.MINUTE.value) != SCROLL_TYPE.MINUTE.value) {                minute.add(formatTimeUnit(startMinute));            } else {                for (int i = startMinute; i <= MAX_MINUTE; i++) {                    minute.add(formatTimeUnit(i));                }            }        } else if (spanMon) {            year.add(String.valueOf(startYear));            for (int i = startMonth; i <= endMonth; i++) {                month.add(formatTimeUnit(i));            }            for (int i = startDay; i <= startCalendar.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {                day.add(formatTimeUnit(i));            }            if ((scrollUnits & SCROLL_TYPE.HOUR.value) != SCROLL_TYPE.HOUR.value) {                hour.add(formatTimeUnit(startHour));            } else {                for (int i = startHour; i <= MAX_HOUR; i++) {                    hour.add(formatTimeUnit(i));                }            }            if ((scrollUnits & SCROLL_TYPE.MINUTE.value) != SCROLL_TYPE.MINUTE.value) {                minute.add(formatTimeUnit(startMinute));            } else {                for (int i = startMinute; i <= MAX_MINUTE; i++) {                    minute.add(formatTimeUnit(i));                }            }        } else if (spanDay) {            year.add(String.valueOf(startYear));            month.add(formatTimeUnit(startMonth));            for (int i = startDay; i <= endDay; i++) {                day.add(formatTimeUnit(i));            }            if ((scrollUnits & SCROLL_TYPE.HOUR.value) != SCROLL_TYPE.HOUR.value) {                hour.add(formatTimeUnit(startHour));            } else {                for (int i = startHour; i <= MAX_HOUR; i++) {                    hour.add(formatTimeUnit(i));                }            }            if ((scrollUnits & SCROLL_TYPE.MINUTE.value) != SCROLL_TYPE.MINUTE.value) {                minute.add(formatTimeUnit(startMinute));            } else {                for (int i = startMinute; i <= MAX_MINUTE; i++) {                    minute.add(formatTimeUnit(i));                }            }        } else if (spanHour) {            year.add(String.valueOf(startYear));            month.add(formatTimeUnit(startMonth));            day.add(formatTimeUnit(startDay));            if ((scrollUnits & SCROLL_TYPE.HOUR.value) != SCROLL_TYPE.HOUR.value) {                hour.add(formatTimeUnit(startHour));            } else {                for (int i = startHour; i <= endHour; i++) {                    hour.add(formatTimeUnit(i));                }            }            if ((scrollUnits & SCROLL_TYPE.MINUTE.value) != SCROLL_TYPE.MINUTE.value) {                minute.add(formatTimeUnit(startMinute));            } else {                for (int i = startMinute; i <= MAX_MINUTE; i++) {                    minute.add(formatTimeUnit(i));                }            }        } else if (spanMin) {            year.add(String.valueOf(startYear));            month.add(formatTimeUnit(startMonth));            day.add(formatTimeUnit(startDay));            hour.add(formatTimeUnit(startHour));            if ((scrollUnits & SCROLL_TYPE.MINUTE.value) != SCROLL_TYPE.MINUTE.value) {                minute.add(formatTimeUnit(startMinute));            } else {                for (int i = startMinute; i <= endMinute; i++) {                    minute.add(formatTimeUnit(i));                }            }        }        loadComponent();    }    /**     * 将“0-9”转换为“00-09”     */    private String formatTimeUnit(int unit) {        return unit < 10 ? "0" + String.valueOf(unit) : String.valueOf(unit);    }    private void initArrayList() {        if (year == null) year = new ArrayList<>();        if (month == null) month = new ArrayList<>();        if (day == null) day = new ArrayList<>();        if (hour == null) hour = new ArrayList<>();        if (minute == null) minute = new ArrayList<>();        year.clear();        month.clear();        day.clear();        hour.clear();        minute.clear();    }    private void loadComponent() {        year_pv.setData(year);        month_pv.setData(month);        day_pv.setData(day);        hour_pv.setData(hour);        minute_pv.setData(minute);        year_pv.setSelected(0);        month_pv.setSelected(0);        day_pv.setSelected(0);        hour_pv.setSelected(0);        minute_pv.setSelected(0);        executeScroll();    }    private void addListener() {        year_pv.setOnSelectListener(new DatePickerView.onSelectListener() {            @Override            public void onSelect(String text) {                selectedCalender.set(Calendar.YEAR, Integer.parseInt(text));                monthChange();            }        });        month_pv.setOnSelectListener(new DatePickerView.onSelectListener() {            @Override            public void onSelect(String text) {                selectedCalender.set(Calendar.DAY_OF_MONTH, 1);                selectedCalender.set(Calendar.MONTH, Integer.parseInt(text) - 1);                dayChange();            }        });        day_pv.setOnSelectListener(new DatePickerView.onSelectListener() {            @Override            public void onSelect(String text) {                selectedCalender.set(Calendar.DAY_OF_MONTH, Integer.parseInt(text));                hourChange();            }        });        hour_pv.setOnSelectListener(new DatePickerView.onSelectListener() {            @Override            public void onSelect(String text) {                selectedCalender.set(Calendar.HOUR_OF_DAY, Integer.parseInt(text));                minuteChange();            }        });        minute_pv.setOnSelectListener(new DatePickerView.onSelectListener() {            @Override            public void onSelect(String text) {                selectedCalender.set(Calendar.MINUTE, Integer.parseInt(text));            }        });    }    private void monthChange() {        month.clear();        int selectedYear = selectedCalender.get(Calendar.YEAR);        if (selectedYear == startYear) {            for (int i = startMonth; i <= MAX_MONTH; i++) {                month.add(formatTimeUnit(i));            }        } else if (selectedYear == endYear) {            for (int i = 1; i <= endMonth; i++) {                month.add(formatTimeUnit(i));            }        } else {            for (int i = 1; i <= MAX_MONTH; i++) {                month.add(formatTimeUnit(i));            }        }        selectedCalender.set(Calendar.MONTH, Integer.parseInt(month.get(0)) - 1);        month_pv.setData(month);        month_pv.setSelected(0);        executeAnimator(month_pv);        month_pv.postDelayed(new Runnable() {            @Override            public void run() {                dayChange();            }        }, 100);    }    private void dayChange() {        day.clear();        int selectedYear = selectedCalender.get(Calendar.YEAR);        int selectedMonth = selectedCalender.get(Calendar.MONTH) + 1;        if (selectedYear == startYear && selectedMonth == startMonth) {            for (int i = startDay; i <= selectedCalender.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {                day.add(formatTimeUnit(i));            }        } else if (selectedYear == endYear && selectedMonth == endMonth) {            for (int i = 1; i <= endDay; i++) {                day.add(formatTimeUnit(i));            }        } else {            for (int i = 1; i <= selectedCalender.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {                day.add(formatTimeUnit(i));            }        }        selectedCalender.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day.get(0)));        day_pv.setData(day);        day_pv.setSelected(0);        executeAnimator(day_pv);        day_pv.postDelayed(new Runnable() {            @Override            public void run() {                hourChange();            }        }, 100);    }    private void hourChange() {        if ((scrollUnits & SCROLL_TYPE.HOUR.value) == SCROLL_TYPE.HOUR.value) {            hour.clear();            int selectedYear = selectedCalender.get(Calendar.YEAR);            int selectedMonth = selectedCalender.get(Calendar.MONTH) + 1;            int selectedDay = selectedCalender.get(Calendar.DAY_OF_MONTH);            if (selectedYear == startYear && selectedMonth == startMonth && selectedDay == startDay) {                for (int i = startHour; i <= MAX_HOUR; i++) {                    hour.add(formatTimeUnit(i));                }            } else if (selectedYear == endYear && selectedMonth == endMonth && selectedDay == endDay) {                for (int i = MIN_HOUR; i <= endHour; i++) {                    hour.add(formatTimeUnit(i));                }            } else {                for (int i = MIN_HOUR; i <= MAX_HOUR; i++) {                    hour.add(formatTimeUnit(i));                }            }            selectedCalender.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour.get(0)));            hour_pv.setData(hour);            hour_pv.setSelected(0);            executeAnimator(hour_pv);        }        hour_pv.postDelayed(new Runnable() {            @Override            public void run() {                minuteChange();            }        }, 100);    }    private void minuteChange() {        if ((scrollUnits & SCROLL_TYPE.MINUTE.value) == SCROLL_TYPE.MINUTE.value) {            minute.clear();            int selectedYear = selectedCalender.get(Calendar.YEAR);            int selectedMonth = selectedCalender.get(Calendar.MONTH) + 1;            int selectedDay = selectedCalender.get(Calendar.DAY_OF_MONTH);            int selectedHour = selectedCalender.get(Calendar.HOUR_OF_DAY);            if (selectedYear == startYear && selectedMonth == startMonth && selectedDay == startDay && selectedHour == startHour) {                for (int i = startMinute; i <= MAX_MINUTE; i++) {                    minute.add(formatTimeUnit(i));                }            } else if (selectedYear == endYear && selectedMonth == endMonth && selectedDay == endDay && selectedHour == endHour) {                for (int i = MIN_MINUTE; i <= endMinute; i++) {                    minute.add(formatTimeUnit(i));                }            } else {                for (int i = MIN_MINUTE; i <= MAX_MINUTE; i++) {                    minute.add(formatTimeUnit(i));                }            }            selectedCalender.set(Calendar.MINUTE, Integer.parseInt(minute.get(0)));            minute_pv.setData(minute);            minute_pv.setSelected(0);            executeAnimator(minute_pv);        }        executeScroll();    }    private void executeAnimator(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(200).start();    }    private void executeScroll() {        year_pv.setCanScroll(year.size() > 1);        month_pv.setCanScroll(month.size() > 1);        day_pv.setCanScroll(day.size() > 1);        hour_pv.setCanScroll(hour.size() > 1 && (scrollUnits & SCROLL_TYPE.HOUR.value) == SCROLL_TYPE.HOUR.value);        minute_pv.setCanScroll(minute.size() > 1 && (scrollUnits & SCROLL_TYPE.MINUTE.value) == SCROLL_TYPE.MINUTE.value);    }    private int disScrollUnit(SCROLL_TYPE... scroll_types) {        if (scroll_types == null || scroll_types.length == 0) {            scrollUnits = SCROLL_TYPE.HOUR.value + SCROLL_TYPE.MINUTE.value;        } else {            for (SCROLL_TYPE scroll_type : scroll_types) {                scrollUnits ^= scroll_type.value;            }        }        return scrollUnits;    }    public void show(String time) {        if (canAccess) {            if (isValidDate(time, "yyyy-MM-dd")) {                if (startCalendar.getTime().getTime() < endCalendar.getTime().getTime()) {                    canAccess = true;                    initParameter();                    initTimer();                    addListener();                    setSelectedTime(time);                    datePickerDialog.show();                }            } else {                canAccess = false;            }        }    }    /**     * 设置日期控件是否显示时和分     */    public void showSpecificTime(boolean show) {        if (canAccess) {            if (show) {                disScrollUnit();                hour_pv.setVisibility(View.VISIBLE);                hour_text.setVisibility(View.VISIBLE);                minute_pv.setVisibility(View.VISIBLE);                minute_text.setVisibility(View.VISIBLE);            } else {                disScrollUnit(SCROLL_TYPE.HOUR, SCROLL_TYPE.MINUTE);                hour_pv.setVisibility(View.GONE);                hour_text.setVisibility(View.GONE);                minute_pv.setVisibility(View.GONE);                minute_text.setVisibility(View.GONE);            }        }    }    /**     * 设置日期控件是否可以循环滚动     */    public void setIsLoop(boolean isLoop) {        if (canAccess) {            this.year_pv.setIsLoop(isLoop);            this.month_pv.setIsLoop(isLoop);            this.day_pv.setIsLoop(isLoop);            this.hour_pv.setIsLoop(isLoop);            this.minute_pv.setIsLoop(isLoop);        }    }    /**     * 设置日期控件默认选中的时间     */    public void setSelectedTime(String time) {        if (canAccess) {            String[] str = time.split(" ");            String[] dateStr = str[0].split("-");            year_pv.setSelected(dateStr[0]);            selectedCalender.set(Calendar.YEAR, Integer.parseInt(dateStr[0]));            month.clear();            int selectedYear = selectedCalender.get(Calendar.YEAR);            if (selectedYear == startYear) {                for (int i = startMonth; i <= MAX_MONTH; i++) {                    month.add(formatTimeUnit(i));                }            } else if (selectedYear == endYear) {                for (int i = 1; i <= endMonth; i++) {                    month.add(formatTimeUnit(i));                }            } else {                for (int i = 1; i <= MAX_MONTH; i++) {                    month.add(formatTimeUnit(i));                }            }            month_pv.setData(month);            month_pv.setSelected(dateStr[1]);            selectedCalender.set(Calendar.MONTH, Integer.parseInt(dateStr[1]) - 1);            executeAnimator(month_pv);            day.clear();            int selectedMonth = selectedCalender.get(Calendar.MONTH) + 1;            if (selectedYear == startYear && selectedMonth == startMonth) {                for (int i = startDay; i <= selectedCalender.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {                    day.add(formatTimeUnit(i));                }            } else if (selectedYear == endYear && selectedMonth == endMonth) {                for (int i = 1; i <= endDay; i++) {                    day.add(formatTimeUnit(i));                }            } else {                for (int i = 1; i <= selectedCalender.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {                    day.add(formatTimeUnit(i));                }            }            day_pv.setData(day);            day_pv.setSelected(dateStr[2]);            selectedCalender.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStr[2]));            executeAnimator(day_pv);            if (str.length == 2) {                String[] timeStr = str[1].split(":");                if ((scrollUnits & SCROLL_TYPE.HOUR.value) == SCROLL_TYPE.HOUR.value) {                    hour.clear();                    int selectedDay = selectedCalender.get(Calendar.DAY_OF_MONTH);                    if (selectedYear == startYear && selectedMonth == startMonth && selectedDay == startDay) {                        for (int i = startHour; i <= MAX_HOUR; i++) {                            hour.add(formatTimeUnit(i));                        }                    } else if (selectedYear == endYear && selectedMonth == endMonth && selectedDay == endDay) {                        for (int i = MIN_HOUR; i <= endHour; i++) {                            hour.add(formatTimeUnit(i));                        }                    } else {                        for (int i = MIN_HOUR; i <= MAX_HOUR; i++) {                            hour.add(formatTimeUnit(i));                        }                    }                    hour_pv.setData(hour);                    hour_pv.setSelected(timeStr[0]);                    selectedCalender.set(Calendar.HOUR_OF_DAY, Integer.parseInt(timeStr[0]));                    executeAnimator(hour_pv);                }                if ((scrollUnits & SCROLL_TYPE.MINUTE.value) == SCROLL_TYPE.MINUTE.value) {                    minute.clear();                    int selectedDay = selectedCalender.get(Calendar.DAY_OF_MONTH);                    int selectedHour = selectedCalender.get(Calendar.HOUR_OF_DAY);                    if (selectedYear == startYear && selectedMonth == startMonth && selectedDay == startDay && selectedHour == startHour) {                        for (int i = startMinute; i <= MAX_MINUTE; i++) {                            minute.add(formatTimeUnit(i));                        }                    } else if (selectedYear == endYear && selectedMonth == endMonth && selectedDay == endDay && selectedHour == endHour) {                        for (int i = MIN_MINUTE; i <= endMinute; i++) {                            minute.add(formatTimeUnit(i));                        }                    } else {                        for (int i = MIN_MINUTE; i <= MAX_MINUTE; i++) {                            minute.add(formatTimeUnit(i));                        }                    }                    minute_pv.setData(minute);                    minute_pv.setSelected(timeStr[1]);                    selectedCalender.set(Calendar.MINUTE, Integer.parseInt(timeStr[1]));                    executeAnimator(minute_pv);                }            }            executeScroll();        }    }    /**     * 验证字符串是否是一个合法的日期格式     */    private boolean isValidDate(String date, String template) {        boolean convertSuccess = true;        // 指定日期格式        SimpleDateFormat format = new SimpleDateFormat(template, Locale.CHINA);        try {            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期,比如2015/02/29会被接受,并转换成2015/03/01            format.setLenient(false);            format.parse(date);        } catch (Exception e) {            // 如果throw java.text.ParseException或者NullPointerException,就说明格式不对            convertSuccess = false;        }        return convertSuccess;    }}

DatePickerView类我们自定义滑动效果:

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.support.v4.content.ContextCompat;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import java.util.ArrayList;import java.util.List;import java.util.Timer;import java.util.TimerTask;public class DatePickerView extends View {    private Context context;    /**     * 新增字段 控制是否首尾相接循环显示 默认为循环显示     */    private boolean loop = true;    /**     * text之间间距和minTextSize之比     */    public static final float MARGIN_ALPHA = 2.8f;    /**     * 自动回滚到中间的速度     */    public static final float SPEED = 10;    private List mDataList;    /**     * 选中的位置,这个位置是mDataList的中心位置,一直不变     */    private int mCurrentSelected;    private Paint mPaint, nPaint;    private float mMaxTextSize = 80;    private float mMinTextSize = 40;    private float mMaxTextAlpha = 255;    private float mMinTextAlpha = 120;    private int mViewHeight;    private int mViewWidth;    private float mLastDownY;    /**     * 滑动的距离     */    private float mMoveLen = 0;    private boolean isInit = false;    private boolean canScroll = true;    private onSelectListener mSelectListener;    private Timer timer;    private MyTimerTask mTask;    private 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 DatePickerView(Context context, AttributeSet attrs) {        super(context, attrs);        this.context = context;        init();    }    public void setOnSelectListener(onSelectListener listener) {        mSelectListener = listener;    }    private void performSelect() {        if (mSelectListener != null) {            mSelectListener.onSelect(mDataList.get(mCurrentSelected));        }    }    public void setData(List datas) {        mDataList = datas;        mCurrentSelected = datas.size() / 4;        invalidate();    }    /**     * 选择选中的item的index     */    public void setSelected(int selected) {        mCurrentSelected = selected;        if (loop) {            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();    }    /**     * 选择选中的内容     */    public void setSelected(String mSelectItem) {        for (int i = 0; i < mDataList.size(); i++) {            if (mDataList.get(i).equals(mSelectItem)) {                setSelected(i);                break;            }        }    }    private void moveHeadToTail() {        if (loop) {            String head = mDataList.get(0);            mDataList.remove(0);            mDataList.add(head);        }    }    private void moveTailToHead() {        if (loop) {            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<>();        //第一个paint        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mPaint.setStyle(Style.FILL);        mPaint.setTextAlign(Align.CENTER);        mPaint.setColor(ContextCompat.getColor(context, R.color.color_59B29C));        //第二个paint        nPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        nPaint.setStyle(Style.FILL);        nPaint.setTextAlign(Align.CENTER);        nPaint.setColor(ContextCompat.getColor(context, R.color.color_333333));    }    @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 position 距离mCurrentSelected的差值     * @param type     1表示向下绘制,-1表示向上绘制     */    private void drawOtherText(Canvas canvas, int position, int type) {        float d = MARGIN_ALPHA * mMinTextSize * position + type * mMoveLen;        float scale = parabola(mViewHeight / 4.0f, d);        float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;        nPaint.setTextSize(size);        nPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));        float y = (float) (mViewHeight / 2.0 + type * d);        FontMetricsInt fmi = nPaint.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, nPaint);    }    /**     * 抛物线     *     * @param zero 零点坐标     * @param x    偏移量     */    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:                mMoveLen += (event.getY() - mLastDownY);                if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2) {                    if (!loop && mCurrentSelected == 0) {                        mLastDownY = event.getY();                        invalidate();                        return true;                    }                    if (!loop) {                        mCurrentSelected--;                    }                    // 往下滑超过离开距离                    moveTailToHead();                    mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize;                } else if (mMoveLen < -MARGIN_ALPHA * mMinTextSize / 2) {                    if (mCurrentSelected == mDataList.size() - 1) {                        mLastDownY = event.getY();                        invalidate();                        return true;                    }                    if (!loop) {                        mCurrentSelected++;                    }                    // 往上滑超过离开距离                    moveHeadToTail();                    mMoveLen = mMoveLen + MARGIN_ALPHA * mMinTextSize;                }                mLastDownY = event.getY();                invalidate();                break;            case MotionEvent.ACTION_UP:                doUp();                break;        }        return true;    }    private void doDown(MotionEvent event) {        if (mTask != null) {            mTask.cancel();            mTask = null;        }        mLastDownY = event.getY();    }    private void doUp() {        // 抬起手后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);    }    public void setCanScroll(boolean canScroll) {        this.canScroll = canScroll;    }    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        return canScroll && super.dispatchTouchEvent(event);    }    /**     * 控制内容是否首尾相连     */    public void setIsLoop(boolean isLoop) {        loop = isLoop;    }}

 最后我们看下调用方法MainActivity类:
 

import android.app.Activity;import android.os.Bundle;import android.text.TextUtils;import android.util.Log;import android.view.View;import android.widget.TextView;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Locale;public class MainActivity extends Activity implements View.OnClickListener{    private CustomDatePicker customDatePicker;    private String now;    private TextView tv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        tv = findViewById(R.id.tv);        findViewById(R.id.bt).setOnClickListener(this);        DatePicker();    }    /**     * 显示时间     */    private void DatePicker() {        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.CHINA);        //获取当前时间        now = sdf.format(new Date());        //tvElectricalTime.setText(now.split(" ")[0]);        customDatePicker = new CustomDatePicker(this, new CustomDatePicker.ResultHandler() {            @Override            public void handle(String time) { // 回调接口,获得选中的时间                Log.d("yyyyy", time);                tv.setText(time);            }        }, "1990-01-01 00:00", now); // 初始化日期格式请用:yyyy-MM-dd HH:mm,否则不能正常运行        customDatePicker.showSpecificTime(true); // 不显示时和分        customDatePicker.setIsLoop(false); // 不允许循环滚动    }    @Override    public void onClick(View view) {        if (TextUtils.isEmpty(tv.getText().toString().trim()))            customDatePicker.show(now);        else  // 日期格式为yyyy-MM-dd            customDatePicker.show(tv.getText().toString());    }}

这里不用过多的解释了

弹窗样式布局custom_date_picker.xml

<?xml version="1.0" encoding="utf-8"?>                                                                                                                                                                                    

 activity_main.xml类就没有什么东西了,但我还是给大家贴出来吧:
 

<?xml version="1.0" encoding="utf-8"?>  

 这就是主要代码了,还有一些辅助文件我就不贴出来了,希望能帮助到大家.

                                              点我有惊喜哦

 

更多相关文章

  1. Android事件分发机制分析
  2. android studio checkbox复选框的选中,并显示打印出来
  3. Android(安卓)ApiDemos示例解析(106):Views->Chronometer
  4. Android(安卓)Studio——layout_weight体验(实现按比例显示)
  5. android中TextView和EditText长度可变或者填满父控件wrap_conten
  6. 第一行代码 Android(安卓)第 2 版 读书笔记
  7. Android(安卓)XML 用途汇总
  8. android之定时器AlarmManager
  9. 可以在Android上发定时短信

随机推荐

  1. android camera(一):camera模组CMM介绍
  2. android win8效果实现进阶(一)
  3. Android原生项目引入最新的React Native
  4. 安卓巴士Android开发神贴整理
  5. android增加5G热点
  6. android权限设置
  7. Android地图添加标记和文字【代码片段】
  8. ubuntu系统下,搭建Android开发环境!!
  9. Android编译源码时出现的错误: “_FORTIFY
  10. 【Android(安卓)UI】状态栏和toolbar颜色