android的绘制

  • super.onDraw(canvas);之前还是之后?
    • 继承 View 类,在 onDraw() 中完全自定义它的绘制。

      在之前的样例中,我把绘制代码全都写在了 super.onDraw() 的下面。不过其实,绘制代码写在 super.onDraw() 的上面还是下面都无所谓,甚至,你把 super.onDraw() 这行代码删掉都没关系,效果都是一样的——因为在 View 这个类里,onDraw() 本来就是空实现:

      // 在 View.java 的源码中,onDraw() 是空的
      // 所以直接继承 View 的类,它们的 super.onDraw() 什么也不会做
      public class View implements Drawable.Callback,  
              KeyEvent.Callback, AccessibilityEventSource {
          ...
      
          /**
           * Implement this to do your drawing.
           *
           * @param canvas the canvas on which the background will be drawn
           */
          protected void onDraw(Canvas canvas) {
          }
      
          ...
      }
      
    • 除了继承 View 类,自定义绘制更为常见的情况是,继承一个具有某种功能的控件,去重写它的 onDraw() ,在里面添加一些绘制代码,做出一个「进化版」的控件:基于已有控件的自定义绘制,就不能不考虑 super.onDraw() 了:你需要根据自己的需求,判断出你绘制的内容需要盖住控件原有的内容还是需要被控件原有的内容盖住,从而确定你的绘制代码是应该写在 super.onDraw() 的上面还是下面。

 

  • dispatchDraw():绘制子 View 的方法

    • 造成这种情况的原因是 Android 的绘制顺序:在绘制过程中,每一个 ViewGroup 会先调用自己的 onDraw()来绘制完自己的主体之后再去绘制它的子 View。对于上面这个例子来说,就是你的 LinearLayout 会在绘制完斑点后再去绘制它的子 View。那么在子 View 绘制完成之后,先前绘制的斑点就被子 View 盖住了。

      具体来讲,这里说的「绘制子 View」是通过另一个绘制方法的调用来发生的,这个绘制方法叫做:dispatchDraw()。也就是说,在绘制过程中,每个 View 和 ViewGroup 都会先调用 onDraw() 方法来绘制主体,再调用 dispatchDraw() 方法来绘制子 View。

      注:虽然 View 和 ViewGroup 都有 dispatchDraw() 方法,不过由于 View 是没有子 View 的,所以一般来说 dispatchDraw() 这个方法只对 ViewGroup(以及它的子类)有意义。

 

  • 绘制过程简述
    • 绘制部分最典型的两部分是绘制主题(onDraw)和子view(dispatchDraw),但它们并不是绘制过程的全部。还有其他绘制过程
      • Background
      • 主题Ondraw
      • 子view
      • 滑动边缘渐变和滑动条
      • 前景
      •  

  • onDrawForeground()

    • 首先,再说一遍,这个方法是 API 23 才引入的,所以在重写这个方法的时候要确认你的 minSdk 达到了 23,不然低版本的手机装上你的软件会没有效果。

 

  • 写在 super.onDrawForeground() 的下面

    如果你把绘制代码写在了 super.onDrawForeground() 的下面,绘制代码会在滑动边缘渐变、滑动条和前景之后被执行,那么绘制内容将会盖住滑动边缘渐变、滑动条和前景。

    public class AppImageView extends ImageView {  
        ...
    
        public void onDrawForeground(Canvas canvas) {
           super.onDrawForeground(canvas);
    
           ... // 绘制「New」标签
        }
    }
    
    <!-- 使用半透明的黑色作为前景,这是一种很常见的处理 -->  
    <AppImageView  
        ...
        android:foreground="#88000000" />
    

      • 写在 super.onDrawForeground() 的上面

        如果你把绘制代码写在了 super.onDrawForeground() 的上面,绘制内容就会在 dispatchDraw() 和 super.onDrawForeground() 之间执行,那么绘制内容会盖住子 View,但被滑动边缘渐变、滑动条以及前景盖住:

        public class AppImageView extends ImageView {  
            ...
        
            public void onDrawForeground(Canvas canvas) {
               ... // 绘制「New」标签
        
               super.onDrawForeground(canvas);
            }
        }
        

 

    由于被半透明黑色遮罩盖住,左上角的标签明显变暗了。

 

 

  • draw() 总调度方法

    • 除了 onDraw() dispatchDraw() 和 onDrawForeground() 之外,还有一个可以用来实现自定义绘制的方法: draw()

      draw() 是绘制过程的总调度方法。一个 View 的整个绘制过程都发生在 draw() 方法里。前面讲到的背景、主体、子 View 、滑动相关以及前景的绘制,它们其实都是在 draw() 方法里的。

      // View.java 的 draw() 方法的简化版大致结构(是大致结构,不是源码哦):
      
      public void draw(Canvas canvas) {  
          ...
      
          drawBackground(Canvas); // 绘制背景(不能重写)
          onDraw(Canvas); // 绘制主体
          dispatchDraw(Canvas); // 绘制子 View
          onDrawForeground(Canvas); // 绘制滑动相关和前景
      
          ...
      }

 

posted on 2018-09-06 15:44  endian11  阅读(169)  评论(0)    收藏  举报

导航