网格
最近有个需求是为课表控件TimetableView添加一个网格背景,大致整理了一下该需求的实现思路
- 自定义一个网格的View
- 将该View添加到课表的底层布局中
实现效果如下,(不得不吐槽一下这个需求真的是很鸡肋,加上网格反而难看了):
本篇博文主要介绍如何自定义底层的网格View,课表控件的实现原理可以参考一起实现一个健壮的课程表控件
网格布局
1.创建自定义View
创建的类需要继承自View
基类,如下:
public class SubjectGridView extends View {
//...
}
2.参数初始化
所谓画网格,其实就是画横线和竖线,只要找到画线的起始坐标即可。要画线,那么肯定需要一支画笔Paint
吧,布局的宽度、高度、课程项的宽度、高度、间距用来确定线条的位置,属性如下:
//画笔、线条颜色
Paint paint = new Paint();
int lineColor=Color.GRAY;
//布局的宽度、高度
float width,height;
//课程项的宽度、高度、间距
int itemHeight;
int itemWidth;
int marTop,marLeft;
在构造方法中进行参数的初始化,课程项的宽度、高度、间距采用默认值,需要转化为像素值
/**
* 使用默认的参数构造网格
* @param context
* @param attrs
*/
public SubjectGridView(Context context,AttributeSet attrs) {
super(context, attrs);
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
setLayoutParams(lp);
itemHeight=OtherUtils.dip2px(context,55);
marTop=OtherUtils.dip2px(context,3);
marLeft=OtherUtils.dip2px(context,3);
}
布局的宽度、高度在构造函数中是获取不到的,所以应该在onMeasure()
中初始化布局的宽度、高度
//计算参数
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
width=MeasureSpec.getSize(widthMeasureSpec);
height=MeasureSpec.getSize(heightMeasureSpec);
//课程项分为了15等分,第一列占一份,其余七列每列占两份
float each=width/15.0f;
itemWidth=(int)each*2;
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}
3.开始绘制
参数初始化完成后,就应该绘制网格线了,绘制过程非常简单,直接看代码吧
@Override
protected void onDraw(Canvas canvas) {
paint.setColor(lineColor);
paint.setStrokeWidth(1);
//第一条横线
canvas.drawLine(0,itemHeight+1,width,itemHeight+1,paint);
//剩余横线
for(int i=2;i<=12;i++){
float startY=itemHeight*i+(i-1)*marTop+2;
float stopY=startY;
canvas.drawLine(0,startY,width,stopY,paint);
}
//竖线
canvas.drawLine(itemWidth/2,0,itemWidth/2,height,paint);
for(int j=1;j<=8;j++){
float startX=itemWidth*j+itemWidth/2-1;
float stopX=startX;
canvas.drawLine(startX,0,stopX,height,paint);
}
}
小结
这个自定义View
不算复杂,顶多算是个自定义View中入门级的小例子了,之后的文章中将涉及到自定义属性的知识