李sir_Blog

博客园 首页 联系 订阅 管理

 

 

日历控件View:

 

  1. /** 
  2.  * 日历控件 功能:获得点选的日期区间 
  3.  *  
  4.  */  
  5. public class CalendarView extends View implements View.OnTouchListener {  
  6.     private final static String TAG = "anCalendar";  
  7.     private Date selectedStartDate;  
  8.     private Date selectedEndDate;  
  9.     private Date curDate; // 当前日历显示的月  
  10.     private Date today; // 今天的日期文字显示红色  
  11.     private Date downDate; // 手指按下状态时临时日期  
  12.     private Date showFirstDate, showLastDate; // 日历显示的第一个日期和最后一个日期  
  13.     private int downIndex; // 按下的格子索引  
  14.     private Calendar calendar;  
  15.     private Surface surface;  
  16.     private int[] date = new int[42]; // 日历显示数字  
  17.     private int curStartIndex, curEndIndex; // 当前显示的日历起始的索引  
  18.     //private boolean completed = false; // 为false表示只选择了开始日期,true表示结束日期也选择了  
  19.     //给控件设置监听事件  
  20.     private OnItemClickListener onItemClickListener;  
  21.       
  22.     public CalendarView(Context context) {  
  23.         super(context);  
  24.         init();  
  25.     }  
  26.   
  27.     public CalendarView(Context context, AttributeSet attrs) {  
  28.         super(context, attrs);  
  29.         init();  
  30.     }  
  31.   
  32.     private void init() {  
  33.         curDate = selectedStartDate = selectedEndDate = today = new Date();  
  34.         calendar = Calendar.getInstance();  
  35.         calendar.setTime(curDate);  
  36.         surface = new Surface();  
  37.         surface.density = getResources().getDisplayMetrics().density;  
  38.         setBackgroundColor(surface.bgColor);  
  39.         setOnTouchListener(this);  
  40.     }  
  41.   
  42.     @Override  
  43.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  44.         surface.width = getResources().getDisplayMetrics().widthPixels;  
  45.         surface.height = (int) (getResources().getDisplayMetrics().heightPixels*2/5);  
  46. //      if (View.MeasureSpec.getMode(widthMeasureSpec) == View.MeasureSpec.EXACTLY) {  
  47. //          surface.width = View.MeasureSpec.getSize(widthMeasureSpec);  
  48. //      }  
  49. //      if (View.MeasureSpec.getMode(heightMeasureSpec) == View.MeasureSpec.EXACTLY) {  
  50. //          surface.height = View.MeasureSpec.getSize(heightMeasureSpec);  
  51. //      }  
  52.         widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(surface.width,  
  53.                 View.MeasureSpec.EXACTLY);  
  54.         heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(surface.height,  
  55.                 View.MeasureSpec.EXACTLY);  
  56.         setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);  
  57.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  58.     }  
  59.   
  60.     @Override  
  61.     protected void onLayout(boolean changed, int left, int top, int right,  
  62.             int bottom) {  
  63.         Log.d(TAG, "[onLayout] changed:"  
  64.                 + (changed ? "new size" : "not change") + " left:" + left  
  65.                 + " top:" + top + " right:" + right + " bottom:" + bottom);  
  66.         if (changed) {  
  67.             surface.init();  
  68.         }  
  69.         super.onLayout(changed, left, top, right, bottom);  
  70.     }  
  71.   
  72.     @Override  
  73.     protected void onDraw(Canvas canvas) {  
  74.         Log.d(TAG, "onDraw");  
  75.         // 画框  
  76.         canvas.drawPath(surface.boxPath, surface.borderPaint);  
  77.         // 年月  
  78.         //String monthText = getYearAndmonth();  
  79.         //float textWidth = surface.monthPaint.measureText(monthText);  
  80.         //canvas.drawText(monthText, (surface.width - textWidth) / 2f,  
  81.         //      surface.monthHeight * 3 / 4f, surface.monthPaint);  
  82.         // 上一月/下一月  
  83.         //canvas.drawPath(surface.preMonthBtnPath, surface.monthChangeBtnPaint);  
  84.         //canvas.drawPath(surface.nextMonthBtnPath, surface.monthChangeBtnPaint);  
  85.         // 星期  
  86.         float weekTextY = surface.monthHeight + surface.weekHeight * 3 / 4f;  
  87.         // 星期背景  
  88. //      surface.cellBgPaint.setColor(surface.textColor);  
  89. //      canvas.drawRect(surface.weekHeight, surface.width, surface.weekHeight, surface.width, surface.cellBgPaint);  
  90.         for (int i = 0; i < surface.weekText.length; i++) {  
  91.             float weekTextX = i  
  92.                     * surface.cellWidth  
  93.                     + (surface.cellWidth - surface.weekPaint  
  94.                             .measureText(surface.weekText[i])) / 2f;  
  95.             canvas.drawText(surface.weekText[i], weekTextX, weekTextY,  
  96.                     surface.weekPaint);  
  97.         }  
  98.           
  99.         // 计算日期  
  100.         calculateDate();  
  101.         // 按下状态,选择状态背景色  
  102.         drawDownOrSelectedBg(canvas);  
  103.         // write date number  
  104.         // today index  
  105.         int todayIndex = -1;  
  106.         calendar.setTime(curDate);  
  107.         String curYearAndMonth = calendar.get(Calendar.YEAR) + ""  
  108.                 + calendar.get(Calendar.MONTH);  
  109.         calendar.setTime(today);  
  110.         String todayYearAndMonth = calendar.get(Calendar.YEAR) + ""  
  111.                 + calendar.get(Calendar.MONTH);  
  112.         if (curYearAndMonth.equals(todayYearAndMonth)) {  
  113.             int todayNumber = calendar.get(Calendar.DAY_OF_MONTH);  
  114.             todayIndex = curStartIndex + todayNumber - 1;  
  115.         }  
  116.         for (int i = 0; i < 42; i++) {  
  117.             int color = surface.textColor;  
  118.             if (isLastMonth(i)) {  
  119.                 color = surface.borderColor;  
  120.             } else if (isNextMonth(i)) {  
  121.                 color = surface.borderColor;  
  122.             }  
  123.             if (todayIndex != -1 && i == todayIndex) {  
  124.                 color = surface.todayNumberColor;  
  125.             }  
  126.             drawCellText(canvas, i, date[i] + "", color);  
  127.         }  
  128.         super.onDraw(canvas);  
  129.     }  
  130.   
  131.     private void calculateDate() {  
  132.         calendar.setTime(curDate);  
  133.         calendar.set(Calendar.DAY_OF_MONTH, 1);  
  134.         int dayInWeek = calendar.get(Calendar.DAY_OF_WEEK);  
  135.         Log.d(TAG, "day in week:" + dayInWeek);  
  136.         int monthStart = dayInWeek;  
  137.         if (monthStart == 1) {  
  138.             monthStart = 8;  
  139.         }  
  140.         monthStart -= 1;  //以日为开头-1,以星期一为开头-2  
  141.         curStartIndex = monthStart;  
  142.         date[monthStart] = 1;  
  143.         // last month  
  144.         if (monthStart > 0) {  
  145.             calendar.set(Calendar.DAY_OF_MONTH, 0);  
  146.             int dayInmonth = calendar.get(Calendar.DAY_OF_MONTH);  
  147.             for (int i = monthStart - 1; i >= 0; i--) {  
  148.                 date[i] = dayInmonth;  
  149.                 dayInmonth--;  
  150.             }  
  151.             calendar.set(Calendar.DAY_OF_MONTH, date[0]);  
  152.         }  
  153.         showFirstDate = calendar.getTime();  
  154.         // this month  
  155.         calendar.setTime(curDate);  
  156.         calendar.add(Calendar.MONTH, 1);  
  157.         calendar.set(Calendar.DAY_OF_MONTH, 0);  
  158.         // Log.d(TAG, "m:" + calendar.get(Calendar.MONTH) + " d:" +  
  159.         // calendar.get(Calendar.DAY_OF_MONTH));  
  160.         int monthDay = calendar.get(Calendar.DAY_OF_MONTH);  
  161.         for (int i = 1; i < monthDay; i++) {  
  162.             date[monthStart + i] = i + 1;  
  163.         }  
  164.         curEndIndex = monthStart + monthDay;  
  165.         // next month  
  166.         for (int i = monthStart + monthDay; i < 42; i++) {  
  167.             date[i] = i - (monthStart + monthDay) + 1;  
  168.         }  
  169.         if (curEndIndex < 42) {  
  170.             // 显示了下一月的  
  171.             calendar.add(Calendar.DAY_OF_MONTH, 1);  
  172.         }  
  173.         calendar.set(Calendar.DAY_OF_MONTH, date[41]);  
  174.         showLastDate = calendar.getTime();  
  175.     }  
  176.   
  177.     /** 
  178.      *  
  179.      * @param canvas 
  180.      * @param index 
  181.      * @param text 
  182.      */  
  183.     private void drawCellText(Canvas canvas, int index, String text, int color) {  
  184.         int x = getXByIndex(index);  
  185.         int y = getYByIndex(index);  
  186.         surface.datePaint.setColor(color);  
  187.         float cellY = surface.monthHeight + surface.weekHeight + (y - 1)  
  188.                 * surface.cellHeight + surface.cellHeight * 3 / 4f;  
  189.         float cellX = (surface.cellWidth * (x - 1))  
  190.                 + (surface.cellWidth - surface.datePaint.measureText(text))  
  191.                 / 2f;  
  192.         canvas.drawText(text, cellX, cellY, surface.datePaint);  
  193.     }  
  194.   
  195.     /** 
  196.      *  
  197.      * @param canvas 
  198.      * @param index 
  199.      * @param color 
  200.      */  
  201.     private void drawCellBg(Canvas canvas, int index, int color) {  
  202.         int x = getXByIndex(index);  
  203.         int y = getYByIndex(index);  
  204.         surface.cellBgPaint.setColor(color);  
  205.         float left = surface.cellWidth * (x - 1) + surface.borderWidth;  
  206.         float top = surface.monthHeight + surface.weekHeight + (y - 1)  
  207.                 * surface.cellHeight + surface.borderWidth;  
  208.         canvas.drawRect(left, top, left + surface.cellWidth  
  209.                 - surface.borderWidth, top + surface.cellHeight  
  210.                 - surface.borderWidth, surface.cellBgPaint);  
  211.     }  
  212.   
  213.     private void drawDownOrSelectedBg(Canvas canvas) {  
  214.         // down and not up  
  215.         if (downDate != null) {  
  216.             drawCellBg(canvas, downIndex, surface.cellDownColor);  
  217.         }  
  218.         // selected bg color  
  219.         if (!selectedEndDate.before(showFirstDate)  
  220.                 && !selectedStartDate.after(showLastDate)) {  
  221.             int[] section = new int[] { -1, -1 };  
  222.             calendar.setTime(curDate);  
  223.             calendar.add(Calendar.MONTH, -1);  
  224.             findSelectedIndex(0, curStartIndex, calendar, section);  
  225.             if (section[1] == -1) {  
  226.                 calendar.setTime(curDate);  
  227.                 findSelectedIndex(curStartIndex, curEndIndex, calendar, section);  
  228.             }  
  229.             if (section[1] == -1) {  
  230.                 calendar.setTime(curDate);  
  231.                 calendar.add(Calendar.MONTH, 1);  
  232.                 findSelectedIndex(curEndIndex, 42, calendar, section);  
  233.             }  
  234.             if (section[0] == -1) {  
  235.                 section[0] = 0;  
  236.             }  
  237.             if (section[1] == -1) {  
  238.                 section[1] = 41;  
  239.             }  
  240.             for (int i = section[0]; i <= section[1]; i++) {  
  241.                 drawCellBg(canvas, i, surface.cellSelectedColor);  
  242.             }  
  243.         }  
  244.     }  
  245.   
  246.     private void findSelectedIndex(int startIndex, int endIndex,  
  247.             Calendar calendar, int[] section) {  
  248.         for (int i = startIndex; i < endIndex; i++) {  
  249.             calendar.set(Calendar.DAY_OF_MONTH, date[i]);  
  250.             Date temp = calendar.getTime();  
  251.             // Log.d(TAG, "temp:" + temp.toLocaleString());  
  252.             if (temp.compareTo(selectedStartDate) == 0) {  
  253.                 section[0] = i;  
  254.             }  
  255.             if (temp.compareTo(selectedEndDate) == 0) {  
  256.                 section[1] = i;  
  257.                 return;  
  258.             }  
  259.         }  
  260.     }  
  261.   
  262.     public Date getSelectedStartDate() {  
  263.         return selectedStartDate;  
  264.     }  
  265.   
  266.     public Date getSelectedEndDate() {  
  267.         return selectedEndDate;  
  268.     }  
  269.   
  270.     private boolean isLastMonth(int i) {  
  271.         if (i < curStartIndex) {  
  272.             return true;  
  273.         }  
  274.         return false;  
  275.     }  
  276.   
  277.     private boolean isNextMonth(int i) {  
  278.         if (i >= curEndIndex) {  
  279.             return true;  
  280.         }  
  281.         return false;  
  282.     }  
  283.   
  284.     private int getXByIndex(int i) {  
  285.         return i % 7 + 1; // 1 2 3 4 5 6 7  
  286.     }  
  287.   
  288.     private int getYByIndex(int i) {  
  289.         return i / 7 + 1; // 1 2 3 4 5 6  
  290.     }  
  291.   
  292.     // 获得当前应该显示的年月  
  293.     public String getYearAndmonth() {  
  294.         calendar.setTime(curDate);  
  295.         int year = calendar.get(Calendar.YEAR);  
  296.         int month = calendar.get(Calendar.MONTH);  
  297.         return year + "-" + surface.monthText[month];  
  298.     }  
  299.       
  300.     //上一月  
  301.     public String clickLeftMonth(){  
  302.         calendar.setTime(curDate);  
  303.         calendar.add(Calendar.MONTH, -1);  
  304.         curDate = calendar.getTime();  
  305.         invalidate();  
  306.         return getYearAndmonth();  
  307.     }  
  308.     //下一月  
  309.     public String clickRightMonth(){  
  310.         calendar.setTime(curDate);  
  311.         calendar.add(Calendar.MONTH, 1);  
  312.         curDate = calendar.getTime();  
  313.         invalidate();  
  314.         return getYearAndmonth();  
  315.     }  
  316.   
  317.     private void setSelectedDateByCoor(float x, float y) {  
  318.         // change month  
  319. //      if (y < surface.monthHeight) {  
  320. //          // pre month  
  321. //          if (x < surface.monthChangeWidth) {  
  322. //              calendar.setTime(curDate);  
  323. //              calendar.add(Calendar.MONTH, -1);  
  324. //              curDate = calendar.getTime();  
  325. //          }  
  326. //          // next month  
  327. //          else if (x > surface.width - surface.monthChangeWidth) {  
  328. //              calendar.setTime(curDate);  
  329. //              calendar.add(Calendar.MONTH, 1);  
  330. //              curDate = calendar.getTime();  
  331. //          }  
  332. //      }  
  333.         // cell click down  
  334.         if (y > surface.monthHeight + surface.weekHeight) {  
  335.             int m = (int) (Math.floor(x / surface.cellWidth) + 1);  
  336.             int n = (int) (Math  
  337.                     .floor((y - (surface.monthHeight + surface.weekHeight))  
  338.                             / Float.valueOf(surface.cellHeight)) + 1);  
  339.             downIndex = (n - 1) * 7 + m - 1;  
  340.             Log.d(TAG, "downIndex:" + downIndex);  
  341.             calendar.setTime(curDate);  
  342.             if (isLastMonth(downIndex)) {  
  343.                 calendar.add(Calendar.MONTH, -1);  
  344.             } else if (isNextMonth(downIndex)) {  
  345.                 calendar.add(Calendar.MONTH, 1);  
  346.             }  
  347.             calendar.set(Calendar.DAY_OF_MONTH, date[downIndex]);  
  348.             downDate = calendar.getTime();  
  349.         }  
  350.         invalidate();  
  351.     }  
  352.   
  353.     @Override  
  354.     public boolean onTouch(View v, MotionEvent event) {  
  355.         switch (event.getAction()) {  
  356.         case MotionEvent.ACTION_DOWN:  
  357.             setSelectedDateByCoor(event.getX(), event.getY());  
  358.             break;  
  359.         case MotionEvent.ACTION_UP:  
  360.             if (downDate != null) {  
  361. //              if (!completed) {  
  362. //                  if (downDate.before(selectedStartDate)) {  
  363. //                      selectedEndDate = selectedStartDate;  
  364. //                      selectedStartDate = downDate;  
  365. //                  } else {  
  366. //                      selectedEndDate = downDate;  
  367. //                  }  
  368. //                  completed = true;  
  369. //              } else {  
  370. //                  selectedStartDate = selectedEndDate = downDate;  
  371. //                  completed = false;  
  372. //              }  
  373.                 selectedStartDate = selectedEndDate = downDate;  
  374.                 //响应监听事件  
  375.                 onItemClickListener.OnItemClick(selectedStartDate);  
  376.                 // Log.d(TAG, "downdate:" + downDate.toLocaleString());  
  377.                 //Log.d(TAG, "start:" + selectedStartDate.toLocaleString());  
  378.                 //Log.d(TAG, "end:" + selectedEndDate.toLocaleString());  
  379.                 downDate = null;  
  380.                 invalidate();  
  381.             }  
  382.             break;  
  383.         }  
  384.         return true;  
  385.     }  
  386.       
  387.     //给控件设置监听事件  
  388.     public void setOnItemClickListener(OnItemClickListener onItemClickListener){  
  389.         this.onItemClickListener =  onItemClickListener;  
  390.     }  
  391.     //监听接口  
  392.     public interface OnItemClickListener {  
  393.         void OnItemClick(Date date);  
  394.     }  
  395.   
  396.     /** 
  397.      *  
  398.      * 1. 布局尺寸 2. 文字颜色,大小 3. 当前日期的颜色,选择的日期颜色 
  399.      */  
  400.     private class Surface {  
  401.         public float density;  
  402.         public int width; // 整个控件的宽度  
  403.         public int height; // 整个控件的高度  
  404.         public float monthHeight; // 显示月的高度  
  405.         //public float monthChangeWidth; // 上一月、下一月按钮宽度  
  406.         public float weekHeight; // 显示星期的高度  
  407.         public float cellWidth; // 日期方框宽度  
  408.         public float cellHeight; // 日期方框高度    
  409.         public float borderWidth;  
  410.         public int bgColor = Color.parseColor("#FFFFFF");  
  411.         private int textColor = Color.BLACK;  
  412.         //private int textColorUnimportant = Color.parseColor("#666666");  
  413.         private int btnColor = Color.parseColor("#666666");  
  414.         private int borderColor = Color.parseColor("#CCCCCC");  
  415.         public int todayNumberColor = Color.RED;  
  416.         public int cellDownColor = Color.parseColor("#CCFFFF");  
  417.         public int cellSelectedColor = Color.parseColor("#99CCFF");  
  418.         public Paint borderPaint;  
  419.         public Paint monthPaint;  
  420.         public Paint weekPaint;  
  421.         public Paint datePaint;  
  422.         public Paint monthChangeBtnPaint;  
  423.         public Paint cellBgPaint;  
  424.         public Path boxPath; // 边框路径  
  425.         //public Path preMonthBtnPath; // 上一月按钮三角形  
  426.         //public Path nextMonthBtnPath; // 下一月按钮三角形  
  427.         public String[] weekText = { "Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};  
  428.         public String[] monthText = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};  
  429.              
  430.         public void init() {  
  431.             float temp = height / 7f;  
  432.             monthHeight = 0;//(float) ((temp + temp * 0.3f) * 0.6);  
  433.             //monthChangeWidth = monthHeight * 1.5f;  
  434.             weekHeight = (float) ((temp + temp * 0.3f) * 0.7);  
  435.             cellHeight = (height - monthHeight - weekHeight) / 6f;  
  436.             cellWidth = width / 7f;  
  437.             borderPaint = new Paint();  
  438.             borderPaint.setColor(borderColor);  
  439.             borderPaint.setStyle(Paint.Style.STROKE);  
  440.             borderWidth = (float) (0.5 * density);  
  441.             // Log.d(TAG, "borderwidth:" + borderWidth);  
  442.             borderWidth = borderWidth < 1 ? 1 : borderWidth;  
  443.             borderPaint.setStrokeWidth(borderWidth);  
  444.             monthPaint = new Paint();  
  445.             monthPaint.setColor(textColor);  
  446.             monthPaint.setAntiAlias(true);  
  447.             float textSize = cellHeight * 0.4f;  
  448.             Log.d(TAG, "text size:" + textSize);  
  449.             monthPaint.setTextSize(textSize);  
  450.             monthPaint.setTypeface(Typeface.DEFAULT_BOLD);  
  451.             weekPaint = new Paint();  
  452.             weekPaint.setColor(textColor);  
  453.             weekPaint.setAntiAlias(true);  
  454.             float weekTextSize = weekHeight * 0.6f;  
  455.             weekPaint.setTextSize(weekTextSize);  
  456.             weekPaint.setTypeface(Typeface.DEFAULT_BOLD);  
  457.             datePaint = new Paint();  
  458.             datePaint.setColor(textColor);  
  459.             datePaint.setAntiAlias(true);  
  460.             float cellTextSize = cellHeight * 0.5f;  
  461.             datePaint.setTextSize(cellTextSize);  
  462.             datePaint.setTypeface(Typeface.DEFAULT_BOLD);  
  463.             boxPath = new Path();  
  464.             //boxPath.addRect(0, 0, width, height, Direction.CW);  
  465.             //boxPath.moveTo(0, monthHeight);  
  466.             boxPath.rLineTo(width, 0);  
  467.             boxPath.moveTo(0, monthHeight + weekHeight);  
  468.             boxPath.rLineTo(width, 0);  
  469.             for (int i = 1; i < 6; i++) {  
  470.                 boxPath.moveTo(0, monthHeight + weekHeight + i * cellHeight);  
  471.                 boxPath.rLineTo(width, 0);  
  472.                 boxPath.moveTo(i * cellWidth, monthHeight);  
  473.                 boxPath.rLineTo(0, height - monthHeight);  
  474.             }  
  475.             boxPath.moveTo(6 * cellWidth, monthHeight);  
  476.             boxPath.rLineTo(0, height - monthHeight);  
  477.             //preMonthBtnPath = new Path();  
  478.             //int btnHeight = (int) (monthHeight * 0.6f);  
  479.             //preMonthBtnPath.moveTo(monthChangeWidth / 2f, monthHeight / 2f);  
  480.             //preMonthBtnPath.rLineTo(btnHeight / 2f, -btnHeight / 2f);  
  481.             //preMonthBtnPath.rLineTo(0, btnHeight);  
  482.             //preMonthBtnPath.close();  
  483.             //nextMonthBtnPath = new Path();  
  484.             //nextMonthBtnPath.moveTo(width - monthChangeWidth / 2f,  
  485.             //      monthHeight / 2f);  
  486.             //nextMonthBtnPath.rLineTo(-btnHeight / 2f, -btnHeight / 2f);  
  487.             //nextMonthBtnPath.rLineTo(0, btnHeight);  
  488.             //nextMonthBtnPath.close();  
  489.             monthChangeBtnPaint = new Paint();  
  490.             monthChangeBtnPaint.setAntiAlias(true);  
  491.             monthChangeBtnPaint.setStyle(Paint.Style.FILL_AND_STROKE);  
  492.             monthChangeBtnPaint.setColor(btnColor);  
  493.             cellBgPaint = new Paint();  
  494.             cellBgPaint.setAntiAlias(true);  
  495.             cellBgPaint.setStyle(Paint.Style.FILL);  
  496.             cellBgPaint.setColor(cellSelectedColor);  
  497.         }  
  498.     }  
  499. }  
