自定义View(一)之课程表

自定义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;
        }
    }
}

今天就到这里了 (╯▔^▔)╯

想要源码的小伙伴戳这

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值