android 日历控件第二季

作者: 郑鸿翊 | 来源:发表于2015-12-31 00:27 被阅读2031次

    前言:最近一直做项目,遇到许多问题,其中令我很不爽的是:项目需求要求的日历控件一定要仿苹果!!!安卓本身提供的TimePicker是年月日分开滚动的,这不行呀,一定得一起滚,这让我挺大地感慨当前安卓开发很难真正做出android的风格出来,不是技术问题而是需求问题。还好,第二个项目对日历控件的要求没那么严格了,但是我百度了一下,开源的日历控件很少有符合心意的(可能是我没找到,有的话请留言我~),所以就根据之前的日历控件再做改进,回头看去,之前的我还是太年轻了。

    总结之前的缺陷:

    • 没有用好Canvas和Paint,绘制的位置计算不对
    • 功能不足,比如设置可已选择的日期

    于是,第二季来了


    整体效果 hohoooo

    这其实是两个部分的结合,上部分显示年月和按钮的是一个LinearLayout,下面的日历才是真正的主角。

    这一期的重点

    考虑到之前绘制了年月和切换上下月的按钮,感觉不太灵活,于是单独将日历页拿出来,这样就可以运用到很多地方了。只要结合多其他的控件,即可以做出想要的效果。

    思路部分:

    • 将高度划分为八份,第一份绘制周数,第二份至第八份绘制日期。
    • 将宽度划分为七份,分别绘制星期一至星期日。
    • 获取一个月最大天数和第一天的星期则可以得到这个月的所有日期,用以绘制。
    • 最重要的,关于时间判断处理的逻辑是最头疼的,在网上找了许多关于时间的算法,总结成了一个CalendarUtils。

    方法部分:

    • public void setYear(int year);设置年
    • public void setMonth(int month);设置月
    • public void setToday(int today);设置今天
    • public void setCalendarBg(int calendarBg);设置日历背景颜色
    • public void setAllDays(int maxnum);设置一个月的天数
    • public void setmNormalTextColor(int mNormalTextColor);设置普通文字颜色
    • public void setmBeSelectedTextColor(int mBeSelectedTextColor);设置被选择文字颜色
    • public void setmUnBeSelectedTextColor(int mUnBeSelectedTextColor);设置不可选择文字颜色
    • public void setmUnBeSelectedTextBgColor(int mUnBeSelectedTextBgColor);设置不可选择文字背景颜色
    • public void setmBeSelectedTextBgColor(int mBeSelectedTextBgColor);设置被选择文字背景颜色
    • public void setmNormalTextBgColor(int mNormalTextBgColor);设置普通文字背景颜色
    • public void setmBgRadius(int mBgRadius);设置背景半径
    • public void setmWeekTextColor(int mWeekTextColor);设置周字体颜色
    • ``

    代码部分:

    @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            super.onDraw(canvas);
            Log.d(TAG, "mViewWidth=" + mViewWidth);
            Log.d(TAG, "mViewHeight=" + mViewHeight);
            canvas.drawColor(calendarBg);
    
            int hang_num = 8;
            int lie_num = 7;
    
            xInterval = mViewWidth / lie_num;
            yInterval = mViewHeight / hang_num;
            
            //背景圆的半径
            mBgRadius = (int) (Math.min(xInterval, yInterval) / 2);
            
            mWeekTextSize = Math.min(mViewHeight, mViewWidth) / 15;
            mDayTextsize = Math.min(mViewHeight, mViewWidth) / 15;
    
            float x = 0;
            float y = 0;
            float offset = 0;
            mPaint.reset();
    
            drawWeekText(canvas);
    
            drawDay(canvas);
    
        }
    
    /**
         * 绘制周
         * 
         * @param canvas
         */
        private void drawWeekText(Canvas canvas) {
            float x, y;
            float offset;
            
            //注意,这里要先设置TextSize,后面用Paint测量String长度才会准,这样绘制文字才会准
            mPaint.setTextSize(mWeekTextSize);
            // 绘制一周
            for (int i = 0; i < weekName.length; i++) {
                x = i * xInterval + xInterval / 2;
                // 因为绘制在第一行
                y = 1 * yInterval;
    
                offset = mPaint.measureText(weekName[i]);
                if (i == 0 || i == weekName.length - 1) {
                    mPaint.setColor(mWeekTextColor);
                    mPaint.setAntiAlias(true);
                    canvas.drawText(weekName[i], x - offset / 2, y, mPaint);
                } else {
                    mPaint.setColor(mWeekTextColor);
                    mPaint.setAntiAlias(true);
                    canvas.drawText(weekName[i], x - offset / 2, y, mPaint);
                }
            }
            mPaint.reset();
        }
    

    绘制的方法也做了修改,让字体的绘制更加精准

    /**
         * 绘制天
         * 
         * @param canvas
         */
        private void drawDay(Canvas canvas) {
            mPaint.setTextSize(mDayTextsize);
            mPaint.setAntiAlias(true);
            int day = 0;
            int theday;
            boolean istoday = false;
            boolean isCheckDay = false;
            float offset = 0;
    
            float x, y;
            // 绘制的日期
            String str;
            for (int i = 2; i < 8; i++) {
                for (int j = 0; j < 7; j++) {
    
                    if (i == 2 && j == 0) {
                        j = weekOfFirstDay;
                    }
                    if (day > allDays.length - 1) {
                        theday = -1;
                    } else {
                        theday = allDays[day];
                    }
    
                    if (theday < 10) {
                        str = "0" + theday;
                    } else {
                        str = "" + theday;
                    }
                    if (theday == -1) {
                        str = "";
                    }
                    offset = mPaint.measureText(str);
                    x = j * xInterval + xInterval / 2;
                    // 因为绘制在第一行
                    y = i * yInterval;
    
                    drawDayText(x, y, str, mNormalTextColor, isToday(theday), isTheday(theday, month, year),
                            isOverdue(theday, month, year), canvas, offset);
                    day++;
                }
            }
    
        }
    

    很多代码跟之前的是重复的,不贴太多。
    主要一个贴出CalendarUtils这个工具类,帮助更多人

    package tools;
    
    import java.util.Calendar;
    
    import android.util.Log;
    
    public class CalendarUtils {
    
        private static Calendar calendar = Calendar.getInstance();
        private static int theDay = calendar.get(Calendar.DAY_OF_MONTH);
        private static int theMonth = calendar.get(Calendar.MONTH) + 1;
        private static int theYear = calendar.get(Calendar.YEAR);
    
        public static void reset() {
    
            calendar.set(theYear, theMonth - 1, theDay);
            printCalendar();
        }
        
        public static Calendar getCanlendar(){
            return calendar;
        }
    
        public static int getToday() {
            return theDay;
        }
    
        public static int getTomonth() {
            return theMonth;
        }
    
        public static int getToyear() {
            return theYear;
        }
    
        public static int getCurrentYear() {
            return calendar.get(Calendar.YEAR);
        }
    
        public static int getCurrentMonth() {
            return calendar.get(Calendar.MONTH) + 1;
        }
    
        public static int getCurrentDate() {
            return calendar.get(Calendar.DATE);
        }
    
        public static int getCurrentMaxNumOfMonth() {
            return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        }
    
        public static int getCurrentFirstWeekdayOfMoth() {
            int today = getCurrentDate();
            calendar.set(Calendar.DATE, 1);
            int weekday = calendar.get(Calendar.DAY_OF_WEEK) - 1;
            calendar.set(Calendar.DATE, today);
            return weekday;
        }
    
        public static void nextMonth() {
            calendar.add(Calendar.MONTH, 1);
        }
    
        public static void preMonth() {
            calendar.add(Calendar.MONTH, -1);
        }
    
        public static void printCalendar() {
            Log.d("CalendarUtils", getCurrentYear() + "年" + getCurrentMonth() + "月" + getCurrentDate() + "日");
            // System.out.println(getCurrentYear() + "年" + getCurrentMonth() + "月" +
            // getCurrentDate() + "日");
            // System.out.println("总共有" + getCurrentMaxNumOfMonth() + "天" + "第一天是星期"
            // + getCurrentFirstWeekdayOfMoth());
        }
    
        public static String getNextDay(int year, int month, int day) {
            calendar.set(year, month - 1, day + 1);
            int currentYear = getCurrentYear();
            int currentMonth = getCurrentMonth();
            int currentDate = getCurrentDate();
            reset();
            return currentYear + "-" + currentMonth + "-" + currentDate;
        }
    
        public static String getPreDay(int year, int month, int day) {
            calendar.set(year, month - 1, day - 1);
            int currentYear = getCurrentYear();
            int currentMonth = getCurrentMonth();
            int currentDate = getCurrentDate();
            reset();
            return currentYear + "-" + currentMonth + "-" + currentDate;
        }
    
        /**
         * O 日 距离  T 日 的天数
         * @param yearo
         * @param montho
         * @param dayo
         * @param yeart
         * @param montht
         * @param dayt
         * @return
         */
        public static int getGapCount(int yearo, int montho, int dayo, int yeart, int montht, int dayt) {
            int oldYear = getCurrentYear();
            int oldMonth = getCurrentMonth();
            int oldDay = getCurrentDate();
            
            calendar.set(yearo, montho, dayo, 0, 0, 0);
            long time1 = calendar.getTime().getTime();
            
            calendar.set(yeart, montht, dayt, 0, 0, 0);
            long time2 = calendar.getTime().getTime();
            
            calendar.set(oldYear, oldMonth-1 , oldDay);
            
            return (int) ((time1-time2) / (1000 * 60 * 60 * 24));
        }
        
        public static boolean isPreDay( int year, int month, int day){
            if(getGapCount(year,month,day,theYear,theMonth,theDay)<0){
                return true;
            }else{
                return false;
            }
        }
    
        public static void set(int year, int month, int day) {
            // TODO Auto-generated method stub
            calendar.set(year, month, day);
        }
    
    }
    

    其实,回头一看,这个日历控件好像不怎么高大上了。。。

    项目地址,欢迎点赞

    相关文章

      网友评论

      • 54fa08225713:有个时间list,主要是天数的集合,遍历后选中显示出来,然后天数里面又分三个时间段去设置控件的显示效果,要怎么实现啊
      • 212130d3d956:谢谢楼主的分享,学到很多 :+1:
        G刚刚:@yangzhenpeng
        郑鸿翊:@yangzhenpeng 能帮你很高兴,通过写这篇文章,可以回顾到一些不足之处,这些代码仍然有很多缺陷,最近忙于其他事情没得更改,有想法可以告诉我

      本文标题:android 日历控件第二季

      本文链接:https://www.haomeiwen.com/subject/nwmihttx.html