自定义View之点 线 面以及绘制一个综合应用时钟

            本来前天应该整理的了,但是临时有任务给耽搁了,不过今天回过头来发现好多注意点都忘了,还是记录一下吧。

            canvas绘制点,绘制线,绘制各种图形,其实这个可以说是最简单的了,也没有什么具体可以讲的,方法的参数含义基本上都可以理解,这里只说一点:圆弧或者扇形是的绘制如何确定。圆弧的绘制是这样的,他是将一个矩形(之所以不是正方形是因为也可以是椭圆的一部分)的内切圆的一部分截取出来的。那问题就是矩形如何确定呢?这里举个例子:例如所需扇形的半径为100,圆心坐标为(200,200),那么所需矩形的左上角坐标就为(100,100),右下角坐标为(300,300),我想规律已经出来了,没错就是这么算的,矩形的左上角坐标x=centerX-r,y=centerY-r ,矩形右下角坐标为 x=centerX+r   y=centerY+r 。这个自己敲一下代码就看出来了。。。。其他方法,没什么好说的,自己敲一下代码就理解了,不多说了也,我把我的代码复制下来,里面也有注意的地方。

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.YELLOW);
        canvas.drawPoint(50,50,mPaint);
        //实心圆  圆心坐标x y  半径 r  画笔
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(100, 100, 80, mPaint);

        //绘制圆弧(实心)  这里注意如何确定参数中第一个矩形的坐标如何确定,(centerX-r,centerY-r,centerX+r,centerY+r)  开始的角度 -90度为我们理解的0度方向   转过的角度  是否连接圆心
         RectF oval = new RectF(0, 200, 200, 400);
//        canvas.drawArc(oval,-90,90,false,mPaint);//圆弧
        canvas.drawArc(oval, -90, 90, true, mPaint);//扇形

        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(3);
        RectF ov = new RectF(0, 350, 200, 550);
//        canvas.drawArc(ov,-90,90,true,mPaint);//扇形
        canvas.drawArc(ov, -90, 90, false, mPaint);//弧线

        //椭圆
        canvas.drawOval(0, 650, 200, 800, mPaint);
        //矩形
        Rect rect = new Rect(0, 850, 200, 1050);
        canvas.drawRect(rect, mPaint);
        //圆角矩形
        canvas.drawRoundRect(250, 10, 450, 210, 15, 15, mPaint);
        // 按照path写文字
        mPaint.setTextSize(DensityUtils.sp2px(getContext(), 16));
        mPaint.setStrokeWidth(1);
        mPaint.setStyle(Paint.Style.FILL);
        String te = "abcdefsgeg";
        Path pa = new Path();
        pa.addArc(300, 500, 900, 1000, -180, 120);
        canvas.drawTextOnPath(te, pa, 0, 0, mPaint);

        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(3);
        Path p = new Path();
        p.moveTo(500, 800);
        p.quadTo(650, 850, 450, 1150);//赛贝尔曲线
//        p.cubicTo(100,200,200,500,6200,850);//两个控制点的赛贝尔曲线  http://www.cnblogs.com/lenve/p/5865874.html
        canvas.drawPath(p, mPaint);

补充:看来确实是过了两天忘了很多东西,有两个重要的知识忘了记录了