/**
 * 日历控件 功能:获得点选的日期区间
 * 
 */
public class CalendarView extends View implements View.OnTouchListener {
	private final static String TAG = "anCalendar";
	private Date selectedStartDate;
	private Date selectedEndDate;
	private Date curDate; // 当前日历显示的月
	private Date today; // 今天的日期文字显示红色
	private Date downDate; // 手指按下状态时临时日期
	private Date showFirstDate, showLastDate; // 日历显示的第一个日期和最后一个日期
	private int downIndex; // 按下的格子索引
	private Calendar calendar;
	private Surface surface;
	private int[] date = new int[42]; // 日历显示数字
	private int curStartIndex, curEndIndex; // 当前显示的日历起始的索引
	//private boolean completed = false; // 为false表示只选择了开始日期,true表示结束日期也选择了
	//给控件设置监听事件
	private OnItemClickListener onItemClickListener;
	
	public CalendarView(Context context) {
		super(context);
		init();
	}

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

	private void init() {
		curDate = selectedStartDate = selectedEndDate = today = new Date();
		calendar = Calendar.getInstance();
		calendar.setTime(curDate);
		surface = new Surface();
		surface.density = getResources().getDisplayMetrics().density;
		setBackgroundColor(surface.bgColor);
		setOnTouchListener(this);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		surface.width = getResources().getDisplayMetrics().widthPixels;
		surface.height = (int) (getResources().getDisplayMetrics().heightPixels*2/5);
//		if (View.MeasureSpec.getMode(widthMeasureSpec) == View.MeasureSpec.EXACTLY) {
//			surface.width = View.MeasureSpec.getSize(widthMeasureSpec);
//		}
//		if (View.MeasureSpec.getMode(heightMeasureSpec) == View.MeasureSpec.EXACTLY) {
//			surface.height = View.MeasureSpec.getSize(heightMeasureSpec);
//		}
		widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(surface.width,
				View.MeasureSpec.EXACTLY);
		heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(surface.height,
				View.MeasureSpec.EXACTLY);
		setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		Log.d(TAG, "[onLayout] changed:"
				+ (changed ? "new size" : "not change") + " left:" + left
				+ " top:" + top + " right:" + right + " bottom:" + bottom);
		if (changed) {
			surface.init();
		}
		super.onLayout(changed, left, top, right, bottom);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		Log.d(TAG, "onDraw");
		// 画框
		canvas.drawPath(surface.boxPath, surface.borderPaint);
		// 年月
		//String monthText = getYearAndmonth();
		//float textWidth = surface.monthPaint.measureText(monthText);
		//canvas.drawText(monthText, (surface.width - textWidth) / 2f,
		//		surface.monthHeight * 3 / 4f, surface.monthPaint);
		// 上一月/下一月
		//canvas.drawPath(surface.preMonthBtnPath, surface.monthChangeBtnPaint);
		//canvas.drawPath(surface.nextMonthBtnPath, surface.monthChangeBtnPaint);
		// 星期
		float weekTextY = surface.monthHeight + surface.weekHeight * 3 / 4f;
		// 星期背景
//		surface.cellBgPaint.setColor(surface.textColor);
//		canvas.drawRect(surface.weekHeight, surface.width, surface.weekHeight, surface.width, surface.cellBgPaint);
		for (int i = 0; i < surface.weekText.length; i++) {
			float weekTextX = i
					* surface.cellWidth
					+ (surface.cellWidth - surface.weekPaint
							.measureText(surface.weekText[i])) / 2f;
			canvas.drawText(surface.weekText[i], weekTextX, weekTextY,
					surface.weekPaint);
		}
		
		// 计算日期
		calculateDate();
		// 按下状态,选择状态背景色
		drawDownOrSelectedBg(canvas);
		// write date number
		// today index
		int todayIndex = -1;
		calendar.setTime(curDate);
		String curYearAndMonth = calendar.get(Calendar.YEAR) + ""
				+ calendar.get(Calendar.MONTH);
		calendar.setTime(today);
		String todayYearAndMonth = calendar.get(Calendar.YEAR) + ""
				+ calendar.get(Calendar.MONTH);
		if (curYearAndMonth.equals(todayYearAndMonth)) {
			int todayNumber = calendar.get(Calendar.DAY_OF_MONTH);
			todayIndex = curStartIndex + todayNumber - 1;
		}
		for (int i = 0; i < 42; i++) {
			int color = surface.textColor;
			if (isLastMonth(i)) {
				color = surface.borderColor;
			} else if (isNextMonth(i)) {
				color = surface.borderColor;
			}
			if (todayIndex != -1 && i == todayIndex) {
				color = surface.todayNumberColor;
			}
			drawCellText(canvas, i, date[i] + "", color);
		}
		super.onDraw(canvas);
	}

