app/src/main/java/com/jjforever/wgj/maincalendar/wheelpicker/picker/DatePicker.java
public class DatePicker extends WheelPicker {
    /**
     * 年月日
     */
    public static final int YEAR_MONTH_DAY = 0;
    /**
     * 年月
     */
    public static final int YEAR_MONTH = 1;
    /**
     * 月日
     */
    public static final int MONTH_DAY = 2;
    /**
     * 年月日 时分
     */
    public static final int DATE_TIME = 3;
    private ArrayList<String> years = new ArrayList<>();
    private ArrayList<String> months = new ArrayList<>();
    private ArrayList<String> days = new ArrayList<>();
    private ArrayList<String> hours = new ArrayList<>();
    private ArrayList<String> minutes = new ArrayList<>();
    private OnDatePickListener onDatePickListener;
//    private String yearLabel = "年", monthLabel = "月", dayLabel = "日";
//    private String hourLabel = ":", minuteLabel = "";
    private String selectedHour = "", selectedMinute = "";
    private int selectedYearIndex = 0, selectedMonthIndex = 0, selectedDayIndex = 0;
    private int mode = YEAR_MONTH_DAY;

    // 农历日期
    private LunarCalendar mLunar = new LunarCalendar();

    /**
     * 安卓开发应避免使用枚举类（enum），因为相比于静态常量enum会花费两倍以上的内存。
     *
     * @link http ://developer.android.com/training/articles/memory.html#Overhead
     */
    @IntDef(value = {YEAR_MONTH_DAY, YEAR_MONTH, MONTH_DAY, DATE_TIME})
    @Retention(RetentionPolicy.SOURCE)
    @interface Mode {
    }

    /**
     * Instantiates a new Date picker.
     *
     * @param activity the activity
     */
    public DatePicker(Activity activity) {
        this(activity, YEAR_MONTH_DAY);
    }

    /**
     * Instantiates a new Date picker.
     *
     * @param activity the activity
     * @param mode     the mode
     * @see #YEAR_MONTH_DAY #YEAR_MONTH_DAY#YEAR_MONTH_DAY
     * @see #YEAR_MONTH #YEAR_MONTH#YEAR_MONTH
     * @see #MONTH_DAY #MONTH_DAY#MONTH_DAY
     */
    public DatePicker(Activity activity, @Mode int mode) {
        super(activity);
        this.mode = mode;
        for (int i = 2000; i <= 2050; i++) {
            years.add(String.valueOf(i));
        }
        for (int i = 1; i <= 12; i++) {
            months.add(DateUtils.fillZero(i));
        }
        for (int i = 1; i <= 31; i++) {
            days.add(DateUtils.fillZero(i));
        }
        for (int i = 0; i < 24; i++) {
            hours.add(DateUtils.fillZero(i));
        }
        for (int i = 0; i < 60; i++) {
            minutes.add(DateUtils.fillZero(i));
        }
    }

    /**
     * 设置年月日的单位字符
     *
     * @param yearLabel  the year label
     * @param monthLabel the month label
     * @param dayLabel   the day label
     */
//    public void setLabel(String yearLabel, String monthLabel, String dayLabel) {
//        this.yearLabel = yearLabel;
//        this.monthLabel = monthLabel;
//        this.dayLabel = dayLabel;
//    }

    /**
     * 设置要显示的年代范围
     *
     * @param startYear the start year
     * @param endYear   the end year
     */
    public void setRange(int startYear, int endYear) {
        years.clear();
        for (int i = startYear; i <= endYear; i++) {
            years.add(String.valueOf(i));
        }
    }

    private int findItemIndex(ArrayList<String> items, int item) {
        //折半查找有序元素的索引
        int index = Collections.binarySearch(items, item, new Comparator<Object>() {
            @Override
            public int compare(Object lhs, Object rhs) {
                String lhsStr = lhs.toString();
                String rhsStr = rhs.toString();
                lhsStr = lhsStr.startsWith("0") ? lhsStr.substring(1) : lhsStr;
                rhsStr = rhsStr.startsWith("0") ? rhsStr.substring(1) : rhsStr;
                return Integer.parseInt(lhsStr) - Integer.parseInt(rhsStr);
            }
        });
        if (index < 0) {
            index = 0;
        }
        return index;
    }

    /**
     * Sets selected item.
     *
     * @param year  the year
     * @param month the month
     * @param day   the day
     */
    public void setSelectedItem(int year, int month, int day) {
        selectedYearIndex = findItemIndex(years, year);
        selectedMonthIndex = findItemIndex(months, month + 1);
        selectedDayIndex = findItemIndex(days, day);
    }

    /**
     * 设置选择项
     * @param year 年
     * @param month 月
     * @param day 日
     * @param hour 时
     * @param minute 分
     */
    public void setSelectedItem(int year, int month, int day, int hour, int minute)
    {
        setSelectedItem(year, month, day);
        selectedHour = DateUtils.fillZero(hour);
        selectedMinute = DateUtils.fillZero(minute);
    }

    /**
     * Sets selected item.
     *
     * @param yearOrMonth the year or month
     * @param monthOrDay  the month or day
     */
    public void setSelectedItem(int yearOrMonth, int monthOrDay) {
        if (mode == MONTH_DAY) {
            selectedMonthIndex = findItemIndex(months, yearOrMonth + 1);
            selectedDayIndex = findItemIndex(days, monthOrDay);
        } else {
            selectedYearIndex = findItemIndex(years, yearOrMonth);
            selectedMonthIndex = findItemIndex(months, monthOrDay + 1);
        }
    }

    /**
     * Sets on CellDate pick listener.
     *
     * @param listener the listener
     */
    public void setOnDatePickListener(OnDatePickListener listener) {
        this.onDatePickListener = listener;
    }

    /**
     * 更新农历日期
     */
    private void updateLunar()
    {
        mLunar.set(Calendar.YEAR, getSelectedYear());
        mLunar.set(Calendar.MONTH, getSelectedMonth());
        mLunar.set(Calendar.DAY_OF_MONTH, getSelectedDay());
        setTitleText(mLunar.getLunarDateString());
    }

    /**
     * 创建一个滑动选择视图
     * @param layout 要添加的父层
     * @param label 单位标签
     * @return 创建的滑动控件
     */
    private WheelView createWheelView(LinearLayout layout, String label, boolean hide)
    {
        if (hide){
            return null;
        }
        WheelView tmpView = new WheelView(activity.getBaseContext());
        tmpView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
        tmpView.setTextSize(textSize);
        tmpView.setTextColor(textColorNormal, textColorFocus);
        tmpView.setLineVisible(lineVisible);
        tmpView.setLineColor(lineColor);
        tmpView.setOffset(offset);
        layout.addView(tmpView);
        TextView tmpTextView = new TextView(activity);
        tmpTextView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
        tmpTextView.setTextSize(textSize);
        tmpTextView.setTextColor(textColorFocus);
        if (!TextUtils.isEmpty(label)) {
            tmpTextView.setText(label);
        }
        layout.addView(tmpTextView);

//        if (hide){
//            tmpView.setVisibility(View.GONE);
//            tmpTextView.setVisibility(View.GONE);
//        }

        return tmpView;
    }

