自定义View(1)

------ 关于View,ViewGroup的测量和绘制流程

   

   在Android当中,自定义控件属于比较高级的知识体系,今天我们就一起研究研究关于自定义View的那点事,看看它到底高深在什么地方。使用自定义View可以实现不同的效果,比原生控件更加的灵活,当然难度也是大大的加大了,但是不要怕,我们一起慢慢学习,看透他,也就那么点事。好了,不废话了进入我们的正题吧!

   
   Android自定义控件的意思就是说我们把我们想要绘制的View显示在屏幕上,并且可以使他有某种功能,这就是一个大体的自定义View的意思。为什么会存在自定义控件呢!当然就是因为人们嫌弃Goolge出的原生控件太丑了,或者功能不能满足人们的需求,所以自定义View才出现了。

    

   那么如何来实现我们自定义控件呢,我们先什么都不要考虑,先让他能显示出来再说吧。要显示怎么做呢,我们会涉及到View的测量以及绘制,Andorid系统会先对控件(不管是原生的还是自定义的)进行一个测量,现在想想我们在XML里面写宽高属性的时候“wrap_content“不是一个具体的值,所以我们的需要一个具体的值,这个工作就是Android完成的,当他完成以后,他就会进行绘制,(这里先不考虑ViewGroup的测量和绘制,后面会仔细讲),关于想把View画出来,大体的流程就是这样子的。

    下面我们看看我们如何对View进行测量,

   

    如果我们要对View进行测量,我们只需要实现onMeasure()方法,在这个方法里面我们就可以对我们要测量的值进行测量,然后把我们要测量的值传给系统即可(就是调用父类的这个方法),掌握这一个方法还不太够,所以我们还需要一个帮助类——MeasureSpec类,它可以帮助我们来测量我们的View,MeasureSpec其实是一个32int的值,最高的两位用来表示测量模式,后面的全部都表示测量的精确值,它是通过位运算来算出我们控件的大小值得,(使用位运算就是为了快速的提高效率)下面我们研究研究一下MeasureSpec的测量模式都有哪些。

      

      EXACTLY(精确模式):看他的名字,我相信各位猿猿都知道是什么意思了,就是具体的数值,在我们指定宽高的时候使用具体的数值,"32dp"之类的,但是,在这里友情提示一句,还有"match_parent"(占据父亲View)也是使用这种测量模式的。

      

      AT_MOST(最大值模式):就是当我们宽高指定为"warp_content"的时候,系统是使用这种测量模式的,控件的大小一般随控件内容的变化而变化,现在的要求是就是只要不超过父亲空间的允许的最大值就OK!

      

      UNSPECIFIED(随意模式):心有多大,梦想就会有多大,这句话送给大家,慢慢体会

    看完测量模式我给大家友情提示一句:

      

      View默认的测量模式是EXACTLY模式,所以我们如果不重写onMeasure()方法,你的精确值,还有"match_parent"可以OK,但是如果你使用的是"warp_content"这种模式,不好意思,获取不到,挂了!,我曾就就是这么挂的!很干脆,很无语

    光说不练假把式,来个真把式,直接上代码,我们一块研究,

 /**
  *
  * @author 刘酸酸
  *
  */
 public class MeasureText extends View{

     public MeasureText(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
     }

     public MeasureText(Context context, AttributeSet attrs) {
         super(context, attrs);
     }

     public MeasureText(Context context) {
         super(context);
     }

     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int widthWeasure = measure(widthMeasureSpec);
         int heightMeasure = measure(heightMeasureSpec);
         super.onMeasure(widthWeasure, heightMeasure);
     }

     /** 测试高度 */
     private int measure(int measureSpec) {
         int result = 0;
         //获取测量模式,和测量大小
         int mode = MeasureSpec.getMode(measureSpec);
         int size = MeasureSpec.getSize(measureSpec);

         //精确值模式
         if(mode == MeasureSpec.EXACTLY){
             result = size;
         }else{
             if(mode == MeasureSpec.AT_MOST){
                 result = 200;
             }else{
                 result = Math.min(size, result);
             }
         }
         return result;
     }

  这样我们就可以自己随意的去测量任意一个自己想去测量的View

  

  下面我们看看View的绘制流程吧,

 

    上面我们看完如何测量,下面我们就去看看如何去绘制把!在学习绘制之前,我们在这里必须介绍一个系统2D绘图的API那就是Canvas画布对象,想要在Android当中绘制相应的图像,我们就会使用到Android当中的Canvas对象,你可以把Canvas想象成一个画板,而Bitmap相当于我们作画时使用的画纸,那么我们的Paint对象就相当于一支画笔。

    首先让我们理解下Android平台中的显示类是View,但是还提供了底层图形类android.graphics,今天所说的这些均为graphics底层图形接口。

      Bitmap - 称作位图,一般位图的文件格式后缀为bmp,当然编码器也有很多如RGB565、RGB888。作为一种逐像素的显示对象执行效率高,但是缺点也很明显存储效率低。我们理解为一种存储对象比较好。

      Drawable - 作为Android平下通用的图形对象,它可以装载常用格式的图像,比如GIF、PNG、JPG,当然也支持BMP,当然还提供一些高级的可视化对象,比如渐变、图形等。

      Canvas - 名为画布,我们可以看作是一种处理过程,使用各种方法来管理Bitmap、GL或者Path路径,同时它可以配合Matrix矩阵类给图像做旋转、缩放等操作,同时Canvas类还提供了裁剪、选取等操作。

      Paint - 我们可以把它看做一个画图工具,比如画笔、画刷。他管理了每个画图工具的字体、颜色、样式。 如果涉及一些Android游戏开发、显示特效可以通过这些底层图形类来高效实现自己的应用。

    介绍完了上述的四个作画工具了,那么究竟怎么作画呢。很简单我们继承View并且去重写它的onDraw()方法即可,

  