	private void calculateDate() {
		calendar.setTime(curDate);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		int dayInWeek = calendar.get(Calendar.DAY_OF_WEEK);
		Log.d(TAG, "day in week:" + dayInWeek);
		int monthStart = dayInWeek;
		if (monthStart == 1) {
			monthStart = 8;
		}
		monthStart -= 1;  //以日为开头-1,以星期一为开头-2
		curStartIndex = monthStart;
		date[monthStart] = 1;
		// last month
		if (monthStart > 0) {
			calendar.set(Calendar.DAY_OF_MONTH, 0);
			int dayInmonth = calendar.get(Calendar.DAY_OF_MONTH);
			for (int i = monthStart - 1; i >= 0; i--) {
				date[i] = dayInmonth;
				dayInmonth--;
			}
			calendar.set(Calendar.DAY_OF_MONTH, date[0]);
		}
		showFirstDate = calendar.getTime();
		// this month
		calendar.setTime(curDate);
		calendar.add(Calendar.MONTH, 1);
		calendar.set(Calendar.DAY_OF_MONTH, 0);
		// Log.d(TAG, "m:" + calendar.get(Calendar.MONTH) + " d:" +
		// calendar.get(Calendar.DAY_OF_MONTH));
		int monthDay = calendar.get(Calendar.DAY_OF_MONTH);
		for (int i = 1; i < monthDay; i++) {
			date[monthStart + i] = i + 1;
		}
		curEndIndex = monthStart + monthDay;
		// next month
		for (int i = monthStart + monthDay; i < 42; i++) {
			date[i] = i - (monthStart + monthDay) + 1;
		}
		if (curEndIndex < 42) {
			// 显示了下一月的
			calendar.add(Calendar.DAY_OF_MONTH, 1);
		}
		calendar.set(Calendar.DAY_OF_MONTH, date[41]);
		showLastDate = calendar.getTime();
	}