    @Override
    @NonNull
    protected View makeCenterView() {
        LinearLayout layout = new LinearLayout(activity);
        layout.setOrientation(LinearLayout.HORIZONTAL);
        layout.setGravity(Gravity.CENTER);
        WheelView yearView = createWheelView(layout, "-", mode == MONTH_DAY);
        WheelView monthView = createWheelView(layout, "-", false);
        final WheelView dayView = createWheelView(layout, "", mode == YEAR_MONTH);

        WheelView hourView = createWheelView(layout, ":", mode != DATE_TIME);
        WheelView minuteView = createWheelView(layout, "", mode != DATE_TIME);

        if (mode == DATE_TIME){
            hourView.setItems(hours, selectedHour);
            minuteView.setItems(minutes, selectedMinute);
            hourView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
                @Override
                public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
                    selectedHour = item;
                }
            });
            minuteView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
                @Override
                public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
                    selectedMinute = item;
                }
            });
        }

        if (mode != MONTH_DAY) {
            if (selectedYearIndex == 0) {
                yearView.setItems(years);
            } else {
                yearView.setItems(years, selectedYearIndex);
            }
            yearView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
                @Override
                public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
                    selectedYearIndex = selectedIndex;
                    //需要根据年份及月份动态计算天数
                    days.clear();
                    int maxDays = DateUtils.calculateDaysInMonth(stringToYearMonthDay(item), stringToYearMonthDay(months.get(selectedMonthIndex)));
                    for (int i = 1; i <= maxDays; i++) {
                        days.add(DateUtils.fillZero(i));
                    }
                    if (selectedDayIndex >= maxDays) {
                        //年或月变动时，保持之前选择的日不动：如果之前选择的日是之前年月的最大日，则日自动为该年月的最大日
                        selectedDayIndex = days.size() - 1;
                    }
                    dayView.setItems(days, selectedDayIndex);
                    updateLunar();
                }
            });
        }

        if (selectedMonthIndex == 0) {
            monthView.setItems(months);
        } else {
            monthView.setItems(months, selectedMonthIndex);
        }
        monthView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
            @Override
            public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
                selectedMonthIndex = selectedIndex;
                if (mode != YEAR_MONTH) {
                    //年月日或年月模式下，需要根据年份及月份动态计算天数
                    days.clear();
                    int maxDays = DateUtils.calculateDaysInMonth(stringToYearMonthDay(years.get(selectedYearIndex)), stringToYearMonthDay(item));
                    for (int i = 1; i <= maxDays; i++) {
                        days.add(DateUtils.fillZero(i));
                    }
                    if (selectedDayIndex >= maxDays) {
                        //年或月变动时，保持之前选择的日不动：如果之前选择的日是之前年月的最大日，则日自动为该年月的最大日
                        selectedDayIndex = days.size() - 1;
                    }
                    dayView.setItems(days, selectedDayIndex);
                    updateLunar();
                }
            }
        });
        if (mode != YEAR_MONTH) {
            if (selectedDayIndex == 0) {
                dayView.setItems(days);
            } else {
                dayView.setItems(days, selectedDayIndex);
            }
            dayView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
                @Override
                public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
                    selectedDayIndex = selectedIndex;
                    updateLunar();
                }
            });
        }
        return layout;
    }

    private int stringToYearMonthDay(String text) {
        if (text.startsWith("0") && text.length() > 1) {
            //截取掉前缀0以便转换为整数
            text = text.substring(1);
        }
        return Integer.parseInt(text);
    }

    @Override
    protected void onSubmit() {
        if (onDatePickListener != null) {
            int year = getSelectedYear();
            int month = getSelectedMonth();
            int day = getSelectedDay();
            switch (mode) {
                case YEAR_MONTH:
                    ((OnYearMonthPickListener) onDatePickListener).onDatePicked(year, month);
                    break;
                case MONTH_DAY:
                    ((OnMonthDayPickListener) onDatePickListener).onDatePicked(month, day);
                    break;
                case DATE_TIME:
                    ((OnAllPickListener) onDatePickListener).onDatePicked(year, month, day,
                                                        getSelectedHour(), getSelectedMinute());
                    break;
                default:
                    ((OnYearMonthDayPickListener) onDatePickListener).onDatePicked(year, month, day);
                    break;
            }
        }
    }

    /**
     * Gets selected year.
     *
     * @return the selected year
     */
    public int getSelectedYear() {
        return stringToYearMonthDay(years.get(selectedYearIndex));
    }

    /**
     * Gets selected month.
     *
     * @return the selected month
     */
    public int getSelectedMonth() {
        return stringToYearMonthDay(months.get(selectedMonthIndex)) - 1;
    }

    /**
     * Gets selected day.
     *
     * @return the selected day
     */
    public int getSelectedDay() {
        return stringToYearMonthDay(days.get(selectedDayIndex));
    }
    /**
     * Gets selected hour.
     *
     * @return the selected hour
     */
    public int getSelectedHour() {
        return stringToYearMonthDay(selectedHour);
    }

    /**
     * Gets selected minute.
     *
     * @return the selected minute
     */
    public int getSelectedMinute() {
        return stringToYearMonthDay(selectedMinute);
    }

    /**
     * The interface On CellDate pick listener.
     */
    interface OnDatePickListener {

    }

    /**
     * The interface On year month day pick listener.
     */
    public interface OnYearMonthDayPickListener extends OnDatePickListener {

        /**
         * On CellDate picked.
         *
         * @param year  the year
         * @param month the month
         * @param day   the day
         */
        void onDatePicked(int year, int month, int day);

    }

    /**
     * 设置最详细的监听接口
     */
    public interface OnAllPickListener extends OnDatePickListener {

        /**
         * On CellDate picked.
         *
         * @param year  the year
         * @param month the month
         * @param day   the day
         * @param hour 时
         * @param minute 分
         */
        void onDatePicked(int year, int month, int day, int hour, int minute);
    }

    /**
     * The interface On year month pick listener.
     */
    interface OnYearMonthPickListener extends OnDatePickListener {

        /**
         * On CellDate picked.
         *
         * @param year  the year
         * @param month the month
         */
        void onDatePicked(int year, int month);

    }

    /**
     * The interface On month day pick listener.
     */
    public interface OnMonthDayPickListener extends OnDatePickListener {

        /**
         * On CellDate picked.
         *
         * @param month the month
         * @param day   the day
         */
        void onDatePicked(int month, int day);

    }

}
app/src/main/java/com/jjforever/wgj/maincalendar/util/LunarCalendar.java
public class LunarCalendar extends GregorianCalendar{

    private static final long serialVersionUID = 8L;

    /** 农历年属性 */
    public static final int LUNAR_YEAR = 801;
    /** 农历月属性 */
    public static final int LUNAR_MONTH = 802;
    /** 农历日属性 */
    public static final int LUNAR_DATE = 803;
    /** 当月的节气对应的公历日(前一个节气)属性 */
    static final int LUNAR_SECTIONAL_TERM = 804;
    /** 当月的中气对应的公历日(后一个节气)属性 */
    static final int LUNAR_PRINCIPLE_TERM = 805;
    /** 天干属性 */
    static final int LUNAR_HEAVENLY_STEM = 806;
    /** 地支属性 */
    static final int LUNAR_EARTHLY_BRANCH = 807;
    /** 农历年的属相(生肖)属性 */
    public static final int LUNAR_ANIMAL = 808;

    // 阴历年
    private int lunarYear;
    // 阴历月 1起始，负数表示闰月
    private int lunarMonth;
    // 阴历日
    private int lunarDate;
    // 当月节气的公历日
    private int sectionalTerm;
    // 当月中气的公历日
    private int principleTerm;
    // 农历日期是否已经经过计算确认
    private boolean areLunarFieldsComputed;
    // 节气是否已经经过计算确认
    private boolean areSolarTermsComputed;
    // 最后设置的是不是农历属性
    private boolean lastSetLunar;

    @IntDef(value = {YEAR, MONTH, DAY_OF_MONTH, DAY_OF_WEEK,
    DAY_OF_WEEK_IN_MONTH, DAY_OF_YEAR, HOUR, HOUR_OF_DAY, MINUTE, SECOND,
    LUNAR_ANIMAL, LUNAR_DATE, LUNAR_EARTHLY_BRANCH, LUNAR_HEAVENLY_STEM,
    LUNAR_YEAR, LUNAR_MONTH, LUNAR_PRINCIPLE_TERM, LUNAR_SECTIONAL_TERM,
    MILLISECOND})
    @Retention(RetentionPolicy.SOURCE)
    @interface Field {
    }

    /** 使用当前时间构造一个实例。 */
    public LunarCalendar() {
        super();
    }

    /** 使用指定时间构造一个实例。 */
    public LunarCalendar(Date d) {
        super.setTime(d);
    }

    /** 使用指定时间构造一个实例。 */
    public LunarCalendar(Calendar c) {
        this(c.getTime());
    }

    /** 使用指定公历日期构造一个实例。 */
    public LunarCalendar(int y, int m, int d) {
        super(y, m, d);
    }

    /**
     * 使用指定日期构造一个农历日期。
     * @param y 农历年
     * @param m 农历月
     * @param d 农历日
     * @param leap 是否为闰月
     */
    public LunarCalendar(int y, int m, int d, boolean leap) {
        this.set(LUNAR_YEAR, y);
        this.set(LUNAR_MONTH, leap ? -m : m);
        this.set(LUNAR_DATE, d);
    }

    /**
     * 设置指定日期属性的值，可以为阴历跟阳历
     * @param field 字段 可为Calendar中定义字段，也可以为本类中定义的字段
     * @param value 要设置的值
     */
    @Override
    public void set(@Field int field, int value) {
        computeIfNeed(field);

        if (isLunarField(field)) {
            // 农历属性
            switch (field) {
                case LUNAR_YEAR:
                    lunarYear = value;
                    break;

                case LUNAR_MONTH:
                    lunarMonth = value;
                    break;

                case LUNAR_DATE:
                    lunarDate = value;
                    break;

                default:
                    throw new IllegalArgumentException("Not supported field: " + field);
            }

            lastSetLunar = true;
        } else {
            // 非农历属性
            super.set(field, value);
            lastSetLunar = false;
        }

        areFieldsSet = false;
        areLunarFieldsComputed = false;
        areSolarTermsComputed = false;
    }

    /**
     * 获取指定日期属性的值，可以为阴历跟阳历
     * @param field 字段 可为Calendar中定义字段，也可以为本类中定义的字段
     * @return 获取的值
     */
    @Override
    public int get(@Field int field) {
        computeIfNeed(field);

        if (!isLunarField(field)) {
            return super.get(field);
        }

        if (!areLunarFieldsComputed) {
            // 计算农历属性
            computeLunarFields();
            areLunarFieldsComputed = true;
        }

        switch (field) {
            case LUNAR_YEAR:
                return lunarYear;

            case LUNAR_MONTH:
                return lunarMonth;

            case LUNAR_DATE:
                return lunarDate;

            case LUNAR_SECTIONAL_TERM:
                if (!areSolarTermsComputed) {
                    computeSolarTerms();
                    areSolarTermsComputed = true;
                }
                return sectionalTerm;

            case LUNAR_PRINCIPLE_TERM:
                if (!areSolarTermsComputed) {
                    computeSolarTerms();
                    areSolarTermsComputed = true;
                }
                return principleTerm;

            case LUNAR_HEAVENLY_STEM:
                return (lunarYear - 4) % 10 + 1;

            case LUNAR_EARTHLY_BRANCH:
            case LUNAR_ANIMAL:
                return (lunarYear - 4) % 12 + 1;

            default:
                throw new IllegalArgumentException("Not supported field: " + field);
        }
    }

    /**
     * 日期指定属性增加指定值
     * @param field 字段 可为Calendar中定义字段，也可以为本类中定义的字段
     * @param amount 要增加的值
     */
    public void add(@Field int field, int amount) {
        computeIfNeed(field);

        if (!isLunarField(field)) {
            super.add(field, amount);

            lastSetLunar = false;
            areLunarFieldsComputed = false;
            areSolarTermsComputed = false;
            return;
        }

        switch (field) {
            case LUNAR_YEAR:
                lunarYear += amount;
                break;

            case LUNAR_MONTH:
                for (int i = 0; i < amount; i++) {
                    lunarMonth = nextLunarMonth(lunarYear, lunarMonth);
                    if (lunarMonth == 1) {
                        lunarYear++;
                    }
                }
                break;

            case LUNAR_DATE:
                int maxDate = daysInLunarMonth(lunarYear, lunarMonth);
                for (int i = 0; i < amount; i++) {
                    lunarDate++;
                    if (lunarDate > maxDate) {
                        lunarDate = 1;
                        lunarMonth = nextLunarMonth(lunarYear, lunarMonth);
                        if (lunarMonth == 1) {
                            lunarYear++;
                        }

                        maxDate = daysInLunarMonth(lunarYear, lunarMonth);
                    }
                }

            default:
                throw new IllegalArgumentException("Not supported field: " + field);
        }

        lastSetLunar = true;
        areFieldsSet = false;
        areSolarTermsComputed = false;
    }