/**
     * 刘酸酸
     */
    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColor(Color.BLACK);
        canvas.drawLine(0, 0, 56, 56 , paint);
    }

效果就是:

    下面说一下关于创建Canvas对象的细节吧!

      我们的onDraw()方法里面有一个参数,就是Canvas对象,在这个方法里面我们就不去创建了,但是假如我们现在需要创建一个Canvas对象怎么办,

//不带任何参数的构造方法
Canvas canvas = new Canvas()
//带一个参数Bitmap的构造方法
Canvas canvas = new Canvas(Bitmap bitmap)

    第一种方式,虽然编译器(IDE)不会报错,但是我们这里不是很推荐使用,下面我们看第二种方式,第二种方式意思就是,把一个bitmap和canvas绑定在一起,这个过程我们叫装载画布,而这里我们的bitmap对象里面就存储了canvas里面所有的像素信息,如果我们使用第二种方式的话,Canvas.drawXX()方法所操作的就是bitmap对象,说白了是这个方法通过改变bitmap,然后让View重绘,从而显示改变之后的bitmap,

    在理解了Canvas对象之后,我们就可以重写View的onDraw()方法画出我们想要的东西,

    友情提示:当遇到比较难绘制的图形的时候,不要慌,把他化解成为几个简单的像素块,然后再处理。

  ViewGroup的测量:

      其实如果你把前面的View的测量看懂的话,这个就简单了。我们在之前说过,ViewGroup回去管理自己的孩子View,其中所需要管理的一项就是就是测量孩子的显示大小,确定自己的大小,当为”warp_content“的时候,ViewGroup就会去便利所有孩子,得到孩子的大小,从而决定自己的大小,在其他模式下会通过具体的值来设置自身的值,

      ViewGroup在测量时通过便利所有孩子节点,从而调用孩子View的Measure方法来获得每一个孩子的测量结果。

      当孩子便利完成以后,就回去掉用孩子View的layout方法,并制定具体要显示的位置,

      在自定义ViewGruop时,我们通常会重写onLayout()方法来控制孩子显示的位置。

  ViewGruop的绘制:

      其实ViewGruop通常情况下不需要绘制的,因为他本身就没有需要绘制的东西,如果不指定ViewGroup的背景图片,颜色之类的,那么ViewGroup的onDraw()方法都不会去调用,但是ViewGroup会使用dispatchDraw()方法来绘制孩子的,其过程同样是通过便利所有孩子View,调用孩子View的onDraw()方法来完成绘制工作。

    下一篇,我们正式开始学习自定义控件,如果有错的,请及时指出,谢谢大家,

    

