首页   

Android Study之自定义View进阶路:掌握绘制基本图形(一)

程序员大咖  · 程序员  · 6 年前

点击上方“程序员大咖”,选择“置顶公众号”

关键时刻,第一时间送达!

         LZ-Says:我觉得人与人相处,首先排在首位的是诚信,其次才是一些其他的东西。而关于技术,交流才是成长的路,闭门造车永远看不到外面的精彩,领悟不到自身新高度。So,诚信待人,多交流,多沟通,一起成长~!


前言

        开发过程以及平时使用过程中,总是能看到炫之又炫的效果,以前一直都是展首相望,一直都不敢触碰,But,今天,我们从基础开始,一步一步征服自定义View。

        在此,装个小B,希望大家和我一样掌握之后都可以如下这么豪气~ ^.^


本文目标

        通过讲解并举例说明绘制基本图形方法技巧,get自定义View基础招式,更6,更自信的玩转自定义View。


自定义View缘由

        总说自定义View,自定义View,我为什么要自定义View,系统自带的不行吗?下面我们简单的举例说明下。

    > Boss Say:XXX,这个字给我闪动起来~ 
    > You:好~(心里默默Fuck...)

        如上很简单,却又很实际的一个场景,一般来说我们显示直接TextView加载显示内容即可,但是现在要闪动起来,那么这个时候怎么办呢?系统也没有提供相应的案例。

只能自定义了呗。

        So,下次有人再问你为什么要自定义View,你可以这样告诉他:

    > 当系统自带控件已经无法满足我们实际需求,这时候,就需要自定义View去实现了。


回顾常用控件

        对于一名Android开发者,想必已经玩转基本同时也是常用控件的使用了吧,But,大家有没有想到它们的内部是如何实现的?或者简单说,他们都是继承谁呢?

简单为大家附上几个例子:

  • public class TextView extends View

  • public class Button extends TextView

  • public class CheckBox extends CompoundButton

  • public abstract class CompoundButton extends Button

  • public class RelativeLayout extends ViewGroup

  • public abstract class ViewGroup extends View

  • public class LinearLayout extends ViewGroup

         等等诸如此类有很多,这里就不一一说明了,大家仔细观察,看看有什么相似点。而我们自定义View,又该继承What?

        LZ简单概括下~


自定义View继承父类及简述

  • 继承常用控件,在原有基础上进行升级改造;

  • 继承View;

  • 继承ViewGroup;

  • 组合控件。

        下面分别举例说明以上使用场景。


1.继承常用控件,升级或改造

        比如之前ScrollView嵌入ListView或者GirdView常常会出现显示不全,我们有n种解决办法,其中有一种便是继承ListView或者GirdView重写即可解决,下面贴出关键代码:

    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        
       int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,                MeasureSpec.AT_MOST);        
       super.onMeasure(widthMeasureSpec, expandSpec);    }

        这种方式的好处不用说也知道,方便,快捷。


2.继承View或者ViewGroup区别

        大家都知道,ViewGroup是View的子类,那么继承它们有什么区别呢?

  • View,从字面上来看,就是显示视图,比如我画个圆,画个矩形,我操作仅仅是显示,那么我们果断继承View即可;

  • ViewGroup,同样从字面上来看,Group群组,它里面允许放置一些子视图,主要也是用户自定义一些布局什么的,可以考虑继承ViewGroup。

3.组合控件

        关于这个可以考虑查看LZ之前写的如下一篇文章,地址如下:

    > Android Study 之分分钟让你玩转EditText右下角实时显示输入字数


        先上个效果图:

        组合控件,个人感觉优势在于比继承系统提供控件方便,开发起来也就是基于已有控件,难点或者说是复杂处也就是自己的逻辑。


View绘制流程

        下方高能,附上一张流程图,简单了解下,进入我们撸码阶段。

        以上流程图重点关注onDraw()以及onMeasure()即可。下面简单说明下:

  • onDraw:鉴名其意,就是绘制,绘制的统统在这里,秒懂?

  • onMeasure:这个可以简单理解为绘制的区域大小,就好比你指定一个控件宽高一样。

        PS:LZ可是一枚有着良好职业道德,职业操守以及职业素养的Android开发者。