    public void roll(@Field int field, int amount) {
        computeIfNeed(field);

        if (!isLunarField(field)) {
            super.roll(field, amount);
            lastSetLunar = false;
            areLunarFieldsComputed = false;
            areSolarTermsComputed = false;
            return;
        }

        switch (field) {
            case LUNAR_YEAR:
                lunarYear += amount;
                break;

            case LUNAR_MONTH:
                for (int i = 0; i < amount; i++) {
                    lunarMonth = nextLunarMonth(lunarYear, lunarMonth);
                }
                break;

            case LUNAR_DATE:
                int maxDate = daysInLunarMonth(lunarYear, lunarMonth);
                for (int i = 0; i < amount; i++) {
                    lunarDate++;
                    if (lunarDate > maxDate) {
                        lunarDate = 1;
                    }
                }

            default:
                throw new IllegalArgumentException("Not supported field: " + field);
        }

        lastSetLunar = true;
        areFieldsSet = false;
        areSolarTermsComputed = false;
    }

    /**
     * 获得属性的中文，可以使用的属性字段为DAY_OF_WEEK以及所有农历属性字段。
     * @param field 本类中定义的字段
     * @return 农历日期中文字符串
     */
    public String getLunar(@Field int field) {
        switch (field) {
            case LUNAR_YEAR:
                return getLunar(LUNAR_HEAVENLY_STEM)
                        + getLunar(LUNAR_EARTHLY_BRANCH);

            case LUNAR_MONTH:
                return getLunarMonth(lunarMonth);

            case LUNAR_DATE:
                return lunarDateNames[lunarDate];

            case LUNAR_SECTIONAL_TERM:
                return SolarTerm.getSectionalTermName(get(Calendar.MONTH));

            case LUNAR_PRINCIPLE_TERM:
                return SolarTerm.getPrincipleTermName(get(Calendar.MONTH));

            case LUNAR_HEAVENLY_STEM:
//                if (!areSolarTermsComputed) {
//                    computeSolarTerms();
//                    areSolarTermsComputed = true;
//                }
                return stemNames[get(field)];

            case LUNAR_EARTHLY_BRANCH:
//                if (!areSolarTermsComputed) {
//                    computeSolarTerms();
//                    areSolarTermsComputed = true;
//                }
                return branchNames[get(field)];

            case LUNAR_ANIMAL:
                return animalNames[get(field)];

            case Calendar.DAY_OF_WEEK:
                return lunarWeekNames[get(field)];

            default:
                throw new IllegalArgumentException("Not supported field: " + field);
        }
    }

    /**
     * 获取阳历的数字日期 20XX-XX-XX
     * @return 20XX-XX-XX样式的日期描述
     */
    public String toShortString() {
        return String.format(Locale.getDefault(), "%d-%02d-%02d", get(YEAR),
                get(MONTH) + 1, get(DAY_OF_MONTH));
    }

    /**
     * 时间线中用到的时间日期字符串
     * @param showDate 是否显示日期部分
     * @return 日期时间
     */
    public String getTimeLineString(boolean showDate){
        String tmpStr = "";
        if (showDate) {
            tmpStr = String.format(Locale.getDefault(), "%d-%02d-%02d ",
                    get(YEAR), get(MONTH) + 1, get(DAY_OF_MONTH));
        }
        return String.format(Locale.getDefault(), "%s%02d:%02d",
                    tmpStr, get(HOUR_OF_DAY), get(MINUTE));
    }

    /**
     * 获取农历的数字日期 XXXX-XX-XX
     * @return 20XX-XX-XX样式的日期描述
     */
//    public String getSimpleLunarDateString() {
//        return String.format(Locale.getDefault(), "%d-%s-%d",
//                get(LUNAR_YEAR), get(LUNAR_MONTH) > 0 ? ""
//                        + get(LUNAR_MONTH) : "*"
//                        + (-get(LUNAR_MONTH)),
//                get(LUNAR_DATE));
//    }

    /**
     * 获取农历日期天干地支描述
     * @return 天干地支日期描述
     */
    public String getLunarDateString() {
        return new StringBuilder().append(getLunar(LUNAR_YEAR))
                .append(getLunar(LUNAR_ANIMAL))
                .append("年")
                .append(getLunar(LUNAR_MONTH))
                .append("月")
                .append(getLunar(LUNAR_DATE))
                .toString();
    }

    /**
     * 获取农历年及月信息
     * @return 农历年月信息
     */
//    public String getLunarMonthString(){
//        return new StringBuilder().append(getLunar(LUNAR_YEAR))
//                .append(getLunar(LUNAR_ANIMAL))
//                .append("年")
//                .append(getLunar(LUNAR_MONTH))
//                .append("月")
//                .toString();
//    }

    /**
     * 输出公历及农历详细字符串
     * @return 公历及农历详细字符串
     */
    public String toString() {
        return new StringBuilder().append(toShortString())
                .append(" | ")
                .append(getLunar(DAY_OF_WEEK))
                .append(" | [农历]")
                .append(getLunarDateString()).toString();
    }

    /**
     * 输出20XX年XX月XX日 XX:XX
     * @return 用于记录的日期字符串
     */
    public String toRecordTime()
    {
        computeIfNeed(LUNAR_MONTH);

        return String.format(Locale.getDefault(), "%4d年%d月%d日 %02d:%02d\r\n%s月%s %s",
                get(YEAR), get(MONTH) + 1, get(DAY_OF_MONTH),
                get(HOUR_OF_DAY), get(MINUTE),
                getLunar(LUNAR_MONTH), getLunar(LUNAR_DATE), getLunar(DAY_OF_WEEK));
    }

    /**
     * 判断是不是农历属性
     * @param field 要判断的字段
     * @return 是否为农历属性字段
     */
    private boolean isLunarField(int field) {
        switch (field) {
            case LUNAR_YEAR:
            case LUNAR_MONTH:
            case LUNAR_DATE:
            case LUNAR_SECTIONAL_TERM:
            case LUNAR_PRINCIPLE_TERM:
            case LUNAR_HEAVENLY_STEM:
            case LUNAR_EARTHLY_BRANCH:
            case LUNAR_ANIMAL:
                return true;

            default:
                return false;
        }
    }

    /**
     * 更新农历信息
     */
    public void updateLunar(){
        computeIfNeed(LUNAR_DATE);
    }

    /**
     * 如果上一次设置的与这次将要设置或获取的属性不是同一类（农历/公历），
     * 例如上一次设置的是农历而现在要设置或获取公历，
     * 则需要先根据之前设置的农历日期计算出公历日期。
     * @param field 根据字段判断是否需要进行阴阳历转换
     */
    private void computeIfNeed(int field) {
        if (isLunarField(field)) {
            if (!lastSetLunar && !areLunarFieldsComputed) {
                super.complete();
                computeLunarFields();
                areFieldsSet = true;
                areLunarFieldsComputed = true;
                areSolarTermsComputed = false;
            }
        } else {
            if (lastSetLunar && !areFieldsSet) {
                computeGregorianFields();
                super.complete();
                areFieldsSet = true;
                areLunarFieldsComputed = true;
                areSolarTermsComputed = false;
            }
        }
    }

    /**
     * 使用农历日期计算出公历日期
     */
    private void computeGregorianFields() {
        int y = lunarYear;
        int m = lunarMonth;
        int d = lunarDate;

        areLunarFieldsComputed = true;
        areFieldsSet = true;
        lastSetLunar = false;

        // 调整日期范围
        if (y < 1900) {
            y = 1899;
        }
        else if (y > 2100) {
            y = 2101;
        }
        
        if (m < -12) {
            m = -12;
        }
        else if (m > 12) {
            m = 12;
        }

        if (d < 1) {
            d = 1;
        }
        else if (d > 30) {
            d = 30;
        }

        int dateInt = y * 10000 + Math.abs(m) * 100 + d;
        if (dateInt < 19001111) {
            // 太小
            set(1901, Calendar.JANUARY, 1);
            super.complete();
        } else if (dateInt > 21001201) {
            // 太大
            set(2100, Calendar.DECEMBER, 31);
            super.complete();
        } else {
            if (Math.abs(m) > 12) {
                m = 12;
            }

            int days = LunarCalendar.daysInLunarMonth(y, m);
            if (days == 0) {
                m = -m;
                days = LunarCalendar.daysInLunarMonth(y, m);
            }

            if (d > days) {
                d = days;
            }

            set(y, Math.abs(m) - 1, d);
            computeLunarFields();

            int amount = 0;
            while (lunarYear != y || lunarMonth != m) {
                amount += daysInLunarMonth(lunarYear, lunarMonth);
                lunarMonth = nextLunarMonth(lunarYear, lunarMonth);
            }

            amount += d - lunarDate;
            super.add(Calendar.DATE, amount);
        }

        computeLunarFields();
    }

    /**
     * 使用公历日期计算出农历日期
     */
    private void computeLunarFields() {
        int gregorianYear = internalGet(Calendar.YEAR);
        int gregorianMonth = internalGet(Calendar.MONTH) + 1;
        int gregorianDate = internalGet(Calendar.DATE);
        if (gregorianYear < 1901 || gregorianYear > 2100) {
            return;
        }

        int startYear = baseYear;
        int startMonth = baseMonth;
        int startDate = baseDate;

        lunarYear = baseLunarYear;
        lunarMonth = baseLunarMonth;
        lunarDate = baseLunarDate;

        // 第二个对应日，用以提高计算效率
        // 公历 2000 年 1 月 1 日，对应农历 4697 年 11 月 25 日
        if (gregorianYear >= 2000) {
            startYear = baseYear + 99;
            startMonth = 1;
            startDate = 1;

            lunarYear = baseLunarYear + 99;
            lunarMonth = 11;
            lunarDate = 25;
        }

        int daysDiff = 0;
        for (int i = startYear; i < gregorianYear; i++) {
            daysDiff += 365;
            if (DateUtil.isLeapYear(i)) {
                daysDiff += 1; // leap year
            }
        }

        for (int i = startMonth; i < gregorianMonth; i++) {
            daysDiff += DateUtil.getMonthDays(gregorianYear, i - 1);
        }

        daysDiff += gregorianDate - startDate;
        lunarDate += daysDiff;

        int lastDate = daysInLunarMonth(lunarYear, lunarMonth);
        int nextMonth = nextLunarMonth(lunarYear, lunarMonth);
        while (lunarDate > lastDate) {
            if (Math.abs(nextMonth) < Math.abs(lunarMonth)) {
                lunarYear++;
            }

            lunarMonth = nextMonth;
            lunarDate -= lastDate;

            lastDate = daysInLunarMonth(lunarYear, lunarMonth);
            nextMonth = nextLunarMonth(lunarYear, lunarMonth);
        }
    }