自定义View_1_关于View,ViewGroup的测量和绘制流程的更多相关文章

  1. View (三) 视图绘制流程完全解析

    相 信每个Android程序员都知道,我们每天的开发工作当中都在不停地跟View打交道,Android中的任何一个布局.任何一个控件其实都是直接或间 接继承自View的,如TextView.Butto ...

  2. 自定义View/ViewGroup的步骤和实现

    1.设置属性(供XML调用) 在res目录新建attrs.xml文件 <?xml version="1.0" encoding="utf-8"?> ...

  3. Android View 绘制流程(Draw) 完全解析

    前言 前几篇文章,笔者分别讲述了DecorView,measure,layout流程等,接下来将详细分析三大工作流程的最后一个流程——绘制流程.测量流程决定了View的大小,布局流程决定了View的位 ...

  4. Android 控件架构及View、ViewGroup的测量

    附录:示例代码地址 控件在Android开发的过程中是必不可少的,无论是我们在使用系统控件还是自定义的控件.下面我们将讲解一下Android的控件架构,以及如何实现自定义控件. 1.Android控件 ...

  5. 自定义流式布局:ViewGroup的测量与布局

    目录 1.View生命周期以及View层级 1.1.View生命周期 1.2.View层级 2.View测量与MeasureSpec类 2.1.MeasureSpec类 2.2.父View的限制 :测 ...

  6. Android view的测量及绘制

    讲真,自我感觉,我的水平真的是渣的一匹,好多东西都只停留在知道和会用的阶段,也想去研究原理和底层的实现,可是一看到代码就懵逼了,然后就看不下去了, 说自己不着急都是骗人的,我自己都不信,前两天买了本& ...

  7. Android的自定义View及View的绘制流程

    目标:实现Android中的自定义View,为理清楚Android中的View绘制流程“铺路”. 想法很简单:从一个简单例子着手开始编写自定义View,对ViewGroup.View类中与绘制View ...

  8. 128、View 绘制流程 & 自定义View

    记清楚函数调用的顺序才能准确地进行调用. 根据调用链,可将整个绘制过程分为三部分:Measure - Layout - Draw Measure 过程 1. 测量过程由上至下,在measure过程的最 ...

  9. 自定义view:view的绘制流程

    1.view的绘制流程 当 Activity 接收到焦点的时候,它会被请求绘制布局,该请求由 Android framework 处理.绘制是从根节点开始,对布局树进行 measure 和 draw. ...

随机推荐

  1. ux.plup.File plupload 集成 ux.plup.FileLis 批量上传预览

    //plupload 集成 Ext.define('ux.plup.File', { extend: 'Ext.form.field.Text', xtype: 'plupFile', alias: ...

  2. EF执行存储过程时超时问题

    异常信息:Message = EF "Timeout 时间已到.在操作完成之前超时时间已过或服务器未响应." ((IObjectContextAdapter);

  3. 解析Javascript中大括号“{}”的多义性

    JS中大括号有四种语义作用 语义1,组织复合语句,这是最常见的 复制代码 代码如下: if( condition ) {   //... }else {   //... } for() {   //. ...

  4. net组件转化成COM组件

    第一步:生成秘钥文件 强名称工具 (Sn.exe) 有助于使用强名称对程序集进行签名.Sn.exe 提供了用于密钥管理.签名生成和签名验证的选项. 1.使用Visual Studio 命令 Visua ...

  5. Java Web学习系列——创建基于Maven的Web项目

    创建Maven Web项目 在MyEclipse for Spring中新建Maven项目 选择项目类型,在Artifact Id中选择maven-archetype-webapp 输入Group I ...

  6. DDD:四色原型中Role的 “六” 种实现方式

    背景 一个实体在不同的上下文中具备不同的职责,如:产品在“生产完成上下文”中具备的一些职责,在“质检相关上下文”中具备另外一些职责.四色原型.DIC和“UML事物模式”在不同的维度阐述了这一情况,在代 ...

  7. [转载]我们可以用SharePoint做什么

    前言 不知不觉作为一个SharePoint的开发人员若干年了,从SharePoint API开始学习,到了解SharePoint的结构,逐渐一点点了解sharepoint的体系:从SharePoint ...

  8. 【初识 JQMobile 小小总结】

    作为一个前端新手,之前还没有接触过手机端的项目.两周前项目经理告诉我要做手机端,让我用JQMobile. 之前在前端群里,偶尔听说过jqmobile很坑,自己又查了下其他框架,比如zepto.amaz ...

  9. 仿照微信的效果,实现了一个支持多选、选原图和视频的图片选择器,适配了iOS6-9系统,3行代码即可集成.

    提示:如果你发现了Bug,请尝试更新到最新版.目前最新版是1.6.4,此前的版本或多或少存在一些bug的~如果你已经是最新版了,请留一条评论,我看到了会尽快处理和修复哈~ 关于升级iOS10和Xcdo ...

  10. json,serialize,msgpack比较

    速度 在redis中存入同样的压缩数据,取操作执行两个操作: 1 从redis中取 2 解压 3 统一json压缩后放出   ab测试: [yejianfeng@openstack ~/httpd/u ...