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

来源:互联网 发布:知乎 经典 编辑:程序博客网 时间:2024/06/06 02:06

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

            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