基本图形绘制

    > 先定一个能达到的小目标
    > 比如说我先玩转绘制基本图形~


一、绘制圆

撸码前,明确下操作流程:

  • 继承View,实现构造,添加初始化画笔方法;

  • 实现onDraw()方法

        没错,就这俩点,具体撸码瞧着~


1.继承View,实现构造函数

public class CircleView extends View {    
   /**     * 实例化时调用     * @param context     */    public CircleView(Context context) {        
       super(context);    }    
   /**     * 设置属性时调用     * @param context     * @param attrs 属性集合     */    public CircleView(Context context, @Nullable AttributeSet attrs) {        
       super(context, attrs);    }    
   /**     * 设置样式时调用     * @param context     * @param attrs     * @param defStyleAttr 样式     */    public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        
       super(context, attrs, defStyleAttr);    }    }


2.改造构造,为了更好,更方便的调用,并且新增初始化画笔方法

    public CircleView(Context context) {        
       this(context, null);    }    
   public CircleView(Context context, @Nullable AttributeSet attrs) {        
       this(context, attrs, 0);    }    
   public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        
       super(context, attrs, defStyleAttr);        initPaint();    }

        这里可能有人就会说了,这个和那个有什么区别,区别也不是很大嘛。

        其实都差不多,改造的原因就是调用其中一个构造的同时也能调用其它,相对来说提供一些方便而已。

        下面将采取方法说明+代码实现+效果方式进行讲解。


1. 万能Paint

        Paint:画笔 功能强大 可设置颜色 样式等等

        初始化如下:

        // 实例化画笔        paint = new Paint();        
       // 设置画笔颜色        paint.setColor(Color.RED);


2. drawCircle()绘制圆

参数说明:

    > drawCircle(float cx, float cy, float radius, Paint paint)
    > * cx,cy:圆心x,y轴距离;
    > * radius:圆半径;
    > * paint:画笔

        调用如下:

canvas.drawCircle(0, 0, 100, paint);

        效果如下:

        这时候,有人会说了,圆呢?让你糟了?画丢了?表急,这里为大家引入一个坐标系的概念。


3. 坐标系

        如上图,以屏幕左上角为中心点,也就是x,y轴值为(0,0)点。So,秒懂?下面我们指定x,y轴坐标,来看看一个完整的圆~


4. 绘制红色完整圆

        指定x,y轴为300,如下:

canvas.drawCircle(300, 300, 100, paint);

        效果如下:

        在这里不得不提一句,关于绘制出现锯齿情况,如下小篇幅。


5. setAntiAlias()锯齿以及抗锯齿

        关于这个效果,LZ找了一个看的比较明显的图,如下:

        同样本部分也摘于凯哥的HenCoder,下面附上地址,方便大家学习了解。

    > http://hencoder.com/ui-1-1/


        关于这块,LZ学习了下凯哥的文章,简单的从里面截取一些内容,如下:

    > 实质上,锯齿现象的发生,只是由于图形分辨率过低,导致人眼察觉出了画面中的像素颗粒而已;而抗锯齿的原理是:修改图形边缘处的像素颜色,从而让图形在肉眼看来具有更加平滑的感觉


        下面再次盗取凯哥一张图,如下:

        开启抗锯齿(开启后会消耗部分系统性能,可忽略不计):

    > paint.setAntiAlias(true);

        So,清晰明了,接着往下瞅~到现在,我们已经掌握如何画一个简单的圆,对应的坐标系以及锯齿的简单知识,而下面,我们通过一些简单的方法去实现简单的效果,先达到一个初步了解的目的。


6. setStyle设置样式

参数说明:

    > setStyle(Paint.Style style)中style有三个取值,分别如下:
    > * FILL:填充内部,默认此效果;

    > * FILL_AND_STROKE:填充内部并描边,如下效果图,是不是觉得和默认的时候一样呢?视觉效果是一样,但是中间的流程却大不一样,简单来说,Fill仅仅是填充内容即可,而此属性值却在填充的基础增加了描边;

    > * STROKE:描边,只绘制边缘部分,中间内容不绘制,也就是我们说的空心圆。


        调用起来也是很easy,如下:

paint.setStyle(Paint.Style.FILL_AND_STROKE);