1.绘制线,必须要说Paint中与线有关的参数,因为很重要,很重要

       //绘制线的一些设置
        mPaint.setStrokeCap(Paint.Cap.SQUARE);//Paint.Cap.BUTT  无延伸效果,是多大就多大   Paint.Cap.ROUND 延伸为圆角   Paint.Cap.SQUARE 延伸为矩形
        mPaint.setStrokeJoin(Paint.Join.ROUND);//设置连接处效果 Paint.Join.BEVEL  有倒角,为直线倒角   Paint.Join.MITER  没有倒角  Paint.Join.ROUND 圆形倒角  详见:http://blog.csdn.net/abcdef314159/article/details/51720686
        mPaint.setStrokeMiter(Paint.ANTI_ALIAS_FLAG);//设置画笔的倾斜度(不知有没有用)
        mPaint.setHinting(Paint.HINTING_OFF);//设置画笔的隐藏模式  Paint.HINTING_OFF 关闭  Paint.HINTING_ON 打开
        //TODO:特殊线需要单独研究
        mPaint.setPathEffect(new CornerPathEffect(2));//有时候我们需要点画线等特殊的线,这个可以设置连接线的形状  CornerPathEffect 两段线之间用圆角 DashPathEffect将线段虚线话   DiscretePathEffect打散path效果  其他效果详见 http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0120/2334.html
        //mPaint.setRasterizer();//设置光栅,被废弃(无需研究)
下面举例说明两个参数的含义,其他可以看看里面引用的参考文章,讲的很好

        mPaint.setStrokeCap(Paint.Cap.BUTT);//设置线的两端情况 默认为此状态即是多长就多长
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(25);
        Path path=new Path();
        path.moveTo(400,500);
        path.lineTo(600,500);
        canvas.drawPath(path,mPaint);

        mPaint.setStrokeCap(Paint.Cap.ROUND);//两端为圆角伸出
        Path path1=new Path();
        path1.moveTo(400,550);
        path1.lineTo(600,550);
        canvas.drawPath(path1,mPaint);

        mPaint.setStrokeCap(Paint.Cap.SQUARE);//两端为矩形伸出
        Path path2=new Path();
        path2.moveTo(400,600);
        path2.lineTo(600,600);
        canvas.drawPath(path2,mPaint);

        mPaint.setStrokeCap(Paint.Cap.BUTT);
        mPaint.setStrokeJoin(Paint.Join.BEVEL);//设置线与线的连接方式,此参数表示直切,还有圆角,直角,默认为直角
        Path path3=new Path();
        path3.moveTo(400,650);
        path3.lineTo(600,650);
        path3.lineTo(600,750);
        canvas.drawPath(path3,mPaint);
效果就是最后第二张图片中的几条大粗线。

2.绘制点线面,不得不说一个path函数,非常非常重要 参见:http://www.cnblogs.com/lenve/p/5865874.html

下面开始绘制一个大家都会练习的一个例子:时钟。里面有很重要的内容,最好运行一下,仔细看思路。

public class TimeView extends TextView {
    private Paint mPaint;
    private int mSecond;
    private int mMinite;
    private int mHour;

    public TimeView(Context context) {
        this(context, null);
    }