	/**
	 * 
	 * @param canvas
	 * @param index
	 * @param text
	 */
	private void drawCellText(Canvas canvas, int index, String text, int color) {
		int x = getXByIndex(index);
		int y = getYByIndex(index);
		surface.datePaint.setColor(color);
		float cellY = surface.monthHeight + surface.weekHeight + (y - 1)
				* surface.cellHeight + surface.cellHeight * 3 / 4f;
		float cellX = (surface.cellWidth * (x - 1))
				+ (surface.cellWidth - surface.datePaint.measureText(text))
				/ 2f;
		canvas.drawText(text, cellX, cellY, surface.datePaint);
	}

	/**
	 * 
	 * @param canvas
	 * @param index
	 * @param color
	 */
	private void drawCellBg(Canvas canvas, int index, int color) {
		int x = getXByIndex(index);
		int y = getYByIndex(index);
		surface.cellBgPaint.setColor(color);
		float left = surface.cellWidth * (x - 1) + surface.borderWidth;
		float top = surface.monthHeight + surface.weekHeight + (y - 1)
				* surface.cellHeight + surface.borderWidth;
		canvas.drawRect(left, top, left + surface.cellWidth
				- surface.borderWidth, top + surface.cellHeight
				- surface.borderWidth, surface.cellBgPaint);
	}

