最近公司有新项目下来了,拿到美工交给我的图片以后,是这样的:
刚看到这个界面的时候,我的第一想法是想看有没有第三方控件什么,于是乎找来找去,可还是没能找类似的,主要是看到这个界面也不知道该怎么去描述功能,大致的功能就是用户可以选择一周内的时间段去预约(或者做些别的不可描述的操作),嘿嘿嘿~
玩笑归玩笑,发现没能找到和我一样的,本着尝试的心态,我决定自己去写这个功能。终于经过两天的时间,完成了这个大致类似的功能。老规矩,先来看看我实现的界面效果吧。
首先说一下这个主要的功能点,日历表上面所展示的日期段是一周内的星期一至星期天,点击左右两张图片可以切换上一周或下一周,在切换的过程中进行刷新表格中的信息,表中周一至周日下面所展示的是当前一周内的每天的日期。点击对应下面的格子可以选择预约或者其他的什么操作。
其实当我第一次做这个控件的时候准备用线性布局或相对布局搭配表格布局来一个一个的复制粘贴,但是呢,作为一枚“”懒散“”的程序员,这样做我是不能忍受的呢。这样做也不够优雅。不然到时候怎么出去装*呢,哈哈哈哈哈,好吧,我又失态了,这样不好不好。
于是我决定利用android自带的画笔Paint来完成基本表格界面的绘制。感兴趣的也可以去学习使用Paint(真的很强大呢。。。。)
闲话不多说,现在我们来看看代码:
首先是绘制下面的表格,已经一些监听代码事件都写在里面,备注也都写了。
public class CalendarTableView extends View {
private Paint paint;
private DisplayMetrics mDisplayMetrics;
//星期字体颜色 默认黑色
private int mWeekdayColor = Color.parseColor("#000000");
//未选中布局颜色 默认白色
private int mUnSelectColor = Color.parseColor("#ffffff");
//选中布局颜色 默认红色
private int mSelectColor = Color.parseColor("#FF0000");
private static final int NUM_COLUMNS = 8;
private static final int NUM_ROWS = 4;
//每一格的宽度和高度
private int mColumnSize, mRowSize;
//用户选中的行和列数
private int checkRow, checkColumn;
//控件的总宽度和总高度
private int width, height;
private String[] weekString = new String[]{ "一", "二", "三", "四", "五", "六", "日"};
private List dateList = new ArrayList<>();
private String[] timeString = new String[]{ "上午", "下午", "晚上"};
public CalendarTableView(Context context, AttributeSet attrs) {
super(context, attrs);
mDisplayMetrics = getResources().getDisplayMetrics();
paint = new Paint();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.AT_MOST) {
heightSize = mDisplayMetrics.densityDpi * 30;
}
if (widthMode == MeasureSpec.AT_MOST) {
widthSize = mDisplayMetrics.densityDpi * 300;
}
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onDraw(Canvas canvas) {
initSize();
//设置监测当前行数
int row = 1;
//行
for (int j = 0; j < NUM_ROWS; j++) {
//进行画线
paint.setColor(Color.parseColor("#EDEDED"));
paint.setStrokeWidth(4);
canvas.drawLine(0, mRowSize * j, width, mRowSize * j, paint);
//因为第一行有些特殊,单独拿出来绘制第一行
if (j == 0) {
//绘制列
for (int i = 0; i < NUM_COLUMNS; i++) {
//进行画格子左边的竖线
paint.setColor(Color.parseColor("#EDEDED"));
paint.setStrokeWidth(4);
canvas.drawLine(mColumnSize * i, 0, mColumnSize * i, mRowSize, paint);
paint.setColor(Color.parseColor("#f5f5f5"));
//绘制背景色矩形
int startRecX = mColumnSize * i;
int startRecY = 0;
int endRecX = startRecX + mColumnSize;
int endRecY = mRowSize;
canvas.drawRect(startRecX, startRecY, endRecX, endRecY, paint);
//第一格不设置任何信息
if (i != 0) {
String text = weekString[i-1];
int fontWidth = (int) paint.measureText(text);
//设置文字居中
int startX = mColumnSize * i + (mColumnSize - fontWidth) / 2;
int startY = mRowSize / 2;
//设置星期
paint.setColor(mWeekdayColor);
paint.setTextSize(40);
canvas.drawText(text, startX, startY, paint);
//设置底部日期
paint.setTextSize(35);
paint.setColor(Color.parseColor("#6f6f6f"));
int date = dateList.get(i-1);
//获取文字宽度
fontWidth = (int) paint.measureText(date+"");
//设置文字居中
startX = mColumnSize * i + (mColumnSize - fontWidth) / 2;
canvas.drawText(date+"", startX, startY + mRowSize / 3, paint);
}
}
} else {
//绘制其他行
//绘制列
for (int i = 0; i < NUM_COLUMNS; i++) {
//进行画格子左边的竖线
paint.setColor(Color.parseColor("#EDEDED"));
paint.setStrokeWidth(4);
canvas.drawLine(mColumnSize * i, mRowSize * (row - 1), mColumnSize * i, mRowSize * row, paint);
if (checkRow != 0 && checkColumn != 0 && j == checkRow && i == checkColumn) {
paint.setColor(Color.parseColor("#FF0000"));
//绘制背景色矩形
int startRecX = mColumnSize * i;
int startRecY = mRowSize * (row - 1);
int endRecX = startRecX + mColumnSize;
int endRecY = startRecY + mRowSize;
//选中之后绘制文字
canvas.drawRect(startRecX, startRecY, endRecX, endRecY, paint);
paint.setTextSize(40);
paint.setColor(Color.parseColor("#FFFFFF"));
canvas.drawText("预约", (endRecX - startRecX) / 5 + startRecX, (endRecY - startRecY) / 2 + startRecY + 13, paint);
} else {
paint.setColor(mUnSelectColor);
//绘制背景色白色矩形
int startRecX = mColumnSize * i;
int startRecY = mRowSize * (row - 1);
int endRecX = startRecX + mColumnSize;
int endRecY = startRecY + mRowSize;
canvas.drawRect(startRecX, startRecY, endRecX, endRecY, paint);
}
}
paint.setTextSize(40);
paint.setColor(mWeekdayColor);
String text = timeString[j-1];
int fontWidth = (int) paint.measureText(text);
//设置文字居中
int startX = (mColumnSize - fontWidth) / 2;
int startY = (int) (mRowSize / 2 - (paint.ascent() + paint.descent()) / 2);
canvas.drawText(text, startX, startY + mRowSize * j, paint);
}
//绘制完一行之后行数加1
row++;
}
//进行画边界线
paint.setColor(Color.parseColor("#44cdc3"));
paint.setStrokeWidth(4);
canvas.drawLine(0, 0, width, 0, paint);
canvas.drawLine(0, 0, 0, height, paint);
canvas.drawLine(width, 0, width, height, paint);
canvas.drawLine(0, height, width, height, paint);
}
/**
* 初始化列宽行高
*/
private void initSize() {
width = getWidth();
height = getHeight();
mColumnSize = width / NUM_COLUMNS;
mRowSize = height / NUM_ROWS;
}
//将日期列表传递过来
public void setDateList(List dateList){
this.dateList = dateList;
//通知刷新
invalidate();
}
//用来获取用户点击屏幕的坐标
private int downX = 0, downY = 0;
@Override
public boolean onTouchEvent(MotionEvent event) {
int eventCode = event.getAction();
switch (eventCode) {
case MotionEvent.ACTION_DOWN:
downX = (int) event.getX();
downY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
int upX = (int) event.getX();
int upY = (int) event.getY();
if (Math.abs(upX - downX) < 10 && Math.abs(upY - downY) < 10) {//点击事件
performClick();
doClickAction((upX + downX) / 2, (upY + downY) / 2);
}
break;
}
return true;
}
/**
* 执行点击事件
*
* @param x
* @param y
*/
private void doClickAction(int x, int y) {
int row = y / mRowSize;
int column = x / mColumnSize;
if (row != 0 && column != 0) {
//保存用户选中的item
setCheckedItem(row, column);
}
invalidate();
}
private void setCheckedItem(int checkRow, int checkColumn) {
this.checkRow = checkRow;
this.checkColumn = checkColumn;
}
}
绘制好表格之后,就将上面的布局用xml进行封装,接下来是整体控件的代码,里面也做了一些计算时间的操作,备注都有。
/**
* 简易的日历时间表
* Created by Administrator on 2016/11/7.
*/
public class SimpleCalendarView extends RelativeLayout {
private Context mContext;
private String mondayDate, sundayDate;
private TextView currentDateTv;
private ImageView leftImg, rightImg;
private SimpleDateFormat df;
//用户点击次数 初始为0
private int operateNums;
private Calendar mCalendar;
private CalendarTableView calendarView;
public SimpleCalendarView(Context context) {
super(context);
this.mContext = context;
init();
}
private void init() {
View simpleCalendar = LayoutInflater.from(mContext).inflate(R.layout.simple_calendar_view,this);
calendarView = (CalendarTableView) simpleCalendar.findViewById(R.id.main_simple_view);
currentDateTv = (TextView) simpleCalendar.findViewById(R.id.current_time_tv);
leftImg = (ImageView) simpleCalendar.findViewById(R.id.time_left_img);
rightImg = (ImageView) simpleCalendar.findViewById(R.id.time_right_img);
df = new SimpleDateFormat("yyyy-MM-dd");
operateDates();
leftImg.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
operateNums --;
operateDates();
}
});
rightImg.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
operateNums ++;
operateDates();
}
});
}
//计算当前一周日期并显示在界面
private void operateDates() {
mCalendar = Calendar.getInstance();
mCalendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
mCalendar.add(Calendar.WEEK_OF_YEAR, operateNums);
//本周的星期一的日期
mondayDate = df.format(mCalendar.getTime());
//本周的周末的日期
mCalendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
//增加一个星期,才是我们中国人理解的本周日的日期
mCalendar.add(Calendar.WEEK_OF_YEAR, 1);
//本周周日日期
sundayDate = df.format(mCalendar.getTime());
currentDateTv.setText(mondayDate + " - " + sundayDate);
try {
Date date = df.parse(mondayDate);
calendarView.setDateList(dateToWeek(date));
} catch (ParseException e) {
e.printStackTrace();
}
}
/**
* 根据日期获得所在周的日期列表
*
* @param mDate
* @return
*/
@SuppressWarnings("deprecation")
public static List dateToWeek(Date mDate) {
int b = mDate.getDay();
Date fDate;
List list = new ArrayList<>();
Long fTime = mDate.getTime() - b * 24 * 3600000;
for (int i = 0; i < 7; i++) {
fDate = new Date();
fDate.setTime(fTime + ((i + 1) * 24 * 3600000)); //一周从周日开始算
int dates = fDate.getDate();
list.add(dates);
}
return list;
}
}
这个控件的布局代码也很简单,由于没有左右的图片,先用小安卓来替代,后面替换即可。
以上这些代码就是整体的封装,最后就是使用它了。只需要用一个线性布局将实例化的日历控件add进去即可。
由于时间紧迫,目前未将表格的记录事件刷新功能完成,等后期有时间了再来完善吧。
如果你在使用的过程中有问题也可以留言和我交流~