    public TimeView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TimeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        String time = getTimeShort();
        int hour = Integer.valueOf(time.substring(0, 2));
        mHour = hour % 12;
        mMinite = Integer.valueOf(time.substring(3, 5));
        mSecond = Integer.valueOf(time.substring(6, time.length()));
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    mSecond++;
                    if (mSecond == 60) {
                        mSecond = 0;
                        mMinite++;
                        if (mMinite == 60) {
                            mMinite = 0;
                            mHour++;
                            if (mHour == 12) {
                                mHour = 0;
                            }
                        }
                    }
                    invalidate();
                    break;
            }
        }
    };

    @Override
    protected void onDraw(Canvas canvas) {
        int screenX = getMeasuredWidth() / 2;
        int screenY = getMeasuredHeight() / 2;
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(3);
        mPaint.setColor(Color.GREEN);
        //绘制背景
        canvas.drawColor(Color.YELLOW);
        //绘制大圆
        canvas.drawCircle(screenX, screenY, 250, mPaint);
        //绘制表芯小圆
        mPaint.setColor(Color.GRAY);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(screenX, screenY, 18, mPaint);
        //绘制指针小圆
        mPaint.setColor(Color.GREEN);
        canvas.drawCircle(screenX, screenY, 10, mPaint);
        //绘制文字北京时间  问题:如何计算指定长度的字符所占的角度(未解决)
        mPaint.setStrokeWidth(2);
        String s = "北京时间";
        mPaint.setTextSize(DensityUtils.sp2px(getContext(), 19));
        Path textPath = new Path();
        RectF rect = new RectF(screenX - 205, screenY - 205, screenX + 205, screenY + 205);
        textPath.arcTo(rect, -111, 90, false);//这里没有做适配,所以可能运行不是在文字正上方
        canvas.drawTextOnPath(s, textPath, 0, 0, mPaint);
        //绘制刻度  这个不是很好理解:思路是这样的,首先将画布平移到圆的中心(本例子中就是屏幕中央),那么此时高中立体几何的知识就用到了,画布已经平移到屏幕中央了,那么
                 // 此时屏幕中央的坐标是多少呢?答案是(0,0),屏幕左上角的坐标是多少呢(-screenWidth/2,-screenHeight/2),为什么?想想立体几何中的知识(具体什么知识我也忘了,不过确实是)
                //然后我们绘制刻度线就要以屏幕中央为基准点,绘制。怎么绘制?很简单,画笔只负责在同一个位置画直线,然后让画布旋转,相对运动吗,这样转一圈,刻度就好了
                //现在是怎么确定直线两点坐标为题,我的思路是在正上方绘制直线,那么坐标就是多少呢?例如线长为20,圆半径为100,则坐标为(0,-100)和(0,-120).理解一下,再读读上面内容画个坐标系就懂了
         canvas.save();//保存当前画布的各种属性状态,配合canvas.restore();使用
        canvas.translate(screenX, screenY);
        for (int i = 0; i < 60; i++) {
            if (i % 5 == 0) {//长
                mPaint.setStrokeWidth(3);
                canvas.drawLine(0, -250, 0, -274, mPaint);
            } else {//短
                mPaint.setStrokeWidth(2);
                canvas.drawLine(0, -250, 0, -265, mPaint);
            }
            canvas.rotate(6);
        }
        //绘制数字(思路和绘制刻度一样)
        Rect re = new Rect();
        for (int i = 1; i < 13; i++) {
            int t = i - 1;
            if (t == 0) {
                t = 12;
            }
            mPaint.setStrokeWidth(2);
            mPaint.setTextSize(DensityUtils.sp2px(getContext(), 16));
            String num = String.valueOf(t);
            mPaint.getTextBounds(num, 0, num.length(), re);
            canvas.drawText(num, -re.width() / 2, -280, mPaint);
            canvas.rotate(30);
        }
        canvas.restore();//回复保存的画布各种属性状态,这中间做的各种改变都放弃掉
        canvas.save();
        //绘制时针
        mPaint.setStrokeWidth(7);
        canvas.translate(screenX, screenY);
        canvas.rotate((float) 30 * mHour + 30 * (float) mMinite / 60);
        canvas.drawLine(0, 20, 0, -155, mPaint);
        canvas.restore();
        //绘制分针
        canvas.save();
        mPaint.setStrokeWidth(5);
        canvas.translate(screenX, screenY);
        canvas.rotate((float) 6 * mMinite + 6 * (float) mSecond / 60);
        canvas.drawLine(0, 25, 0, -175, mPaint);
        canvas.restore();
        canvas.save();
        //绘制秒针
        canvas.translate(screenX, screenY);
        mPaint.setStrokeWidth(3);
        canvas.rotate(6 * mSecond);
        canvas.drawLine(0, 35, 0, -190, mPaint);
        canvas.restore();
        mHandler.sendEmptyMessageDelayed(0, 1000);
    }

    /**
     * 获取时间 小时:分;秒 HH:mm:ss
     *
     * @return
     */
    public static String getTimeShort() {
        SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
        Date currentTime = new Date();
        return formatter.format(currentTime);
    }

    public void onDestory() {
        mHandler.removeCallbacksAndMessages(null);
        mHandler = null;
    }
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值