	private void drawDownOrSelectedBg(Canvas canvas) {
		// down and not up
		if (downDate != null) {
			drawCellBg(canvas, downIndex, surface.cellDownColor);
		}
		// selected bg color
		if (!selectedEndDate.before(showFirstDate)
				&& !selectedStartDate.after(showLastDate)) {
			int[] section = new int[] { -1, -1 };
			calendar.setTime(curDate);
			calendar.add(Calendar.MONTH, -1);
			findSelectedIndex(0, curStartIndex, calendar, section);
			if (section[1] == -1) {
				calendar.setTime(curDate);
				findSelectedIndex(curStartIndex, curEndIndex, calendar, section);
			}
			if (section[1] == -1) {
				calendar.setTime(curDate);
				calendar.add(Calendar.MONTH, 1);
				findSelectedIndex(curEndIndex, 42, calendar, section);
			}
			if (section[0] == -1) {
				section[0] = 0;
			}
			if (section[1] == -1) {
				section[1] = 41;
			}
			for (int i = section[0]; i <= section[1]; i++) {
				drawCellBg(canvas, i, surface.cellSelectedColor);
			}
		}
	}

	private void findSelectedIndex(int startIndex, int endIndex,
			Calendar calendar, int[] section) {
		for (int i = startIndex; i < endIndex; i++) {
			calendar.set(Calendar.DAY_OF_MONTH, date[i]);
			Date temp = calendar.getTime();
			// Log.d(TAG, "temp:" + temp.toLocaleString());
			if (temp.compareTo(selectedStartDate) == 0) {
				section[0] = i;
			}
			if (temp.compareTo(selectedEndDate) == 0) {
				section[1] = i;
				return;
			}
		}
	}

