先看效果:
我也不知道图片为什么上传的这么大;
基本实现的功能:
1.当前月份显示,上下月补充空余部分
2.默认今天阴影显示,点击日期阴影显示
3.点到上下月的日期,自动跳转到上下月,并阴影显示
4.上下月切换
5.提供点击日期改变的接口
其他功能可以自己添加,上代码:
package com.sunrui.mysport.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.sunrui.mysport.listener.OnDateChangeListener;
import com.sunrui.mysport.utils.DateUtil;
/**
* Created by sunrui on 15/9/11.
* 自定义的日历
*/
public class CalendarView extends View {
/**
* 宽
*/
private float width;
/**
* 高
*/
private float height;
/**
* 单位长度
*/
private float cell;
/**
* 日期画笔
*/
private Paint date_P;
/**
* 当前的日期
*/
private String cur_Date;
/**
* 日期容器
*/
private Rect date_Bounds;
/**
* 星期的容器
*/
private Rect week_Bounds;
/**
* 月的容器
*/
private Rect moth_Bounds;
/**
* 深色画笔
*/
private Paint line_gray_p;
/**
* 星期的画笔
*/
private Paint week_p;
/**
* 星期
*/
private String week;
/**
* 当前月份的天数
*/
private int curMonth_days;
/**
* 年月日
*/
private int year, month, day;
/**
* 显示的天数
*/
private int[] dates;
/**
* 天数的标志
*/
private int[] marks;
private OnDateChangeListener onDateChangeListener;
public CalendarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public CalendarView(Context context) {
super(context);
}
public CalendarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
date_P = new Paint();
date_P.setColor(Color.BLACK);
date_P.setAntiAlias(true);
date_Bounds = new Rect();
line_gray_p = new Paint();
line_gray_p.setColor(Color.GRAY);
line_gray_p.setAntiAlias(true);
line_gray_p.setStrokeWidth(1);
week_p = new Paint();
week_p.setColor(Color.RED);
week_p.setAntiAlias(true);
week = "日一二三四五六";
week_Bounds = new Rect();
moth_Bounds = new Rect();
dates = new int[42];
marks = new int[42];
cur_Date = getCurDate();
setCurDay();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
width = 0;
height = 0;
int specSize = MeasureSpec.getSize(widthMeasureSpec);
width = getPaddingLeft() + getPaddingRight() + specSize;
cell = width / 7;
height = width + 1 + cell;
setMeasuredDimension((int) width, (int) height);
}
@Override
protected void onDraw(Canvas canvas) {
date_P.setTextSize(cell / 3);
date_P.getTextBounds(cur_Date, 0, cur_Date.length(), date_Bounds);
float left = (width - date_Bounds.width()) / 2;
float bottom = cell / 2 + date_Bounds.height() / 2;
canvas.drawText(cur_Date, left, bottom, date_P);
setDate();
String last = "上一月";
String next = "下一月";
line_gray_p.setTextSize(cell / 3);
line_gray_p.getTextBounds(last, 0, last.length(), moth_Bounds);
canvas.drawText(last, (left - moth_Bounds.width()) / 2, bottom, line_gray_p);
canvas.drawText(next, left + date_Bounds.width() + (left - moth_Bounds.width()) / 2, bottom, line_gray_p);
week_p.setTextSize(cell / 3);
week_p.getTextBounds(week, 0, 1, week_Bounds);
canvas.drawLine(0, 0, 0, height, line_gray_p);
canvas.drawLine(width - 2, 0, width - 2, height, line_gray_p);
for (int i = 0; i < 9; i++) {
if (i < 7) {
canvas.drawText(week.substring(i, i + 1), cell / 2 - week_Bounds.width() / 2 + cell * i, cell + cell / 2 + week_Bounds.height() / 2, week_p);
}
if (i > 0 && i < 7) {
canvas.drawLine(cell * i, cell * 2, cell * i, height, line_gray_p);
}
canvas.drawLine(0, cell * i, width, cell * i + 1, line_gray_p);
}
for (int i = 0; i < 42; i++) {
int step_x = i % 7;
int step_y = i / 7;
if (marks[i] == 2) {
if (dates[i] == day) {
canvas.drawRect(cell * step_x, cell * (2 + step_y), cell * step_x + cell, cell * (3 + step_y), line_gray_p);
}
canvas.drawText(dates[i] + "", cell / 2 - week_Bounds.width() / 2 + cell * step_x, cell * (2 + step_y) + cell / 2 + week_Bounds.height() / 2, date_P);
} else {
canvas.drawText(dates[i] + "", cell / 2 - week_Bounds.width() / 2 + cell * step_x, cell * (2 + step_y) + cell / 2 + week_Bounds.height() / 2, line_gray_p);
}
}
}
/**
* 判断点击的位置
*
* @return
*/
private void getTouchEvent(float x, float y) {
if (y <= cell) {
float left = (width - date_Bounds.width()) / 2;
if (x <= left) {
//点击的是上一月区域
toLastMonth();
}
float right = (width + date_Bounds.width()) / 2;
if (x >= right) {
//点击的下一个月的区域
toNextMonth();
}
} else if (y > cell * 2) {
int h = (int) (x / cell);
int v = (int) (y / cell) - 2;
int value = v * 7 + h;
day = dates[value];
if (marks[value] == 2) {
//点击的是本月的日期
postInvalidate();
} else if (marks[value] == 1) {
//点击的是上个月的日期
toLastMonth();
} else {
//点击的下个月的日期
toNextMonth();
}
}
if (onDateChangeListener != null) {
onDateChangeListener.onDateChange(year, month, day);
}
}
/**
* 跳转到下一个月
*/
private void toNextMonth() {
if (month == 12) {
month = 1;
year += 1;
} else {
month += 1;
}
cur_Date = year + "年" + month + "月";
postInvalidate();
}
/**
* 跳转到上一月
*/
private void toLastMonth() {
if (month == 1) {
month = 12;
year = year - 1;
} else {
month = month - 1;
}
cur_Date = year + "年" + month + "月";
postInvalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP) {
float x = event.getX();
float y = event.getY();
getTouchEvent(x, y);
}
return true;
}
private String getCurDate() {
year = DateUtil.getCurrentYear();
month = DateUtil.getCurrentMonth();
day = DateUtil.getCurrentDate();
return year + "年" + month + "月";
}
private void setDate() {
curMonth_days = DateUtil.getDaysByYearMonth(year, month);
int i = 0;
try {
i = DateUtil.dayForWeek(year, month, 1);
} catch (Exception e) {
e.printStackTrace();
}
int last_month;
int last_year;
if (month == 1) {
last_month = 12;
last_year = year - 1;
} else {
last_month = month - 1;
last_year = year;
}
int lastMonthDays = DateUtil.getDaysByYearMonth(last_year, last_month);
for (int m = 0; m < 42; ) {
if (i == 1) {
for (int h = 1; h <= curMonth_days; h++) {
dates[m] = h;
marks[m] = 2;
m++;
}
for (int n = 1; n <= 42; n++) {
dates[m] = n;
marks[m] = 3;
m++;
if (m >= 42) {
break;
}
}
} else {
for (int j = 1; j < i; j++) {
dates[m] = lastMonthDays + j - i + 1;
marks[m] = 1;
m++;
}
for (int k = 1; k <= curMonth_days; k++) {
dates[m] = k;
marks[m] = 2;
m++;
}
for (int n = 1; n <= 42; n++) {
dates[m] = n;
marks[m] = 3;
m++;
if (m >= 42) {
break;
}
}
}
}
}
/**
* 获取当前的日期
*/
private void setCurDay() {
day = DateUtil.getCurrentDate();
}
public void setOnDateChangeListener(OnDateChangeListener onDateChangeListener) {
this.onDateChangeListener = onDateChangeListener;
}
}
package com.sunrui.mysport.listener;
/**
* Created by sunrui on 15/9/11.
* 日期改变的监听
*/
public interface OnDateChangeListener {
void onDateChange(int year, int month, int date);
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.sunrui.mysport.ui.SportCalendarActivity">
<RelativeLayout
android:id="@+id/top"
android:layout_width="match_parent"
android:layout_height="@dimen/_96px"
android:background="@color/top_background">
<ImageView
android:id="@+id/go_home"
android:layout_width="@dimen/_96px"
android:layout_height="@dimen/_96px"
android:padding="@dimen/_20px"
android:scaleType="fitXY"
android:src="@mipmap/home" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/sport_calender"
android:textColor="@color/top_text"
android:textSize="@dimen/_48px" />
</RelativeLayout>
<com.sunrui.mysport.widget.CalendarView
android:id="@+id/calendar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/top"
android:layout_margin="@dimen/_24px" />
<TextView
android:id="@+id/date"
android:layout_width="match_parent"
android:layout_height="@dimen/_36px"
android:textColor="@color/bottom_text"
android:layout_marginLeft="@dimen/_24px"
android:layout_below="@+id/calendar"
android:textSize="@dimen/_24px" />
</RelativeLayout>
package com.sunrui.mysport.ui;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.sunrui.mysport.R;
import com.sunrui.mysport.listener.OnDateChangeListener;
import com.sunrui.mysport.utils.DateUtil;
import com.sunrui.mysport.widget.CalendarView;
/**
* 孙瑞 2015/9/11
* 运动日历
*/
public class SportCalendarActivity extends Activity implements View.OnClickListener, OnDateChangeListener {
/**
* 返回主页面
*/
private ImageView go_home;
/**
* 日历控件
*/
private CalendarView calendar;
/**
* 时间
*/
private TextView dateT;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sport_calendar);
initView();
bindingData();
}
private void bindingData() {
dateT.setText(DateUtil.getDateStr());
}
private void initView(){
go_home = (ImageView) findViewById(R.id.go_home);
go_home.setOnClickListener(this);
calendar = (CalendarView) findViewById(R.id.calendar);
calendar.setOnDateChangeListener(this);
dateT = (TextView) findViewById(R.id.date);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.go_home:
finish();
break;
default:
break;
}
}
@Override
public void onDateChange(int year, int month, int date) {
Log.v("sss", "year=" + year + ",month=" + month + ",date=" + date);
dateT.setText(year + "年" + month + "月" + date + "日");
}
}
package com.sunrui.mysport.utils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
/**
* Created by sunrui on 15/9/11.
* 日期功能类
*/
public class DateUtil {
/**
* 字符串转时间
*
* @param str
* @param format
* @return
*/
public static Date str2Date(String str, String format) {
if (str == null || str.length() == 0) {
return null;
}
if (format == null || format.length() == 0) {
format = "yyyy-MM-dd";
}
Date date = null;
try {
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
date = sdf.parse(str);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
/**
* 获取当前月份的天数
*
* @return
*/
public static int getCurrentMonthDays() {
Calendar a = Calendar.getInstance();
a.set(Calendar.DATE, 1);
a.roll(Calendar.DATE, -1);
int maxDate = a.get(Calendar.DATE);
return maxDate;
}
/**
* 根据年月获取当月天数
*
* @param year 年份
* @param month 月份
* @return
*/
public static int getDaysByYearMonth(int year, int month) {
Calendar a = Calendar.getInstance();
a.set(Calendar.YEAR, year);
a.set(Calendar.MONTH, month - 1);
a.set(Calendar.DATE, 1);
a.roll(Calendar.DATE, -1);
int maxDate = a.get(Calendar.DATE);
return maxDate;
}
/**
* 根据年月日获取星期
*
* @param year
* @param month
* @param date
* @return
* @throws Exception
*/
public static int dayForWeek(int year, int month, int date) throws Exception {
String time = year + "-" + month + "-" + date;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
Calendar c = Calendar.getInstance();
c.setTime(format.parse(time));
int day = c.get(Calendar.DAY_OF_WEEK);
return day;
}
/**
* 返回当前年份
* @return
*/
public static int getCurrentYear() {
Date date = new Date();
DateFormat format = new SimpleDateFormat("yyyy");
String time = format.format(date);
return Integer.parseInt(time);
}
/**
* 返回当前月份
* @return
*/
public static int getCurrentMonth() {
Date date = new Date();
DateFormat format = new SimpleDateFormat("MM");
String time = format.format(date);
return Integer.parseInt(time);
}
/**
* 返回当前日期
* @return
*/
public static int getCurrentDate(){
Date date = new Date();
DateFormat format = new SimpleDateFormat("dd");
String time = format.format(date);
return Integer.parseInt(time);
}
/**
* 返回当前年月日
* @return
*/
public static String getDateStr(){
return getCurrentYear() + "年" + getCurrentMonth() + "月" + getCurrentDate() + "日";
}
}