zoukankan      html  css  js  c++  java
  • android 自定义日历控件

    日历控件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, "border" + 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, "border" + 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.  }  
  • 相关阅读:
    python 数据类型 基础第二天
    Python基础第一篇
    前言、入门程序、常量、变量
    win10打开移动热点让手机连接上网教程
    win10移动热点问题
    博客园快速美化
    Idea提示没有符号类错误解决
    mybatis复习01
    test
    d190305面试题01总结
  • 原文地址:https://www.cnblogs.com/lzjsky/p/5068799.html
Copyright © 2011-2022 走看看