	public Date getSelectedStartDate() {
		return selectedStartDate;
	}

	public Date getSelectedEndDate() {
		return selectedEndDate;
	}

	private boolean isLastMonth(int i) {
		if (i < curStartIndex) {
			return true;
		}
		return false;
	}

	private boolean isNextMonth(int i) {
		if (i >= curEndIndex) {
			return true;
		}
		return false;
	}

	private int getXByIndex(int i) {
		return i % 7 + 1; // 1 2 3 4 5 6 7
	}

	private int getYByIndex(int i) {
		return i / 7 + 1; // 1 2 3 4 5 6
	}

	// 获得当前应该显示的年月
	public String getYearAndmonth() {
		calendar.setTime(curDate);
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH);
		return year + "-" + surface.monthText[month];
	}
	
	//上一月
	public String clickLeftMonth(){
		calendar.setTime(curDate);
		calendar.add(Calendar.MONTH, -1);
		curDate = calendar.getTime();
		invalidate();
		return getYearAndmonth();
	}
	//下一月
	public String clickRightMonth(){
		calendar.setTime(curDate);
		calendar.add(Calendar.MONTH, 1);
		curDate = calendar.getTime();
		invalidate();
		return getYearAndmonth();
	}

	private void setSelectedDateByCoor(float x, float y) {
		// change month
//		if (y < surface.monthHeight) {
//			// pre month
//			if (x < surface.monthChangeWidth) {
//				calendar.setTime(curDate);
//				calendar.add(Calendar.MONTH, -1);
//				curDate = calendar.getTime();
//			}
//			// next month
//			else if (x > surface.width - surface.monthChangeWidth) {
//				calendar.setTime(curDate);
//				calendar.add(Calendar.MONTH, 1);
//				curDate = calendar.getTime();
//			}
//		}
		// cell click down
		if (y > surface.monthHeight + surface.weekHeight) {
			int m = (int) (Math.floor(x / surface.cellWidth) + 1);
			int n = (int) (Math
					.floor((y - (surface.monthHeight + surface.weekHeight))
							/ Float.valueOf(surface.cellHeight)) + 1);
			downIndex = (n - 1) * 7 + m - 1;
			Log.d(TAG, "downIndex:" + downIndex);
			calendar.setTime(curDate);
			if (isLastMonth(downIndex)) {
				calendar.add(Calendar.MONTH, -1);
			} else if (isNextMonth(downIndex)) {
				calendar.add(Calendar.MONTH, 1);
			}
			calendar.set(Calendar.DAY_OF_MONTH, date[downIndex]);
			downDate = calendar.getTime();
		}
		invalidate();
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			setSelectedDateByCoor(event.getX(), event.getY());
			break;
		case MotionEvent.ACTION_UP:
			if (downDate != null) {
//				if (!completed) {
//					if (downDate.before(selectedStartDate)) {
//						selectedEndDate = selectedStartDate;
//						selectedStartDate = downDate;
//					} else {
//						selectedEndDate = downDate;
//					}
//					completed = true;
//				} else {
//					selectedStartDate = selectedEndDate = downDate;
//					completed = false;
//				}
				selectedStartDate = selectedEndDate = downDate;
				//响应监听事件
				onItemClickListener.OnItemClick(selectedStartDate);
				// Log.d(TAG, "downdate:" + downDate.toLocaleString());
				//Log.d(TAG, "start:" + selectedStartDate.toLocaleString());
				//Log.d(TAG, "end:" + selectedEndDate.toLocaleString());
				downDate = null;
				invalidate();
			}
			break;
		}
		return true;
	}
	
	//给控件设置监听事件
	public void setOnItemClickListener(OnItemClickListener onItemClickListener){
		this.onItemClickListener =  onItemClickListener;
	}
	//监听接口
	public interface OnItemClickListener {
		void OnItemClick(Date date);
	}

	/**
	 * 
	 * 1. 布局尺寸 2. 文字颜色,大小 3. 当前日期的颜色,选择的日期颜色
	 */
	private class Surface {
		public float density;
		public int width; // 整个控件的宽度
		public int height; // 整个控件的高度
		public float monthHeight; // 显示月的高度
		//public float monthChangeWidth; // 上一月、下一月按钮宽度
		public float weekHeight; // 显示星期的高度
		public float cellWidth; // 日期方框宽度
		public float cellHeight; // 日期方框高度	
		public float borderWidth;
		public int bgColor = Color.parseColor("#FFFFFF");
		private int textColor = Color.BLACK;
		//private int textColorUnimportant = Color.parseColor("#666666");
		private int btnColor = Color.parseColor("#666666");
		private int borderColor = Color.parseColor("#CCCCCC");
		public int todayNumberColor = Color.RED;
		public int cellDownColor = Color.parseColor("#CCFFFF");
		public int cellSelectedColor = Color.parseColor("#99CCFF");
		public Paint borderPaint;
		public Paint monthPaint;
		public Paint weekPaint;
		public Paint datePaint;
		public Paint monthChangeBtnPaint;
		public Paint cellBgPaint;
		public Path boxPath; // 边框路径
		//public Path preMonthBtnPath; // 上一月按钮三角形
		//public Path nextMonthBtnPath; // 下一月按钮三角形
		public String[] weekText = { "Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
		public String[] monthText = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
		   
		public void init() {
			float temp = height / 7f;
			monthHeight = 0;//(float) ((temp + temp * 0.3f) * 0.6);
			//monthChangeWidth = monthHeight * 1.5f;
			weekHeight = (float) ((temp + temp * 0.3f) * 0.7);
			cellHeight = (height - monthHeight - weekHeight) / 6f;
			cellWidth = width / 7f;
			borderPaint = new Paint();
			borderPaint.setColor(borderColor);
			borderPaint.setStyle(Paint.Style.STROKE);
			borderWidth = (float) (0.5 * density);
			// Log.d(TAG, "borderwidth:" + borderWidth);
			borderWidth = borderWidth < 1 ? 1 : borderWidth;
			borderPaint.setStrokeWidth(borderWidth);
			monthPaint = new Paint();
			monthPaint.setColor(textColor);
			monthPaint.setAntiAlias(true);
			float textSize = cellHeight * 0.4f;
			Log.d(TAG, "text size:" + textSize);
			monthPaint.setTextSize(textSize);
			monthPaint.setTypeface(Typeface.DEFAULT_BOLD);
			weekPaint = new Paint();
			weekPaint.setColor(textColor);
			weekPaint.setAntiAlias(true);
			float weekTextSize = weekHeight * 0.6f;
			weekPaint.setTextSize(weekTextSize);
			weekPaint.setTypeface(Typeface.DEFAULT_BOLD);
			datePaint = new Paint();
			datePaint.setColor(textColor);
			datePaint.setAntiAlias(true);
			float cellTextSize = cellHeight * 0.5f;
			datePaint.setTextSize(cellTextSize);
			datePaint.setTypeface(Typeface.DEFAULT_BOLD);
			boxPath = new Path();
			//boxPath.addRect(0, 0, width, height, Direction.CW);
			//boxPath.moveTo(0, monthHeight);
			boxPath.rLineTo(width, 0);
			boxPath.moveTo(0, monthHeight + weekHeight);
			boxPath.rLineTo(width, 0);
			for (int i = 1; i < 6; i++) {
				boxPath.moveTo(0, monthHeight + weekHeight + i * cellHeight);
				boxPath.rLineTo(width, 0);
				boxPath.moveTo(i * cellWidth, monthHeight);
				boxPath.rLineTo(0, height - monthHeight);
			}
			boxPath.moveTo(6 * cellWidth, monthHeight);
			boxPath.rLineTo(0, height - monthHeight);
			//preMonthBtnPath = new Path();
			//int btnHeight = (int) (monthHeight * 0.6f);
			//preMonthBtnPath.moveTo(monthChangeWidth / 2f, monthHeight / 2f);
			//preMonthBtnPath.rLineTo(btnHeight / 2f, -btnHeight / 2f);
			//preMonthBtnPath.rLineTo(0, btnHeight);
			//preMonthBtnPath.close();
			//nextMonthBtnPath = new Path();
			//nextMonthBtnPath.moveTo(width - monthChangeWidth / 2f,
			//		monthHeight / 2f);
			//nextMonthBtnPath.rLineTo(-btnHeight / 2f, -btnHeight / 2f);
			//nextMonthBtnPath.rLineTo(0, btnHeight);
			//nextMonthBtnPath.close();
			monthChangeBtnPaint = new Paint();
			monthChangeBtnPaint.setAntiAlias(true);
			monthChangeBtnPaint.setStyle(Paint.Style.FILL_AND_STROKE);
			monthChangeBtnPaint.setColor(btnColor);
			cellBgPaint = new Paint();
			cellBgPaint.setAntiAlias(true);
			cellBgPaint.setStyle(Paint.Style.FILL);
			cellBgPaint.setColor(cellSelectedColor);
		}
	}
}
实现日历控件:

 

 

  1. <RelativeLayout  
  2.     android:id="@+id/layout_calendar"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="wrap_content"  
  5.     android:visibility="visible" >  
  6.   
  7.     <TextView  
  8.         android:id="@+id/calendarCenter"  
  9.         style="@style/main_bar_text_style"  
  10.         android:layout_width="wrap_content"  
  11.         android:layout_height="wrap_content"  
  12.         android:layout_centerHorizontal="true"  
  13.         android:layout_margin="8dp" />  
  14.   
  15.     <ImageButton  
  16.         android:id="@+id/calendarLeft"  
  17.         android:layout_width="wrap_content"  
  18.         android:layout_height="wrap_content"  
  19.         android:layout_alignParentLeft="true"  
  20.         android:padding="8dp"  
  21.         android:contentDescription="@null"  
  22.         android:src="@drawable/calendar_month_left"   
  23.         android:background="@null"/>  
  24.   
  25.     <ImageButton  
  26.         android:id="@+id/calendarRight"  
  27.         android:layout_width="wrap_content"  
  28.         android:layout_height="wrap_content"  
  29.         android:layout_alignParentRight="true"  
  30.         android:padding="8dp"  
  31.         android:contentDescription="@null"  
  32.         android:src="@drawable/calendar_month_right"   
  33.         android:background="@null"/>  
  34.   
  35.     <com.techrare.view.CalendarView  
  36.         android:id="@+id/calendar"  
  37.         android:layout_width="fill_parent"  
  38.         android:layout_height="wrap_content"  
  39.         android:layout_alignParentLeft="true"  
  40.         android:layout_below="@+id/calendarCenter" />  
  41. </RelativeLayout>  
        <RelativeLayout
            android:id="@+id/layout_calendar"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:visibility="visible" >

            <TextView
                android:id="@+id/calendarCenter"
                style="@style/main_bar_text_style"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_margin="8dp" />

            <ImageButton
                android:id="@+id/calendarLeft"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:padding="8dp"
                android:contentDescription="@null"
                android:src="@drawable/calendar_month_left" 
                android:background="@null"/>

            <ImageButton
                android:id="@+id/calendarRight"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:padding="8dp"
                android:contentDescription="@null"
                android:src="@drawable/calendar_month_right" 
                android:background="@null"/>

            <com.techrare.view.CalendarView
                android:id="@+id/calendar"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_below="@+id/calendarCenter" />
        </RelativeLayout>

 

 

 

  1. <style name="main_bar_text_style">  
  2.     <item name="android:textColor">@color/white</item>  
  3.     <item name="android:textStyle">bold</item>  
  4.     <item name="android:textSize">18sp</item>  
  5. </style>  
     <style name="main_bar_text_style">
         <item name="android:textColor">@color/white</item>
         <item name="android:textStyle">bold</item>
         <item name="android:textSize">18sp</item>
     </style>

 