    /**
     * 计算节气
     */
    private void computeSolarTerms() {
        int gregorianYear = internalGet(Calendar.YEAR);
        int gregorianMonth = internalGet(Calendar.MONTH);
        if (gregorianYear < 1901 || gregorianYear > 2100) {
            return;
        }

        sectionalTerm = SolarTerm.sectionalTerm(gregorianYear, gregorianMonth);
        principleTerm = SolarTerm.principleTerm(gregorianYear, gregorianMonth);
    }

    /**
     * 计算农历年月的天数
     * @param y 农历年
     * @param m 农历月
     * @return 天数
     */
    static int daysInLunarMonth(int y, int m) {
        // 注意：闰月 m < 0
        int index = y - baseLunarYear + baseIndex;
        int v, l;
        int d = 30;

        if (1 <= m && m <= 8) {
            v = lunarMonths[2 * index];
            l = m - 1;
            if (((v >> l) & 0x01) == 1) {
                d = 29;
            }
        } else if (9 <= m && m <= 12) {
            v = lunarMonths[2 * index + 1];
            l = m - 9;
            if (((v >> l) & 0x01) == 1) {
                d = 29;
            }
        } else {
            v = lunarMonths[2 * index + 1];
            v = (v >> 4) & 0x0F;
            if (v != Math.abs(m)) {
                d = 0;
            } else {
                d = 29;
                for (int tmpIndex : bigLeapMonthYears) {
                    if (tmpIndex == index) {
                        d = 30;
                        break;
                    }
                }
            }
        }

        return d;
    }

    /**
     * 计算农历的下个月
     * @param y 农历年
     * @param m 农历月
     * @return 下个月是农历几月
     */
    private static int nextLunarMonth(int y, int m) {
        int n = Math.abs(m) + 1;
        if (m > 0) {
            int index = y - baseLunarYear + baseIndex;
            int v = lunarMonths[2 * index + 1];
            v = (v >> 4) & 0x0F;
            if (v == m) {
                n = -m;
            }
        }

        if (n == 13) {
            n = 1;
        }

        return n;
    }

    /**
     * 根据星期的位组合返回星期字符串集合
     * @param week 星期
     * @return 星期字符串集合
     */
    public static String getWeeksStr(int week){
        StringBuilder tmpSB = new StringBuilder();
        for (int i = 0; i < 7; i++){
            if ((week & (1 << i)) != 0){
                tmpSB.append(lunarWeekNames[i + 1]).append(",");
            }
        }
        if (tmpSB.length() <= 0){
            return null;
        }
        tmpSB.delete(tmpSB.length() - 1, tmpSB.length());

        return tmpSB.toString();
    }

    /**
     * 获取农历月份描述
     * @param month 农历月份
     * @return 月份描述
     */
    public static String getLunarMonth(int month){
        if (month > 0) {
            return lunarMonthNames[month];
        }
        else {
            return "闰" + lunarMonthNames[-month];
        }
    }

    /**
     * 获取农历日描述
     * @param day 农历日
     * @return 农历日描述
     */
    public static String getLunarDay(int day){
        return lunarDateNames[day];
    }

	// 日历第一天的日期
    private static final int baseYear = 1901;
    private static final int baseMonth = 1;
    private static final int baseDate = 1;
    private static final int baseIndex = 0;
    // 农历的第一天日期
    private static final int baseLunarYear = 1900;
    private static final int baseLunarMonth = 11;
    private static final int baseLunarDate = 11;

	// 中文字符串
    private static final String[] lunarWeekNames = { "", "周日", "周一", "周二",
                                                    "周三", "周四", "周五", "周六" };

    // 农历月份表述集合
    public static final String[] lunarMonthNames = { "", "正", "二", "三", "四",
                                                    "五", "六", "七", "八", "九", "十", "冬", "腊" };

    // 农历日期集合
    public static final String[] lunarDateNames = { "", "初一", "初二", "初三",
            "初四", "初五", "初六", "初七", "初八", "初九", "初十", "十一", "十二", "十三", "十四",
            "十五", "十六", "十七", "十八", "十九", "二十", "廿一", "廿二", "廿三", "廿四", "廿五",
            "廿六", "廿七", "廿八", "廿九", "三十" };

    private static final String[] stemNames = { "", "甲", "乙", "丙", "丁", "戊",
            "己", "庚", "辛", "壬", "癸" };

    private static final String[] branchNames = { "", "子", "丑", "寅", "卯", "辰",
            "巳", "午", "未", "申", "酉", "戌", "亥" };

    private static final String[] animalNames = { "", "鼠", "牛", "虎", "兔", "龙",
            "蛇", "马", "羊", "猴", "鸡", "狗", "猪" };

    // 接下来是数据表
    private static final int[] bigLeapMonthYears = { 6, 14, 19, 25, 33, 36, 38,
            41, 44, 52, 55, 79, 117, 136, 147, 150, 155, 158, 185, 193 };

    private static final char[] lunarMonths = { 0x00, 0x04, 0xad, 0x08, 0x5a,
            0x01, 0xd5, 0x54, 0xb4, 0x09, 0x64, 0x05, 0x59, 0x45, 0x95, 0x0a,
            0xa6, 0x04, 0x55, 0x24, 0xad, 0x08, 0x5a, 0x62, 0xda, 0x04, 0xb4,
            0x05, 0xb4, 0x55, 0x52, 0x0d, 0x94, 0x0a, 0x4a, 0x2a, 0x56, 0x02,
            0x6d, 0x71, 0x6d, 0x01, 0xda, 0x02, 0xd2, 0x52, 0xa9, 0x05, 0x49,
            0x0d, 0x2a, 0x45, 0x2b, 0x09, 0x56, 0x01, 0xb5, 0x20, 0x6d, 0x01,
            0x59, 0x69, 0xd4, 0x0a, 0xa8, 0x05, 0xa9, 0x56, 0xa5, 0x04, 0x2b,
            0x09, 0x9e, 0x38, 0xb6, 0x08, 0xec, 0x74, 0x6c, 0x05, 0xd4, 0x0a,
            0xe4, 0x6a, 0x52, 0x05, 0x95, 0x0a, 0x5a, 0x42, 0x5b, 0x04, 0xb6,
            0x04, 0xb4, 0x22, 0x6a, 0x05, 0x52, 0x75, 0xc9, 0x0a, 0x52, 0x05,
            0x35, 0x55, 0x4d, 0x0a, 0x5a, 0x02, 0x5d, 0x31, 0xb5, 0x02, 0x6a,
            0x8a, 0x68, 0x05, 0xa9, 0x0a, 0x8a, 0x6a, 0x2a, 0x05, 0x2d, 0x09,
            0xaa, 0x48, 0x5a, 0x01, 0xb5, 0x09, 0xb0, 0x39, 0x64, 0x05, 0x25,
            0x75, 0x95, 0x0a, 0x96, 0x04, 0x4d, 0x54, 0xad, 0x04, 0xda, 0x04,
            0xd4, 0x44, 0xb4, 0x05, 0x54, 0x85, 0x52, 0x0d, 0x92, 0x0a, 0x56,
            0x6a, 0x56, 0x02, 0x6d, 0x02, 0x6a, 0x41, 0xda, 0x02, 0xb2, 0xa1,
            0xa9, 0x05, 0x49, 0x0d, 0x0a, 0x6d, 0x2a, 0x09, 0x56, 0x01, 0xad,
            0x50, 0x6d, 0x01, 0xd9, 0x02, 0xd1, 0x3a, 0xa8, 0x05, 0x29, 0x85,
            0xa5, 0x0c, 0x2a, 0x09, 0x96, 0x54, 0xb6, 0x08, 0x6c, 0x09, 0x64,
            0x45, 0xd4, 0x0a, 0xa4, 0x05, 0x51, 0x25, 0x95, 0x0a, 0x2a, 0x72,
            0x5b, 0x04, 0xb6, 0x04, 0xac, 0x52, 0x6a, 0x05, 0xd2, 0x0a, 0xa2,
            0x4a, 0x4a, 0x05, 0x55, 0x94, 0x2d, 0x0a, 0x5a, 0x02, 0x75, 0x61,
            0xb5, 0x02, 0x6a, 0x03, 0x61, 0x45, 0xa9, 0x0a, 0x4a, 0x05, 0x25,
            0x25, 0x2d, 0x09, 0x9a, 0x68, 0xda, 0x08, 0xb4, 0x09, 0xa8, 0x59,
            0x54, 0x03, 0xa5, 0x0a, 0x91, 0x3a, 0x96, 0x04, 0xad, 0xb0, 0xad,
            0x04, 0xda, 0x04, 0xf4, 0x62, 0xb4, 0x05, 0x54, 0x0b, 0x44, 0x5d,
            0x52, 0x0a, 0x95, 0x04, 0x55, 0x22, 0x6d, 0x02, 0x5a, 0x71, 0xda,
            0x02, 0xaa, 0x05, 0xb2, 0x55, 0x49, 0x0b, 0x4a, 0x0a, 0x2d, 0x39,
            0x36, 0x01, 0x6d, 0x80, 0x6d, 0x01, 0xd9, 0x02, 0xe9, 0x6a, 0xa8,
            0x05, 0x29, 0x0b, 0x9a, 0x4c, 0xaa, 0x08, 0xb6, 0x08, 0xb4, 0x38,
            0x6c, 0x09, 0x54, 0x75, 0xd4, 0x0a, 0xa4, 0x05, 0x45, 0x55, 0x95,
            0x0a, 0x9a, 0x04, 0x55, 0x44, 0xb5, 0x04, 0x6a, 0x82, 0x6a, 0x05,
            0xd2, 0x0a, 0x92, 0x6a, 0x4a, 0x05, 0x55, 0x0a, 0x2a, 0x4a, 0x5a,
            0x02, 0xb5, 0x02, 0xb2, 0x31, 0x69, 0x03, 0x31, 0x73, 0xa9, 0x0a,
            0x4a, 0x05, 0x2d, 0x55, 0x2d, 0x09, 0x5a, 0x01, 0xd5, 0x48, 0xb4,
            0x09, 0x68, 0x89, 0x54, 0x0b, 0xa4, 0x0a, 0xa5, 0x6a, 0x95, 0x04,
            0xad, 0x08, 0x6a, 0x44, 0xda, 0x04, 0x74, 0x05, 0xb0, 0x25, 0x54,
            0x03 };
}
app/src/main/java/com/jjforever/wgj/maincalendar/weather/util/WeatherIconUtil.java
public final class WeatherIconUtil {
    // 天气图标集合，与天气代码一一对应
    private static final int[] mWeatherIcons = new int[]{
            R.drawable.ic_sunny_big, R.drawable.ic_cloudy_big,
            R.drawable.ic_overcast_big, R.drawable.ic_fog_big,
            R.drawable.hurricane_day_night, R.drawable.ic_heavyrain_big,
            R.drawable.ic_heavyrain_big, R.drawable.ic_thundeshower_big,
            R.drawable.ic_shower_big, R.drawable.ic_heavyrain_big,
            R.drawable.ic_moderraterain_big, R.drawable.ic_lightrain_big,
            R.drawable.ic_sleet_big, R.drawable.ic_snow_big,
            R.drawable.ic_snow_big, R.drawable.ic_heavysnow_big,
            R.drawable.ic_snow_big, R.drawable.ic_snow_big,
            R.drawable.ic_sandstorm_big, R.drawable.ic_sandstorm_big,
            R.drawable.ic_sandstorm_big, R.drawable.ic_sandstorm_big,
            R.drawable.freezing_rain_day_night, R.drawable.ic_dust_big,
            R.drawable.ic_haze_big
    };

