自定义View(一)之课程表
课程表大家可是从小用到大了,想不想搞个手机版的玩玩呢,那就跟我来吧,废话不说,先上图
开始写代码之前你还要注意几个问题
1. 你需要一个算法通过当前时间算出这一周的日期,用于填充时间栏
2. 你需要设计一个数据结构用来存储和传递数据(如果你真的准备拿出来用的话)
3. 将数据写入课程表中时候要计算字符串的长度,如果长度大于了课表单元的宽度那就要写到下一行去
日期算法
private List<Date> dateToWeek(Date mDate)
{
int b = mDate.getDay();
Date fDate;
List<Date> list = new ArrayList();
Long fTime = mDate.getTime() - b * 24 * 3600000;
for (int a = 0; a < 8; a++)
{
fDate = new Date();
fDate.setTime(fTime + (a * 24 * 3600000));
Calendar calendar = new GregorianCalendar();
calendar.setTime(fDate);
calendar.add(calendar.DATE, 1);// 把日期往后增加一天.整数往后推,负数往前移动
fDate = calendar.getTime(); // 这个时间就是日期往后推一天的结果
list.add(a, fDate);
}
return list;
}
写入数据的方法
这里使用了paint的mearsureText方法来计算字符串的长度与我们的课表的一个单元的宽进行比较
private void drawText(Canvas canvas, String s, float x, float y, float width, Paint paint)
{
StringBuffer buffer = new StringBuffer();
char c;
for (int i = 0; i < s.length(); i++)
{
//一行写不下了,就输出
if(paint.measureText(buffer.toString())+30 > width)
{
canvas.drawText(buffer.toString(), x, y, paint);
y+=30;
buffer.setLength(0);
}
//一行能写下,就再加字符
c = s.charAt(i);
buffer.append(c);
}
canvas.drawText(buffer.toString(), x, y, paint);
}
在构造方法中初始化一些数据
public TimeTableView(Context context, AttributeSet attrs)
{
super(context, attrs);
imagePaint = new Paint();
//画矩形标题的笔
titlePaint = new Paint();
titlePaint.setColor(Color.argb(127, 164, 159, 155));
//画分割线的笔
linePaint = new Paint();
linePaint.setColor(Color.argb(127, 95, 87, 84));
//得到当前一周的日期
dates = dateToWeek(new Date());
}
onMearsure
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//测量view的宽高
winWidth = measureWidth(widthMeasureSpec);
winHeight = measureHeight(heightMeasureSpec);
setMeasuredDimension(winWidth, winHeight);
widthSize = (winWidth - NUM_SIZE) / 7;
heightSize = winHeight / 12;
Log.i("main", "winWidth:"+winWidth+", winHeight:"+winHeight);
//字体大小
textSize = winWidth/36;
//用于画文字的笔
textPaint = new Paint();
textPaint.setColor(Color.argb(255, 255, 255, 255));
textPaint.setTextSize(textSize);
textPaint.setTextAlign(Paint.Align.CENTER);
}
测量方法。(高的测量方法与宽几乎一致,我就不重复了)
private int measureWidth(int measureSpc)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpc);
int specSize = MeasureSpec.getSize(measureSpc);
//如果给的是精确值(具体数值或者match_parent)
if (specMode == MeasureSpec.EXACTLY)
{
result = specSize;
}
else
{
//不是精确值的话就先给一个初始值
result = 300;
//如果是wrap_content的话,就让他为不超过最大值的一个默认值
if (specMode == MeasureSpec.AT_MOST)
{
result = Math.min(result, specSize);
}
}
return result;
}
onDraw
@Override
protected void onDraw(Canvas canvas)
{
Paint paint = new Paint();
//背景图画
canvas.drawBitmap(Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(),
R.drawable.pic9), winWidth, winHeight, true), 0, 0, new Paint());
//绘制月份
canvas.drawText(new Date().getMonth()+1 + "月", NUM_SIZE / 2, heightSize - 60, textPaint);
//初始化日期
for (int i = 0; i < 7; i++)
{
//画首行格子
RectF rectF = new RectF((NUM_SIZE + widthSize * i),
0,
(NUM_SIZE + widthSize * (i + 1)),
heightSize);
canvas.drawRect(rectF, titlePaint);
//第一行的分割线
canvas.drawLine((NUM_SIZE + widthSize * i),
0,
(NUM_SIZE + widthSize * i),
heightSize,
linePaint);
//第一行的日期
canvas.drawText(dates.get(i).getDate() + "",
(NUM_SIZE + widthSize / 2) + widthSize * i,
heightSize / 3,
textPaint);
canvas.drawText(Translate.translateDateToChinese(i + 1),
(NUM_SIZE + widthSize / 2) + widthSize * i,
(heightSize / 3) * 2,
textPaint);
}
//初始化序号
for (int i = 0; i < 12; i++)
{
//画首列格子
RectF rectF = new RectF(0, heightSize * i, NUM_SIZE, heightSize * (i + 1));
canvas.drawRect(rectF, titlePaint);
//第一列的分割线
canvas.drawLine(0, heightSize * i, NUM_SIZE, heightSize * i, linePaint);
if (i > 0)
{
//第一列的序号
canvas.drawText(i + "", NUM_SIZE / 2, (heightSize * i) + heightSize / 2, textPaint);
}
}
//初始化具体数据
if(times != null)
{
for (int i = 0; i < times.size(); i++)
{
TimeBean bean = times.get(i);
int num = bean.getTo()-bean.getFrom();
//画圆角矩形
imagePaint.setColor(bean.getType().getColor());
RectF rectF = new RectF((bean.getWeek()-1)*widthSize+NUM_SIZE, bean.getFrom()*heightSize,
bean.getWeek()*widthSize+NUM_SIZE, (bean.getTo()+1)*heightSize);
canvas.drawRoundRect(rectF, 20, 20, imagePaint);
//写字
drawText(canvas, bean.getType().getType()+":"+bean.getRemark(),
(bean.getWeek()-1)*widthSize+widthSize/2+NUM_SIZE,
bean.getFrom()*heightSize+(num+1)*heightSize/2, widthSize, textPaint);
}
}
}
提供一个方法给外界传入数据
public void setData(List<TimeBean> times)
{
this.times = times;
invalidate();
}
这是我的数据结构:
也没想过要拿出来用就随便写写了╮(╯▽╰)╭
public class TimeBean
{
private TimeType type;
private int week;
private int from;
private int to;
private String remark;
public TimeBean(TimeType type, int week, int from, int to, String remark)
{
this.type = type;
this.week = week;
this.from = from;
this.to = to;
this.remark = remark;
}
public TimeType getType()
{
return type;
}
public void setType(TimeType type)
{
this.type = type;
}
public String getRemark()
{
return remark;
}
public void setRemark(String remark)
{
this.remark = remark;
}
public int getWeek()
{
return week;
}
public void setWeek(int week)
{
this.week = week;
}
public int getFrom()
{
return from;
}
public void setFrom(int from)
{
this.from = from;
}
public int getTo()
{
return to;
}
public void setTo(int to)
{
this.to = to;
}
public enum TimeType
{
CLASS("上课", Color.argb(127, 255, 0, 0)), ACTIVITY("体育活动", Color.argb(127, 255, 255, 0)),
COMMUNITY("社团活动", Color.argb(127, 255, 153, 0)), SLEEP("睡觉", Color.argb(127, 0, 255, 0)),
OTHER("其他", Color.argb(127, 0, 0, 0));
private String type;
private int color;
TimeType(String type, int color)
{
this.type = type;
this.color = color;
}
public String getType()
{
return type;
}
public int getColor()
{
return color;
}
}
}