上一月图片:

  1. 调用 calendar.clickLeftMonth();   
调用 calendar.clickLeftMonth(); 
     

 

下一月:

 

  1. 调用 calendar.clickRightMonth();   
调用 calendar.clickRightMonth(); 

 

日历控件中的一些功能(可以自己加):

 

 

  1. //获取日历控件对象  
  2. calendar = (CalendarView)findViewById(R.id.calendar);  
  3. //获取日历中年月 ya[0]为年,ya[1]为月(格式大家可以自行在日历控件中改)  
  4. String[] ya = calendar.getYearAndmonth().split("-");   
  5. //点击上一月 同样返回年月   
  6. String leftYearAndmonth = calendar.clickLeftMonth();   
  7. String[] lya = leftYearAndmonth.split("-");  
  8. //点击下一月  
  9. String rightYearAndmonth = calendar.clickRightMonth();   
  10. String[] rya = rightYearAndmonth.split("-");  
  11. //设置控件监听,可以监听到点击的每一天(大家也可以在控件中自行设定)  
  12. calendar.setOnItemClickListener(new calendarItemClickListener());  
  13. class calendarItemClickListener implements OnItemClickListener{  
  14.     @Override  
  15.     public void OnItemClick(Date date) {  
  16.         Toast.makeText(getApplicationContext(), date+"", Toast.LENGTH_SHORT).show();  
  17.     }  
  18.  }  
posted on 2015-12-23 08:46  李sir  阅读(5334)  评论(0编辑  收藏  举报