    // 天气描述集合
    private static String[] mWeatherNames;

    /**
     * 初始化天气描述
     * @param names 天气描述集合
     */
    public static void initWeatherNames(String[] names)
    {
        mWeatherNames = names;
    }

    /**
     * 返回所有的天气描述
     * @return 所有的天气描述
     */
    public static String[] getWeatherNames(){
        return mWeatherNames;
    }

    /**
     * 根据天气代码获取天气图标
     * @param type 天气情况代码
     * @return 天气图标
     */
    public static int getWeatherIcon(int type) {
        if (type >= WeatherConstants.START_CODE && type <= WeatherConstants.END_CODE){
            return mWeatherIcons[type];
        }
        return R.drawable.ic_default_big;
    }

    /**
     * 根据天气代码获取天气描述
     * @param type 天气代码
     * @return 天气描述
     */
    public static String getWeatherName(int type)
    {
        if (type >= WeatherConstants.START_CODE && type <= WeatherConstants.END_CODE){
            return mWeatherNames[type];
        }

        // 最后一个存放无效天气描述
        return mWeatherNames[mWeatherNames.length - 1];
    }
}
app/src/main/java/com/jjforever/wgj/maincalendar/monthui/SwitchButton.java
public class SwitchButton extends CheckBox {
    private Paint mPaint;

    private Bitmap mBottom;

    private Bitmap mCurBtnPic;

    private Bitmap mBtnPressed;

    private Bitmap mBtnNormal;

    private Bitmap mFrame;

    private Bitmap mMask;

    private RectF mSaveLayerRectF;

    private PorterDuffXfermode mXfermode;

    private float mFirstDownY; // 首次按下的Y

    private float mFirstDownX; // 首次按下的X

    private float mRealPos; // 图片的绘制位置

    private float mBtnPos; // 按钮的位置

    private float mBtnOnPos; // 开关打开的位置

    private float mBtnOffPos; // 开关关闭的位置

    private float mMaskWidth;

    private float mMaskHeight;

    private float mBtnWidth;

    private float mBtnInitPos;

    private int mClickTimeout;

    private int mTouchSlop;

    private final int MAX_ALPHA = 255;

    private int mAlpha = MAX_ALPHA;

    private boolean mChecked = false;

    private boolean mBroadcasting;

    private boolean mTurningOn;

    private PerformClick mPerformClick;

    private OnCheckedChangeListener mOnCheckedChangeListener;

//    private OnCheckedChangeListener mOnCheckedChangeWidgetListener;

    private boolean mAnimating;

    private final static float VELOCITY = 350;

    private float mVelocity;

    private final static float EXTENDED_OFFSET_Y = 15;

    private float mExtendOffsetY; // Y轴方向扩大的区域,增大点击区域

    private float mAnimationPosition;

    private float mAnimatedVelocity;

    public SwitchButton(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.checkboxStyle);
    }

    public SwitchButton(Context context) {
        this(context, null);
    }

    public SwitchButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    private void initView(Context context) {
        mPaint = new Paint();
        mPaint.setColor(Color.WHITE);
        Resources resources = context.getResources();

        // get viewConfiguration
        mClickTimeout = ViewConfiguration.getPressedStateDuration()
                + ViewConfiguration.getTapTimeout();
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

        // get Bitmap
        mBottom = BitmapFactory.decodeResource(resources, R.drawable.bottom);
        mBtnPressed = BitmapFactory.decodeResource(resources, R.drawable.btn_pressed);
        mBtnNormal = BitmapFactory.decodeResource(resources, R.drawable.btn_unpressed);
        mFrame = BitmapFactory.decodeResource(resources, R.drawable.frame);
        mMask = BitmapFactory.decodeResource(resources, R.drawable.mask);
        mCurBtnPic = mBtnNormal;

        mBtnWidth = mBtnPressed.getWidth();
        mMaskWidth = mMask.getWidth();
        mMaskHeight = mMask.getHeight();

        mBtnOffPos = mBtnWidth / 2;
        mBtnOnPos = mMaskWidth - mBtnWidth / 2;

        mBtnPos = mChecked ? mBtnOnPos : mBtnOffPos;
        mRealPos = getRealPos(mBtnPos);

        final float density = getResources().getDisplayMetrics().density;
        mVelocity = (int) (VELOCITY * density + 0.5f);
        mExtendOffsetY = (int) (EXTENDED_OFFSET_Y * density + 0.5f);

        mSaveLayerRectF = new RectF(0, mExtendOffsetY, mMask.getWidth(), mMask.getHeight()
                + mExtendOffsetY);
        mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
    }

    @Override
    public void setEnabled(boolean enabled) {
        mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA / 2;
        super.setEnabled(enabled);
    }

    public boolean isChecked() {
        return mChecked;
    }

    public void toggle() {
        setChecked(!mChecked);
    }

    /**
     * 内部调用此方法设置checked状态，此方法会延迟执行各种回调函数，保证动画的流畅度
     *
     * @param checked 选中状态
     */
    private void setCheckedDelayed(final boolean checked) {
        this.postDelayed(new Runnable() {

            @Override
            public void run() {
                setChecked(checked);
            }
        }, 10);
    }

    /**
     * <p>
     * Changes the checked State of this button.
     * </p>
     *
     * @param checked true to check the button, false to uncheck it
     */
    public void setChecked(boolean checked) {

        if (mChecked != checked) {
            mChecked = checked;

            mBtnPos = checked ? mBtnOnPos : mBtnOffPos;
            mRealPos = getRealPos(mBtnPos);
            invalidate();

            // Avoid infinite recursions if setChecked() is called from a
            // listener
            if (mBroadcasting) {
                return;
            }

            mBroadcasting = true;
            if (mOnCheckedChangeListener != null) {
                mOnCheckedChangeListener.onCheckedChanged(SwitchButton.this, mChecked);
            }
//            if (mOnCheckedChangeWidgetListener != null) {
//                mOnCheckedChangeWidgetListener.onCheckedChanged(SwitchButton.this, mChecked);
//            }

            mBroadcasting = false;
        }
    }

    /**
     * Register a callback to be invoked when the checked State of this button
     * changes.
     *
     * @param listener the callback to call on checked State change
     */
    public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
        mOnCheckedChangeListener = listener;
    }

    /**
     * Register a callback to be invoked when the checked State of this button
     * changes. This callback is used for internal purpose only.
     *
     * @param listener the callback to call on checked State change
     * @hide
     */
//    void setOnCheckedChangeWidgetListener(OnCheckedChangeListener listener) {
//        mOnCheckedChangeWidgetListener = listener;
//    }

    /**
     * 触摸触发事件
     * @param event 触摸事件
     * @return 是否已处理
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        float x = event.getX();
        float y = event.getY();
        float deltaX = Math.abs(x - mFirstDownX);
        float deltaY = Math.abs(y - mFirstDownY);
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                attemptClaimDrag();
                mFirstDownX = x;
                mFirstDownY = y;
                mCurBtnPic = mBtnPressed;
                mBtnInitPos = mChecked ? mBtnOnPos : mBtnOffPos;
                break;
            case MotionEvent.ACTION_MOVE:
                mBtnPos = mBtnInitPos + event.getX() - mFirstDownX;
                if (mBtnPos >= mBtnOffPos) {
                    mBtnPos = mBtnOffPos;
                }
                if (mBtnPos <= mBtnOnPos) {
                    mBtnPos = mBtnOnPos;
                }
                mTurningOn = mBtnPos > (mBtnOffPos - mBtnOnPos) / 2 + mBtnOnPos;

                mRealPos = getRealPos(mBtnPos);
                break;
            case MotionEvent.ACTION_UP:
                mCurBtnPic = mBtnNormal;
                float time = event.getEventTime() - event.getDownTime();
                if (deltaY < mTouchSlop && deltaX < mTouchSlop && time < mClickTimeout) {
                    if (mPerformClick == null) {
                        mPerformClick = new PerformClick();
                    }
                    if (!post(mPerformClick)) {
                        performClick();
                    }
                } else {
                    startAnimation(!mTurningOn);
                }
                break;
        }

        invalidate();
        return isEnabled();
    }

    private final class PerformClick implements Runnable {
        public void run() {
            performClick();
        }
    }

    @Override
    public boolean performClick() {
        startAnimation(!mChecked);
        return true;
    }

    /**
     * Tries to claim the user's drag motion, and requests disallowing any
     * ancestors from stealing events in the drag.
     */
    private void attemptClaimDrag() {
        ViewParent parent = getParent();
        if (parent != null) {
            parent.requestDisallowInterceptTouchEvent(true);
        }
    }

    /**
     * 将btnPos转换成RealPos
     *
     * @param btnPos 按钮位置
     * @return 真实位置
     */
    private float getRealPos(float btnPos) {
        return btnPos - mBtnWidth / 2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.saveLayerAlpha(mSaveLayerRectF, mAlpha, Canvas.MATRIX_SAVE_FLAG
                | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
                | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
        // 绘制蒙板
        canvas.drawBitmap(mMask, 0, mExtendOffsetY, mPaint);
        mPaint.setXfermode(mXfermode);

        // 绘制底部图片
        canvas.drawBitmap(mBottom, mRealPos, mExtendOffsetY, mPaint);
        mPaint.setXfermode(null);
        // 绘制边框
        canvas.drawBitmap(mFrame, 0, mExtendOffsetY, mPaint);

        // 绘制按钮
        canvas.drawBitmap(mCurBtnPic, mRealPos, mExtendOffsetY, mPaint);
        canvas.restore();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension((int) mMaskWidth, (int) (mMaskHeight + 2 * mExtendOffsetY));
    }

    private void startAnimation(boolean turnOn) {
        mAnimating = true;
        mAnimatedVelocity = turnOn ? -mVelocity : mVelocity;
        mAnimationPosition = mBtnPos;

        new SwitchAnimation().run();
    }

    private void stopAnimation() {
        mAnimating = false;
    }

    private final class SwitchAnimation implements Runnable {

        @Override
        public void run() {
            if (!mAnimating) {
                return;
            }
            doAnimation();
            FrameAnimationController.requestAnimationFrame(this);
        }
    }

    private void doAnimation() {
        mAnimationPosition += mAnimatedVelocity * FrameAnimationController.ANIMATION_FRAME_DURATION
                / 1000;
        if (mAnimationPosition <= mBtnOnPos) {
            stopAnimation();
            mAnimationPosition = mBtnOnPos;
            setCheckedDelayed(true);
        } else if (mAnimationPosition >= mBtnOffPos) {
            stopAnimation();
            mAnimationPosition = mBtnOffPos;
            setCheckedDelayed(false);
        }
        moveView(mAnimationPosition);
    }

    private void moveView(float position) {
        mBtnPos = position;
        mRealPos = getRealPos(mBtnPos);
        invalidate();
    }
}
app/src/main/java/com/jjforever/wgj/maincalendar/dialogpicker/picker/DialogPicker.java
public class DialogPicker extends ConfirmPopup<LinearLayout> {
    private TextView mTextView;
    // 标题
    private String mTitle;
    // 内容
    private String mContent;