7. setStrokeWidth设置描边宽度

        参数说明:

    > setStrokeWidth(float width),数值越大,描边越宽


        简单调用如下:

paint.setStrokeWidth(30);


8. drawOval()绘制椭圆

    > drawOval(),拥有俩种参数方式,如下:
    > * drawOval(float left, float top, float right, float bottom, Paint paint)
    > 参数含义分别为:左上右下坐标以及画笔
    > * drawOval(RectF oval, Paint paint)
    > 参数含义为左上右下点集合(封装类)以及画笔

        下面附上简单使用方式:

        // 绘制椭圆        rectF=new RectF();        rectF.left=100;        rectF.top=600;        rectF.right=400;        rectF.bottom=800;        canvas.drawOval(rectF,paint);

      

        效果如下:

        到此,圆的绘制暂时告一段落,下面开启矩形绘制,其实都差不多,不信瞧着~


二、绘制矩形

1. drawRect()绘制矩形:

    > drawRect()绘制矩形,提供了三种方式,分别如下:
    > * drawRect(float left, float top, float right, float bottom, Paint paint)
    > left,top,right,bottom:左上右下点;
    > paint:画笔。
    > * drawRect(Rect r, Paint paint)
    > r:左上右下点集合;
    > paint:画笔。
    > * drawRect(RectF rect, Paint paint)
    > rect:左上右下点集合;
    > paint:画笔。


        下面依次附上调用以及效果:

        // 三种方式画矩形        paint.setColor(Color.RED);        
       // 左上右下        canvas.drawRect(20, 20, 300, 300, paint);        paint.setColor(Color.BLUE);        rect = new Rect(320, 20, 600, 300);        canvas.drawRect(rect, paint);        paint.setColor(Color.BLACK);        rectF = new RectF();        rectF.left = 620;        rectF.top = 20;        rectF.right = 900;        rectF.bottom = 300;        canvas.drawRect(rectF, paint);

        

        效果如下:


2. 设置空心以及描边宽度

        方式和绘制圆一样,这里直接贴关键代码了。

       // 设置矩形空心        strokePaint.setColor(Color.RED);        strokePaint.setStyle(Paint.Style.STROKE);        canvas.drawRect(20, 320, 300, 600, strokePaint);        
       // 设置矩形描边宽度        strokeWPaint.setColor(Color.RED);        strokeWPaint.setStyle(Paint.Style.STROKE);        strokeWPaint.setStrokeWidth(20);        canvas.drawRect(20, 620, 300, 900, strokeWPaint);

        

        效果如下:


3. drawRoundRect()绘制圆角矩形

        感觉这个更简单了,So easy了,还是老规矩,提下方法参数:

    > drawRoundRect():同样提供了俩种方式,但是原理都是一样,如下:
    > * drawRoundRect(RectF rect, float rx, float ry, Paint paint)
    > rect:左上右下点集合;
    > rx:x轴方向边缘弧度;
    > ry:y轴方向边缘弧度;
    > paint:画笔。
    > * drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)
    > 和上面基本一致,只不过点集合变成了一个个具体点了。

        

        贴代码呗:

        // 绘制圆角矩形        roundPaint.setColor(Color.BLUE);        roundPaint.setStyle(Paint.Style.STROKE);        roundPaint.setStrokeWidth(2);        canvas.drawRoundRect(320, 320, 600, 600, 50, 50, roundPaint);        
       // 绘制圆角矩形        roundPaint.setColor(Color.BLUE);        roundPaint.setStyle(Paint.Style.STROKE);        roundPaint.setStrokeWidth(2);        canvas.drawRoundRect(320, 620, 600, 900, 50, 20, roundPaint);

        来个效果瞅瞅~

        OK~


三、绘制点 线 弧线 扇形

1. drawLine()绘制线

绘制单条线:

    > drawLine(float startX, float startY, float stopX, float stopY, Paint paint): 
    > * startX:起始点x轴坐标;
    > * startY:起始点y轴坐标;
    > * stopX:结束点x轴坐标;
    > * stopY:结束点y轴坐标;
    > * paint:画笔


绘制多条线:

    > drawLines(float[] pts, Paint paint):
    > * pts:坐标集合,每组包含4个坐标点,分别为起始点x轴坐标,起始点y轴坐标,结束点x轴坐标和结束点y轴坐标;
    > * paint:画笔