    // 监听事件
    private OnDialogPickListener onDialogPickListener;

    /**
     * 创建一个对话框
     * @param activity 活动
     * @param title 标题
     * @param content 内容
     */
    public DialogPicker(Activity activity, String title, String content)
    {
        super(activity);
        mTitle = title;
        mContent = content;
    }

    /**
     * 创建一个对话框，标题为提醒字样
     * @param activity 活动
     * @param content 内容
     */
    public DialogPicker(Activity activity, String content)
    {
        this(activity, activity.getResources().getString(R.string.dialog_title), content);
    }

    /**
     * 设置监听事件
     * @param onDialogPickListener 回调方法
     */
    public void setOnDialogPickListener(OnDialogPickListener onDialogPickListener) {
        this.onDialogPickListener = onDialogPickListener;
    }

    @Override
    protected void onSubmit() {
        if (onDialogPickListener != null) {
            onDialogPickListener.onDialogPicked(true);
        }
    }

    @Override
    protected void onCancel()
    {
        if (onDialogPickListener != null) {
            onDialogPickListener.onDialogPicked(false);
        }
    }

    @Override
    @NonNull
    protected LinearLayout makeCenterView() {
        LinearLayout rootLayout = new LinearLayout(activity);
        rootLayout.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        rootLayout.setOrientation(LinearLayout.VERTICAL);

        mTextView = new TextView(activity);
        mTextView.setHeight(screenHeightPixels/4);
        mTextView.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        mTextView.setGravity(Gravity.CENTER);
        mTextView.setTextSize(16);
        mTextView.setPadding(10, 10, 10, 10);
        mTextView.setText(mContent);
        rootLayout.addView(mTextView);

        setTitleText(mTitle);
        return rootLayout;
    }

    /**
     * 对话框确认取消接口
     */
    public interface OnDialogPickListener {
        /**
         * 对话框确认事件
         * @param confirm 是否确认
         */
        void onDialogPicked(boolean confirm);

    }
}
app/src/main/java/com/jjforever/wgj/maincalendar/util/Helper.java
public final class Helper {

    /**
     * 判断字符串是否为空
     * @param str 要判断的字符串
     * @return 是否为空
     */
    public static boolean isNullOrEmpty(String str)
    {
        return  (str == null || str.length() <= 0);
    }

    /**
     * 返回当前程序版本名
     */
    public static String getAppVersionName(Context context) {
        String versionName = "";

        try {
            PackageManager pm = context.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
            versionName = pi.versionName;
            if (isNullOrEmpty(versionName)) {
                return "";
            }
        } catch (Exception e) {
            AppConstants.ELog(e.toString());
        }
        return versionName;
    }

    /**
     * 根据全路径获取文件名
     * @param path 路径
     * @return 文件名
     */
    public static String getFileName(String path){
        int start = path.lastIndexOf("/");
        int end = path.lastIndexOf(".");
        if (start != -1 && end != -1){
            return path.substring(start + 1, end);
        }else{
            return null;
        }
    }

    /**
     * 根据全路径获取路径名
     * @param path 路径
     * @return 路径
     */
    public static String getFilePath(String path){
        int end = path.lastIndexOf("/");
        if (end != -1){
            return path.substring(0, end);
        }
        else{
            return null;
        }
    }

    /**
     * 获取状态栏高度
     * @return 状态栏高度
     */
    public static int getStatusHeight(Context context){
        //获取status_bar_height资源的ID
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            //根据资源ID获取响应的尺寸值
            return context.getResources().getDimensionPixelSize(resourceId) - 5;
        }

        AppConstants.WLog("Do not find status height...");
        return 35;
    }

    /**
     * 获取日志文件路径
     * @return 文件句柄
     */
    private static File getLogFile(){
        File file = null;

        String logPath = Environment.getExternalStorageDirectory().getPath() + "/MainLog.txt";
        try {
            file = new File(logPath);
            if (!file.exists()) {
                if (!file.createNewFile()){
                    AppConstants.XLog("create New file fail...");
                    return null;
                }
            }
        } catch (Exception e) {
            AppConstants.XLog("get log file fail: " + e.toString());
        }

        return file;
    }

    /**
     * 将日志记录到文件中
     * @param content 记录内容
     */
    public static void RecordLog(char level, String content){
        if (level == 'X'){
            return;
        }
        if (!AppConstants.DEBUG && !GlobalSettingMng.getSetting().getIsRecordLog()){
            return;
        }

        File tmpFile = getLogFile();
        if (tmpFile == null){
            return;
        }

        try {
            RandomAccessFile raf = new RandomAccessFile(tmpFile, "rwd");
            raf.seek(tmpFile.length());
            DateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm:ss", Locale.getDefault());
            String tmpStr = String.format("%s %c %s\r\n",
                                dateFormat.format(new java.util.Date()), level,
                                content);
            raf.write(tmpStr.getBytes());
            raf.close();
        }
        catch (Exception ex){
            AppConstants.XLog("Record log ex: " + ex.toString());
        }
    }

    /**
     * 是否为KitKat以后的系统
     * @return true of false
     */
    public static boolean isKitKatOrLater() {
        return Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2;
    }

    /**
     * 查看指定服务是否正在运行
     * @param context 内容提供器
     * @param serviceName 服务全名
     * @return 是否在运行
     */
//    public static boolean isServiceRunning(Context context,String serviceName){
//        // 校验服务是否还存在
//        ActivityManager am = (ActivityManager) context
//                .getSystemService(Context.ACTIVITY_SERVICE);
//        List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(100);
//        for (ActivityManager.RunningServiceInfo info : services) {
//            // 得到所有正在运行的服务的名称
//            String name = info.service.getClassName();
//            if (serviceName.equals(name)) {
//                return true;
//            }
//        }
//        return false;
//    }
}
app/src/main/java/com/jjforever/wgj/maincalendar/BLL/DailyRecordMng.java
public final class DailyRecordMng {
    // 管理的表名
    final static String TABLE_NAME = "DailyRecord";

    private DailyRecordMng(){}

    private static ContentValues getValues(DailyRecord record, boolean isNew){
        // 实例化常量值
        ContentValues cValue = new ContentValues();
        // 记录时间
        cValue.put("record_time", record.getRecordTime().getTimeInMillis());
        // 天气代码
        cValue.put("weather", record.getWeather());
        // 标题
        cValue.put("title", record.getTitle());
        // 内容
        cValue.put("content", record.getContent());
        // 是否显示
        cValue.put("display", record.getDisplay() ? 1 : 0);
        if (isNew) {
            // 本条记录创建时间
            cValue.put("create_time", record.getCreateTime().getTimeInMillis());
        }

        return cValue;
    }

    /**
     * 往数据库中添加一条日常记录
     * @param record 日常记录
     * @return 是否成功
     */
    public static boolean insert(DailyRecord record){
        AppConstants.DLog("DBManager --> add");
        try
        {
            // 实例化常量值
            ContentValues cValue = getValues(record, true);

            //调用insert()方法插入数据
            return DatabaseHelper.SQLiteDb.insert(TABLE_NAME, null, cValue) > 0;
        }
        catch (Exception ex){
            AppConstants.WLog(ex.toString());
            return false;
        }
    }

    /**
     * 更新记录
     * @param record 要更新的记录
     * @return 是否更新成功
     */
    public static boolean update(DailyRecord record){
        try{
            ContentValues cValue = getValues(record, false);
            return DatabaseHelper.SQLiteDb.update(TABLE_NAME, cValue, "[index]=?",
                    new String[] { String.valueOf(record.getIndex()) }) > 0;
        }
        catch (Exception ex){
            AppConstants.WLog(ex.toString());
            return false;
        }
    }

    /**
     * 根据索引删除一条日常记录
     * @param index 记录索引
     * @return 是否成功
     */
    public static boolean delete(long index){
        try{
            return DatabaseHelper.SQLiteDb.delete(TABLE_NAME, "[index]=?",
                    new String[] { String.valueOf(index) }) >= 0;
        }
        catch (Exception ex){
            AppConstants.WLog(ex.toString());
            return false;
        }
    }

    /**
     * 根据索引集合批量删除记录
     * @param indexs 索引集合
     * @return 删除成功与否
     */
    public static boolean delete(ArrayList<Long> indexs){
        // 采用事务处理，确保数据完整性
        DatabaseHelper.SQLiteDb.beginTransaction();
        try
        {
            for (long index : indexs)
            {
                DatabaseHelper.SQLiteDb.delete(TABLE_NAME, "[index]=?",
                        new String[] { String.valueOf(index) });
            }
            // 设置事务成功完成
            DatabaseHelper.SQLiteDb.setTransactionSuccessful();
            return true;
        }
        catch (Exception ex){
            AppConstants.WLog(ex.toString());
            return false;
        }
        finally
        {
            DatabaseHelper.SQLiteDb.endTransaction(); // 结束事务
        }
    }

    /**
     * 检查数据库是否存在此标题的记录
     * @param title 要检查的标题
     * @param index 不为0则排除该索引
     * @return 是否存在
     */
    public static boolean isExist(String title, long index){
        String sqlStr = "select count(*) from " + TABLE_NAME;
        sqlStr += String.format(" where title='%s'", title);
        if (index > 0){
            sqlStr += String.format(Locale.getDefault(),
                    " and [index]<>'%d'", index);
        }
        Cursor cursor = DatabaseHelper.SQLiteDb.rawQuery(sqlStr, null);
        if (cursor == null){
            return false;
        }
        try {
            return (cursor.moveToNext() && cursor.getLong(0) > 0);
        }
        catch (Exception ex){
            AppConstants.WLog(ex.toString());
            return false;
        }
        finally {
            cursor.close();
        }
    }

    /**
     * 根据条件查询所有的日常记录
     * @param where where条件
     * @param args where条件的参数
     * @param orderBy 排序语句
     * @param limit 限制语句
     * @return 日常记录集合
     */
    private static ArrayList<DailyRecord> select(String where, String[] args, String orderBy, String limit){
        ArrayList<DailyRecord> tmpLst = new ArrayList<>();

        Cursor cursor = DatabaseHelper.SQLiteDb.query(TABLE_NAME, null, where, args, null, null, orderBy, limit);
        if (cursor == null){
            return tmpLst;
        }

        // 遍历读取数据
        try {
            while (cursor.moveToNext()) {
                DailyRecord tmpRecord = new DailyRecord(false);
                tmpRecord.setIndex(cursor.getLong(cursor.getColumnIndex("index")));
                long tmpMill = cursor.getLong(cursor.getColumnIndex("record_time"));
                LunarCalendar recordTime = new LunarCalendar();
                recordTime.setTimeInMillis(tmpMill);
                recordTime.updateLunar();
                tmpRecord.setRecordTime(recordTime);
                tmpRecord.setWeather(cursor.getInt(cursor.getColumnIndex("weather")));
                tmpRecord.setTitle(cursor.getString(cursor.getColumnIndex("title")));
                tmpRecord.setContent(cursor.getString(cursor.getColumnIndex("content")));
                tmpRecord.setDisplay(cursor.getInt(cursor.getColumnIndex("display")) == 1);
                tmpMill = cursor.getLong(cursor.getColumnIndex("create_time"));
                LunarCalendar createTime = new LunarCalendar();
                createTime.setTimeInMillis(tmpMill);
                createTime.updateLunar();
                tmpRecord.setCreateTime(createTime);

                tmpLst.add(tmpRecord);
            }
        }
        catch (Exception ex){
            AppConstants.WLog(ex.toString());
        }
        finally {
            cursor.close();
        }

        return tmpLst;
    }

    /**
     * 根据索引降序排列取出所有日常记录
     * @return 查询到的日常记录
     */
    public static ArrayList<DailyRecord> selectAll(){
        return select(null, null, "[index] DESC", null);
    }

    /**
     * 根据索引获取指定日常记录
     * @param index 索引
     * @return 指定索引的日常记录
     */
    public static DailyRecord select(long index){
        ArrayList<DailyRecord> tmpLst = select("[index]=?", new String[]{String.valueOf(index)}, null, null);
        if (tmpLst == null || tmpLst.size() <= 0){
            return null;
        }

        return tmpLst.get(0);
    }

    /**
     * 获取指定年月的日常记录
     * @param year 指定年
     * @param month 指定月
     * @return 记录集合
     */
    public static ArrayList<ICalendarRecord> selectByMonth(int year, int month){
        LunarCalendar tmpDate = new LunarCalendar(year, month, 1);
        // 月初时间
        long startTime = tmpDate.getTimeInMillis();
        tmpDate.add(Calendar.MONTH, 1);
        tmpDate.add(Calendar.MILLISECOND, -1);
        // 月末时间
        long endTime = tmpDate.getTimeInMillis();

        return selectBySlot(startTime, endTime);
    }

    /**
     * 或者指定日期的日常记录
     * @param date 指定日期
     * @return 记录集合
     */
//    public static ArrayList<ICalendarRecord> selectByDate(LunarCalendar date){
//        // 指定日期的0点
//        LunarCalendar tmpDate = new LunarCalendar(date.get(Calendar.YEAR),
//                                                date.get(Calendar.MONTH),
//                                                date.get(Calendar.DAY_OF_MONTH));
//        long startTime = tmpDate.getTimeInMillis();
//        // 定位到指定日期的23点59分59秒
//        tmpDate.add(Calendar.DAY_OF_MONTH, 1);
//        tmpDate.add(Calendar.MILLISECOND, -1);
//        long endTime = tmpDate.getTimeInMillis();
//
//        return selectBySlot(startTime, endTime);
//    }

    /**
     * 查询指定时间段的记录数
     * @param startTime 开始的毫秒数
     * @param endTime 结束时间的毫秒数
     * @return 记录数
     */
    private static ArrayList<ICalendarRecord> selectBySlot(long startTime, long endTime){
        ArrayList<DailyRecord> tmpLst = select("record_time >= ? and record_time <= ? and display <> ?",
                new String[]{String.valueOf(startTime), String.valueOf(endTime), "0"},
                "[index] DESC", null);
        if (tmpLst == null || tmpLst.isEmpty()){
            return null;
        }

        ArrayList<ICalendarRecord> refLst = new ArrayList<>(tmpLst.size());
        refLst.addAll(tmpLst);
        return  refLst;
    }
}
app/src/main/java/com/jjforever/wgj/maincalendar/wheelpicker/picker/WeatherPicker.java
public class WeatherPicker extends WheelPicker {

    // 选择的天气索引
    private int mSelectedWeatherIndex = 0;
    private ArrayList<String> weathers = new ArrayList<>();
    // 天气选中触发事件
    private OnWeatherPickListener onWeatherPickListener;
    // 图片显示
    private TextView mImageView;

    /**
     * 控件初始化
     * @param activity 所在活动
     */
    public WeatherPicker(Activity activity){
        super(activity);

        for (int i = WeatherConstants.START_CODE; i <= WeatherConstants.END_CODE; i++){
            weathers.add(WeatherIconUtil.getWeatherName(i));
        }
    }

    /**
     * 设置触发事件
     * @param listener 监听事件
     */
    public void setOnWeatherPickListener(OnWeatherPickListener listener) {
        this.onWeatherPickListener = listener;
    }

    /**
     * 获取选中的天气代码
     * @return 天气代码
     */
    public int getSelectedWeather()
    {
        return mSelectedWeatherIndex;
    }

    /**
     * 设置默认显示天气
     * @param code 天气代码
     */
    public void setSelectedItem(int code)
    {
        mSelectedWeatherIndex = code;
    }

    // 获取图片
    Html.ImageGetter imageGetter = new Html.ImageGetter() {
        @Override
        public Drawable getDrawable(String source) {
            int id = Integer.parseInt(source);
            Drawable drawable = activity.getResources().getDrawable(id);
            if (drawable != null) {
                drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
                        drawable.getIntrinsicHeight());
            }
            return drawable;
        }
    };

    @Override
    @NonNull
    protected View makeCenterView() {
        LinearLayout layout = new LinearLayout(activity);
        layout.setOrientation(LinearLayout.HORIZONTAL);
        layout.setGravity(Gravity.CENTER);

        WheelView weatherView = new WheelView(activity);
        weatherView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
        weatherView.setTextSize(textSize);
        weatherView.setTextColor(textColorNormal, textColorFocus);
        weatherView.setLineVisible(lineVisible);
        weatherView.setLineColor(lineColor);
        layout.addView(weatherView);

        mImageView = new TextView(activity);
        mImageView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
        mImageView.setText(Html.fromHtml("<img src='" + WeatherIconUtil.getWeatherIcon(mSelectedWeatherIndex) + "'/>", imageGetter, null));
        layout.addView(mImageView);

        weatherView.setItems(weathers, mSelectedWeatherIndex);
        weatherView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
            @Override
            public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
                mSelectedWeatherIndex = selectedIndex;
                mImageView.setText(Html.fromHtml("<img src='" + WeatherIconUtil.getWeatherIcon(mSelectedWeatherIndex) + "'/>", imageGetter, null));
            }
        });

        return layout;
    }

    @Override
    public void onSubmit() {
        if (onWeatherPickListener != null) {
            onWeatherPickListener.onWeatherPicked(getSelectedWeather());
        }
    }

    public interface OnWeatherPickListener {
        /**
         * 天气选中触发事件
         * @param code 天气代码
         */
        void onWeatherPicked(int code);
    }
}
app/src/main/java/com/jjforever/wgj/maincalendar/Model/DailyRecord.java
public class DailyRecord implements ICalendarRecord, Parcelable {

    // 记录索引
    private long mIndex = 0;
    // 记录的日期
    private LunarCalendar mRecordTime;
    // 天气情况代码
    private int mWeather;
    // 记录标题
    private String mTitle = "";
    // 记录内容
    private String mContent = "";
    // 是否在日历中显示
    private boolean mDisplay = true;
    // 记录创建时间
    private Calendar mCreateTime;
    // 是否为新记录
    private boolean mIsNew;

    /**
     * 创建一条新的记录
     */
    public DailyRecord() {
        mIsNew = true;
    }

    /**
     * 创建一条记录
     * @param isNew 是否为新记录
     */
    public DailyRecord(boolean isNew){
        mIsNew = isNew;
    }