指定绘制点集合:

    > drawLines(float[] pts, int offset, int count, Paint paint):
    > * pts:绘制坐标点集合;
    > * offset:指定哪儿些点不需要绘制;
    > * count:实际需要绘制的点;
    > * paint:画笔


        下面依次贴出部分代码,首先绘制一条线:

        // 画单条线        canvas.drawLine(100, 50, 500, 50, paint);

        效果:

        绘制一个字母,^_^

    // 多个坐标集合 一组四个坐标 分别为起始x轴,起始y轴,结束x轴,结束y轴    private float[] pts = {            
           100, 200, 100, 600,            
           100, 400, 300, 400,            
           300, 200, 300, 600};                // 绘制几条线    canvas.drawLines(pts, paint);


        瞅瞅效果?

        绘制指定点,这里直接绘制所有点:

    private float[] pts1 = {            
           400, 100, 400, 200,            
           400,100,600,100,            
           400,200,600,200};                // 参数说明    // pts:绘制直线的端点数组,每条直线占用4个数据。    // offset:跳过的数据个数,这些数据将不参与绘制过程。    // count:实际参与绘制的数据个数。    // paint:绘制直线所使用的画笔。    canvas.drawLines(pts1,0,12,paint);

       

         效果如下:


2. drawArc()绘制扇形 弧形

同样提供俩种方式:

    > drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint):
    > * oval:点坐标集合,指定圆弧的外轮廓矩形区域;
    > * startAngle:起始角度;
    > * sweepAngle:经过的角度,顺时针方向,从右中间开始为零度;
    > * useCenter:如果为True时,绘制圆弧时将圆心包括在内,通常用来绘制扇形,反之则是弧形;
    > * paint:画笔。
    > drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
    > 同样,只是点坐标集合变成了单个

        // 绘制弧线 false为弧线 true为扇形        rectF=new RectF();        rectF.left=20;        rectF.top=600;        rectF.right=220;        rectF.bottom=800;        paint.setStyle(Paint.Style.STROKE);        canvas.drawArc(rectF,0,90,false,paint);        rectF=new RectF();        rectF.left=20;        rectF.top=800;        rectF.right=220;        rectF.bottom=1000;        paint.setStyle(Paint.Style.STROKE);        canvas.drawArc(rectF,0,90,true,paint);

       

        展示下效果:


3. 绘制点

        这个最是Easy,就直接贴代码了,具体大家可以自己看看源码:

        // 绘制点        canvas.drawPoint(600,500,paint);

        如下效果:


四、绘制文字

        这个感觉So Easy,就直接贴出部分源码以及效果了。

        // 设置文本大小        paint.setTextSize(50);        
       // 绘制文字        canvas.drawText("Hello Custom View",100,100,paint);        
       // 绘制指定长度文本        canvas.drawText("Hello,妹子,你好~",6,11,100,200,paint);


GitHub查看地址

https://github.com/HLQ-Struggle/AndroidCustomView


个人感触

         其实我觉得我们应该去感恩,感恩无私奉献的Android团队,感谢开源的Android伙伴,我们真的是站在巨人的肩膀上去看世界,所以我们有什么理由和借口不去努力?不去为了Android越来越好而做出自己的微小贡献呢?


结束

        可能有的人会说了,这些东西很简单,直接一个类放上去不就好了,何必这么麻烦?

        确实,这样做是我省事儿了,但是从不会到会是一个过程,虽然这样写的很麻烦,但是我感觉像和LZ一样的想学习的Android小伙伴会看的清晰明了,So,我麻烦点就麻烦点吧。

        感谢大家查阅,不足之处欢迎提出,随时修改,完善~



  • 来自:http://www.apkbus.com/blog-904057-68729.html

  • Android编程精选整理发布,转载请联系作者获得授权

【点击成为安卓大神】

推荐文章
TeacherGwen  ·  我们一起神翻译|9.28  ·  1 年前  
ShanghaiLOOK  ·  每日壁纸分享 No.103:天桥路灯  ·  1 年前  
© 2022 51好读
删除内容请联系邮箱 2879853325@qq.com