    /**
     * 获取日常记录类型
     * @return 日常记录类型 RecordType.DAILY_RECORD
     */
    public int getType(){
        return RecordType.DAILY_RECORD;
    }

    /**
     * 显示方式
     * @return RecordShowType类型
     */
    public int showType(){
        return mDisplay ? RecordShowType.TEXT_DOT : RecordShowType.HIDE;
    }

    public long getIndex(){
        return mIndex;
    }

    public void setIndex(long index){
        mIndex = index;
    }

    /**
     * 获取记录的日期
     * @return 记录的日期
     */
    public LunarCalendar getRecordTime(){
        return mRecordTime;
    }

    public void setRecordTime(LunarCalendar calendar){
        mRecordTime = calendar;
    }

    public int getWeather(){
        return mWeather;
    }

    public void setWeather(int weather){
        mWeather = weather;
    }

    public String getTitle(){
        return mTitle;
    }

    public void setTitle(String title){
        mTitle = title;
    }

    public String getContent(){
        return mContent;
    }

    public void setContent(String content){
        mContent = content;
    }

    public boolean getDisplay(){
        return  mDisplay;
    }

    public void setDisplay(boolean display){
        mDisplay = display;
    }

    public Calendar getCreateTime(){
        return mCreateTime;
    }

    public void setCreateTime(Calendar calendar){
        mCreateTime = calendar;
    }

    public boolean getIsNew(){
        return  mIsNew;
    }

    public void setIsNew(boolean isNew){
        mIsNew = isNew;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(this.mIndex);
        dest.writeSerializable(this.mRecordTime);
        dest.writeInt(this.mWeather);
        dest.writeString(this.mTitle);
        dest.writeString(this.mContent);
        dest.writeByte(this.mDisplay ? (byte) 1 : (byte) 0);
        dest.writeSerializable(this.mCreateTime);
        dest.writeByte(this.mIsNew ? (byte) 1 : (byte) 0);
    }

    protected DailyRecord(Parcel in) {
        this.mIndex = in.readLong();
        this.mRecordTime = (LunarCalendar) in.readSerializable();
        this.mWeather = in.readInt();
        this.mTitle = in.readString();
        this.mContent = in.readString();
        this.mDisplay = in.readByte() != 0;
        this.mCreateTime = (Calendar) in.readSerializable();
        this.mIsNew = in.readByte() != 0;
    }

    public static final Parcelable.Creator<DailyRecord> CREATOR = new Parcelable.Creator<DailyRecord>() {
        @Override
        public DailyRecord createFromParcel(Parcel source) {
            return new DailyRecord(source);
        }

        @Override
        public DailyRecord[] newArray(int size) {
            return new DailyRecord[size];
        }
    };
}
app/src/main/java/com/jjforever/wgj/maincalendar/toolbar/ToolBarActivity.java
public abstract class ToolBarActivity extends AppCompatActivity implements View.OnClickListener {
    // 工具栏
    public Toolbar mToolbar;
    // 标题控件
    private TextView mTitleView;
    // 确定按钮控件
    private ImageView mOkView;
    // 删除按钮
    private ImageView mDeleteView;
    // 标题字符串
    //private CharSequence mTitle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);

        ViewGroup contentFrameLayout = (ViewGroup) findViewById(Window.ID_ANDROID_CONTENT);
        if (contentFrameLayout != null) {
            View parentView = contentFrameLayout.getChildAt(0);
            if (parentView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                parentView.setFitsSystemWindows(true);
            }
        }
    }

    @Override
    public void setContentView(int layoutResID) {
        int statusHeight = Helper.getStatusHeight(this);
        ToolBarHelper mToolBarHelper = new ToolBarHelper(this,layoutResID);
        mToolbar = mToolBarHelper.getToolBar();
        mToolbar.getLayoutParams().height += statusHeight;
        mToolbar.setPadding(mToolbar.getPaddingLeft(), statusHeight, mToolbar.getPaddingRight(), mToolbar.getPaddingBottom());
        setToolbarBack(ThemeStyle.Primary);
        setContentView(mToolBarHelper.getContentView());
        /*把 mToolbar 设置到Activity 中*/
        setSupportActionBar(mToolbar);
        /*自定义的一些操作*/
        onCreateCustomToolBar(mToolbar);
        mTitleView = (TextView) this.findViewById(R.id.toolbar_title);
        mOkView = (ImageView) this.findViewById(R.id.toolbar_ok_btn);
        if (mOkView != null){
            mOkView.getLayoutParams().height = mOkView.getLayoutParams().width / 3;
            mOkView.setOnClickListener(this);
        }
        mDeleteView = (ImageView) this.findViewById(R.id.toolbar_delete_btn);
        if (mDeleteView != null){
            mDeleteView.getLayoutParams().height = mDeleteView.getLayoutParams().width / 3;
            mDeleteView.setOnClickListener(this);
        }
    }

    public void onCreateCustomToolBar(Toolbar toolbar){
        toolbar.setContentInsetsRelative(0,0);
        getLayoutInflater().inflate(R.layout.toolbar_button, toolbar);
    }

    /**
     * 设置标题
     * @param title 标题字符串
     */
    public void setTitle(CharSequence title)
    {
        //this.mTitle = title;
        if (mTitleView != null) {
            mTitleView.setText(title);
        }
    }

    /**
     * 设置工具栏背景色
     * @param color 背景色
     */
    public void setToolbarBack(int color){
        mToolbar.setBackgroundColor(color);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home){
            finish();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * 显示或者隐藏确定按钮
     * @param show 是否显示
     */
    protected void showOkBtn(boolean show){
        if (mOkView != null){
            mOkView.setVisibility(show ? View.VISIBLE : View.GONE);
        }
    }

    /**
     * 显示或隐藏删除按钮
     * @param show 是否显示
     */
    protected void showDeleteBtn(boolean show){
        if (mDeleteView != null){
            mDeleteView.setVisibility(show ? View.VISIBLE : View.GONE);
        }
    }

    /**
     * 设置OK按钮图标
     * @param resId 要设置的按钮图标资源
     */
    protected void setOkBtnImage(int resId){
        if (mOkView != null){
            mOkView.setImageResource(resId);
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.toolbar_ok_btn:
                // 确定按钮
                onOKButtonClick();
                break;

            case R.id.toolbar_delete_btn:
                // 删除按钮
                onDeleteButtonClick();
                break;

            default:
                break;
        }
    }

    /**
     * 按下确定按钮触发事件，需在子类中重写
     */
    public void onOKButtonClick(){

    }

    /**
     * 按下删除按钮触发事件，需在子类中重写
     */
    public void onDeleteButtonClick(){

    }

    @Override
    public void finish()
    {
        super.finish();
        overridePendingTransition(R.anim.slide_in_left,R.anim.slide_out_right);
    }
}


Question: package com.jjforever.wgj.maincalendar;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.jjforever.wgj.maincalendar.BLL.DailyRecordMng;
import com.jjforever.wgj.maincalendar.Model.DailyRecord;
import com.jjforever.wgj.maincalendar.dialogpicker.picker.DialogPicker;
import com.jjforever.wgj.maincalendar.monthui.SwitchButton;
import com.jjforever.wgj.maincalendar.toolbar.ToolBarActivity;
import com.jjforever.wgj.maincalendar.util.Helper;
import com.jjforever.wgj.maincalendar.util.LunarCalendar;
import com.jjforever.wgj.maincalendar.weather.util.WeatherIconUtil;
import com.jjforever.wgj.maincalendar.wheelpicker.picker.DatePicker;
import com.jjforever.wgj.maincalendar.wheelpicker.picker.WeatherPicker;
import java.util.Calendar;




public class AddDailyActivity extends ToolBarActivity {

    // 记录的时间文本控件
    private TextView mTimeText;
    // 天气情况文本控件
    private ImageView mWeatherView;
    // 是否在日历中显示按钮
    private SwitchButton mSwitchButton;
    // 记录是否更改，以便退出时进行提示
    private boolean mIsChanged = false;
    // 标题栏控件
    private EditText mTitleEdit;
    // 内容编辑控件
    private EditText mContentEdit;
    // 是否确定退出
    private boolean mSureQuit = false;
    // 编辑的记录
    private DailyRecord mRecord;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_daily);

        mRecord = getIntent().getParcelableExtra(AppConstants.MAIN_ACTIVITY_CLICK_DATE);
        if (mRecord == null){
            // 获取错误
            mSureQuit = true;
            finish();
            return;
        }

        setTitle(getResources().getString(R.string.add_daily));
        mTimeText = (TextView) this.findViewById(R.id.record_time);
        mTimeText.setText(mRecord.getRecordTime().toRecordTime());
        mTimeText.setOnClickListener(this);
        mWeatherView = (ImageView) this.findViewById(R.id.record_weather);
        if (mWeatherView != null) {
            mWeatherView.setImageResource(WeatherIconUtil.getWeatherIcon(mRecord.getWeather()));
            mWeatherView.setOnClickListener(this);
        }

        mSwitchButton = (SwitchButton) this.findViewById(R.id.switch_notice);
        mSwitchButton.setChecked(mRecord.getDisplay());
        RelativeLayout displayLayout = (RelativeLayout) this.findViewById(R.id.display_layout);
        if (displayLayout != null){
            displayLayout.setOnClickListener(this);
        }

        mTitleEdit = (EditText) this.findViewById(R.id.text_record_title);
        if (mTitleEdit != null && !Helper.isNullOrEmpty(mRecord.getTitle())) {
            mTitleEdit.setText(mRecord.getTitle());
        }
        mContentEdit = (EditText) this.findViewById(R.id.text_record_content);
        if (mContentEdit != null && !Helper.isNullOrEmpty(mRecord.getContent())){
            mContentEdit.setText(mRecord.getContent());
        }
        if (!mRecord.getIsNew()) {
            // 编辑时才显示删除按钮，新建时不显示
            setTitle(getResources().getString(R.string.edit_daily));
            showDeleteBtn(true);
        }
    }

    @Override
    public void onClick(View v) {
        super.onClick(v);
        switch (v.getId()) {
            case R.id.display_layout:
                mSwitchButton.setChecked(!mSwitchButton.isChecked());
                break;

            case R.id.record_time:
                // 选择时间 默认从2000~2050年
Answer:                 DatePicker picker = new DatePicker(this, DatePicker.DATE_TIME);