精华内容
下载资源
问答
  • 自定义View 绘制顺序

    2019-06-01 12:10:12
    Android 里面绘制都是按 顺序的,先绘制内容会...​ 一般我们自定义绘制 ,全部都是直接继承 View 类,然后重写他 onDraw() 方法,把绘制代码写在里面 @Override protected void onDraw(Canvas canvas) { ...

    Android 里面的绘制都是按 顺序的,先绘制的内容会被后绘制的盖住。比如你先画一个 圆,在画一个方块,这个圆就会被盖住。

    1,super.onDraw() 前 或者 后?

    ​ 一般我们自定义绘制 ,全部都是直接继承 View 类,然后重写他的 onDraw() 方法,把绘制的代码写在里面

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    
       ......绘制内容
     }
    

    ​ 这是自定义绘制的基本状态,继承View ,在onDraw 中完成自定义绘制。
    其实绘制代码写在 super.onDraw 的上面或者下面 都无所谓,甚至可以将这句话删掉。效果都是一样的,因为在 View 的 onDraw 中 是空实现。

    /**
         * Implement this to do your drawing.
         *
         * @param canvas the canvas on which the background will be drawn
         */
        protected void onDraw(Canvas canvas) {
        }
    

    2,写在 super.onDraw 下面

    ​ 如果你继承的 不是View ,而是一个ImageView 。这时由于绘制代码绘制原有内容绘制结束后执行,所以就会覆盖原来控件的内容。

    3,写在 super.onDraw 上面

    ​ 如果继承的是一个 TextView ,将你需要绘制的东西 写在 super.onDraw 上面,这样绘制的内容就会被控件原有的内容覆盖掉。

    ​ 比如:你可以在文字的下面绘制一个 纯色的背景。

    4,dispathDraw(): 绘制字View 的方法

    ​ 如果你继承了一个 LinearLayout ,重写了 onDraw , 然后在 onDraw 中绘制了一些内容,但是 运行程序后会发现 绘制的内容看不见。

    ​ 我学的时候 看到这里也懵了。我没有添加子View 呀。为啥会被覆盖呢。别急,文章的最后面会解答你的疑惑。

    ​ 解决:只有让他在绘制子View 之后执行就好了,重写 dispatchDraw() 并在 super.dispatchDraw() 的下面写上自己的绘制代码,就可以了

     @Override
        protected void dispatchDraw(Canvas canvas) {
            super.dispatchDraw(canvas);
            paint.setColor(Color.parseColor("#ED6F99"));
            paint.setStyle(Paint.Style.FILL);
    
            canvas.drawCircle(100,100,30,paint);
            canvas.drawCircle(300,300,50,paint);
            canvas.drawCircle(300,500,80,paint);
            canvas.drawCircle(700,300,20,paint);
        }
    

    5,绘制过程:

    ​ 一般来说,一个完整的绘制过程会依次绘制一下几个内容:

    ​ 1,背景

    ​ 2,主体(onDraw)

    ​ 3,子View (dispatchDraw)

    ​ 4,滑动边缘渐变 和 滑动条

    ​ 5,前景

    ​ 一般来说,一个View 或者 ViewGroup 的绘制不会将这几项 全部包括,但是必然 逃不出这几项,并且会 遵守这个 顺序。例如一个 LinearLayout 只有背景 和 子View ,那么他会先绘制 背景在绘制子 View 。一个ImageView 有主题,有可能会加上一层半透明的前景 作为 遮罩,那么他的前景 也会在主体之后进行绘制。注意:前景 是在 android6.0 之后加入的,之前其实也有,只不过只支持FrameLayout。直到 6.0 才加入到了 View 里面。

    ​ 第一步背景 ,他的绘制在一个叫 drawBackground() 的方法中,但是这个方法是 private 的,不能重写。如果需要设置背景,只能通过 API 去设置。

    ​ 第二步 绘制主体,在onDraw()中 绘制

    ​ 第三步 绘制子View ,在dispatchDraw 中绘制

    ​ 第四 、 五 两步:这两个部分被放在了 onDrawForeground 方法里,是可以重新写的。

    在这里插入图片描述

    6,onDrawForeground

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

    7,draw 总调度方法

    ​ draw 是绘制的总调度方法,一个View 的绘制过程都发生在 draw 方法里,如下所示:

    public void draw(Canvas canvas) {
        final int privateFlags = mPrivateFlags;
        final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
                (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
        mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
    
        /*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
         *
         *      1. Draw the background
         *      2. If necessary, save the canvas' layers to prepare for fading
         *      3. Draw view's content
         *      4. Draw children
         *      5. If necessary, draw the fading edges and restore layers
         *      6. Draw decorations (scrollbars for instance)
         */
    
        // Step 1, draw the background, if needed
        int saveCount;
    
        if (!dirtyOpaque) {
            drawBackground(canvas);
        }
    
        // skip step 2 & 5 if possible (common case)
        final int viewFlags = mViewFlags;
        boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
        boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
        if (!verticalEdges && !horizontalEdges) {
            // Step 3, draw the content
            if (!dirtyOpaque) onDraw(canvas);
    
            // Step 4, draw the children
            dispatchDraw(canvas);
    
            drawAutofilledHighlight(canvas);
    
            // Overlay is part of the content and draws beneath Foreground
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().dispatchDraw(canvas);
            }
    
            // Step 6, draw decorations (foreground, scrollbars)
            onDrawForeground(canvas);
    
            // Step 7, draw the default focus highlight
            drawDefaultFocusHighlight(canvas);
    
            if (debugDraw()) {
                debugDrawFocus(canvas);
            }
    
            // we're done...
            return;
        }	
    

    ​ 从上面可以看出首先 是绘制背景。然后就是 onDraw ,dispatchDraw , ondrawForeground , 这三个方法被依次调用。所以你也可以重写 这个 draw 放入 来做自定义的调度。

    在这里插入图片描述

    8,写在 super.draw 的下面

    ​ 由于 draw 是总调度方法,如果绘制代码写在下面,那么这段代码将会在 其他所有的 绘制完成后执行。也就是说,他绘制的内容会盖住 其他原有的 内容。

    9,写在 super.draw 上面

    ​ 如果写在上面,这段代码会在 其他所有绘制之前执行。包括背景,背景也会 盖住他。

    注意:关于绘制,有两点需要注意,

    ​ 1,出于效率的考虑,ViewGroup 默认会绕过 draw 方法,转而直接执行 dispatchDraw ,以此来简化 绘制流程。比如自定义了 一个ViewGroup 的子类。并且需要他在 dispatchDraw 以外的任何一个绘制方法内绘制内容,你需要调用 View.setWillNotDraw(false) 方法来切换到完整的绘制流程。

    ​ 2,有的时候,一段绘制代码写在不同的绘制方法中效果是一样的,这时你可以选一个自己喜欢或者习惯的绘制方法来重写。但有一个例外:如果绘制代码既可以写在 onDraw() 里,也可以写在其他绘制方法里,那么优先写在 onDraw() ,因为 Android 有相关的优化,可以在不需要重绘的时候自动跳过 onDraw() 的重复执行,以提升开发效率。享受这种优化的只有 onDraw() 一个方法

    总结:
    在这里插入图片描述

    参考自:https://hencoder.com/ui-1-5/

    展开全文
  • 之前我们自定义view一般都继承了View这个类,其实Android里面所有控件也都继承自这个类,无论是一个view还是viewGroup了,最终都是继承自view。好,如果我们自定义view直接继承自View类,那么我们重写了onDraw在...

    onDraw

    之前我们自定义view一般都继承了View这个类,其实Android里面所有的控件也都继承自这个类,无论是一个view还是viewGroup了,最终都是继承自view。好,如果我们自定义view直接继承自View类,那么我们重写了onDraw在里面做一些自己的绘制,我们也会重写super.onDraw(canvas),但是点击进去看会发现是空实现,只是用注释告诉我们“Implement this to do your drawing”,所以如果是继承自view,那么其实这个super是完全可以不写的,因为父类是空实现啊,但是如果是继承一个现有的view呢,那就不用点击过去看,肯定不是空实现,因为现有控件的绘制操作也是在onDraw里面写的啊,所以这个时候自己把代码写在super.onDraw(canvas)前面还是后面是有影响的

        把自己绘制的代码写在super.onDraw的后面,由于绘制代码会在原有内容绘制结束之后执行,所以绘制内容就会盖住控件原来的内容(这种应用场景就比较多,好比在原来的基础上面加一些东西)
        把自己绘制的代码写在super.onDraw的前面,由于绘制代码会在原有内容绘制之前执行,所以绘制的内容会被控件的super.onDraw的内容覆盖(这种应用场景比较少,但是也会有,例如给继承自textview的文本绘制一个背景色啦,当然绘制背景色有更简单的方法)

    dispatchDraw

    上面的onDraw是针对view自身的绘制,但是如果是把一个view放在viewGroup里面呢?那么父view和子view的绘制顺序又要怎么把握呢?就需要在这个dispatchDraw方法上面做文章了,先来看看这个方法的注释“Called by draw to draw the child views. This may be overridden by derived classes to gain control just before its children are drawn (but after its own view has been drawn).”翻译一下就是这个方法被draw方法调度然后绘制子view,这个方法可以被重写来获得控制权,以能够在它的子view们被绘制之前来做一些事情,但是此时它自身已经被绘制完毕了。好比有这么个例子,我们自定义了一个view继承自linearlayout,是的是一个viewgroup,然后我们想给linearlayout添加一些圆圈的幻影,然后我们将这个linearlayout写在xml中,如果它没有任何子view,那么这个幻影能够正常的展示出来,但是如果我们给这个linearlayout添加了子view,就会发现原来有的幻影现在没有了,这是因为幻影被子view遮盖了,那么要怎么处理呢?其实也很简单,就是在绘制完子view之后我们再绘制linearlayout的幻影就好了,这样就解决问题了,而上面的注释也说了,dispatchDraw方法就是用来调度绘制子view的方法,那么我们把绘制幻影的代码写在super.dispatchDraw(canvas);之后就好了,就这么简单
    关于绘制的顺序概述

        背景background的绘制,这个是发生在一个drawBackground(Canvas canvas)的private的私有方法里面,所以我们无法重写这个方法,只能通过现有Android提供的API去设置它
        onDraw主体绘制,如果是对于父布局而言,也是先调用onDraw绘制自己,然后调用dispatchDraw去绘制子view
        dispatchDraw绘制子view
        滑动边缘渐变和滑动条
        前景(foreGround)(前景的支持是从Android6.0开始的,之前的只是支持framelayout),但是我们貌似一般都不用。这个是被放在一个onDrawForeground方法里面的, 该方法是可以被重写的,做一些自己的设置。当然也可以利用API自带的方法通过xml中的android:scrollbarXXX系列属性设置或者在java代码中调用对应的set方法来进行设置。如果重写了这个那么在super.onDrawForeground()方法的前后写代码则可以控制绘制内容和和滑动边缘以及前景的遮盖关系

    关于绘制方法的调度概述

    为什么上面的方法会按照那样的如下的顺序:背景—onDraw—dispatchDraw—滑动边缘渐变和滑动条—foreGround的顺序来绘制呢?这是因为有一个方法在进行总调度,它就是draw方法,所以如果想要在所有的绘制之前或者所有绘制方法都调用完成后做一些事情,那么就可以重写这个draw方法了,所以如果将自己的绘制代码写在了super.draw(canvas);前面,那么相当于自己绘制的代码会被所有后面的绘制覆盖,如果写在了super.draw(canvas);后面,那么相当于自己的绘制代码会覆盖所有后面的绘制,其实将代码写在super.draw(canvas)后面相当于将代码写在了super.onDrawForeground后面了,因为执行到onDrawForeground就已经执行到绘制的结束时候了
    关于绘制代码书写位置的概述

        出于效率考虑,viewgroup默认会绕过draw,onDraw方法,换而直接执行dispatchdraw,以此来简化绘制流程,所以如果你自定义了某个 ViewGroup 的子类(比如 LinearLayout)并且需要在它的除 dispatchDraw() 以外的任何一个绘制方法内绘制内容,你可能会需要调用 View.setWillNotDraw(false) 这行代码来切换到完整的绘制流程
        有时候代码写在ondraw里面可以,也可以写在dispatchDraw,但是推荐写在onDraw里面,因为对于这个方法android有优化,可以在不需要重绘时候自动跳过onDraw避免重复执行



    转自原文:https://blog.csdn.net/submit66/article/details/80112287
     

    展开全文
  • Android自定义view绘制顺序漫谈

    千次阅读 2018-04-28 12:02:11
      今天就跟大家说说自定义view里面绘制顺序问题,因为有时候避免不了在同一个地方绘制不同view,那么就避免不了遮盖问题,这个时候就就必须考虑绘制顺序的问题了。   说到绘制顺序就不得不提onDraw和...

      今天就跟大家说说自定义view里面的绘制顺序问题,因为有时候避免不了在同一个地方绘制不同的view,那么就避免不了遮盖问题,这个时候就就必须考虑绘制顺序的问题了。
      说到绘制顺序就不得不提onDraw和dispatchDraw这两个方法,下面我们一一来看这两个方法。

    onDraw

    之前我们自定义view一般都继承了View这个类,其实Android里面所有的控件也都继承自这个类,无论是一个view还是viewGroup了,最终都是继承自view。好,如果我们自定义view直接继承自View类,那么我们重写了onDraw在里面做一些自己的绘制,我们也会重写super.onDraw(canvas),但是点击进去看会发现是空实现,只是用注释告诉我们“Implement this to do your drawing”,所以如果是继承自view,那么其实这个super是完全可以不写的,因为父类是空实现啊,但是如果是继承一个现有的view呢,那就不用点击过去看,肯定不是空实现,因为现有控件的绘制操作也是在onDraw里面写的啊,所以这个时候自己把代码写在super.onDraw(canvas)前面还是后面是有影响的

    • 把自己绘制的代码写在super.onDraw的后面,由于绘制代码会在原有内容绘制结束之后执行,所以绘制内容就会盖住控件原来的内容(这种应用场景就比较多,好比在原来的基础上面加一些东西)
    • 把自己绘制的代码写在super.onDraw的前面,由于绘制代码会在原有内容绘制之前执行,所以绘制的内容会被控件的super.onDraw的内容覆盖(这种应用场景比较少,但是也会有,例如给继承自textview的文本绘制一个背景色啦,当然绘制背景色有更简单的方法)

    dispatchDraw

    上面的onDraw是针对view自身的绘制,但是如果是把一个view放在viewGroup里面呢?那么父view和子view的绘制顺序又要怎么把握呢?就需要在这个dispatchDraw方法上面做文章了,先来看看这个方法的注释“Called by draw to draw the child views. This may be overridden by derived classes to gain control just before its children are drawn (but after its own view has been drawn).”翻译一下就是这个方法被draw方法调度然后绘制子view,这个方法可以被重写来获得控制权,以能够在它的子view们被绘制之前来做一些事情,但是此时它自身已经被绘制完毕了。好比有这么个例子,我们自定义了一个view继承自linearlayout,是的是一个viewgroup,然后我们想给linearlayout添加一些圆圈的幻影,然后我们将这个linearlayout写在xml中,如果它没有任何子view,那么这个幻影能够正常的展示出来,但是如果我们给这个linearlayout添加了子view,就会发现原来有的幻影现在没有了,这是因为幻影被子view遮盖了,那么要怎么处理呢?其实也很简单,就是在绘制完子view之后我们再绘制linearlayout的幻影就好了,这样就解决问题了,而上面的注释也说了,dispatchDraw方法就是用来调度绘制子view的方法,那么我们把绘制幻影的代码写在super.dispatchDraw(canvas);之后就好了,就这么简单

    关于绘制的顺序概述

    1. 背景background的绘制,这个是发生在一个drawBackground(Canvas canvas)的private的私有方法里面,所以我们无法重写这个方法,只能通过现有Android提供的API去设置它
    2. onDraw主体绘制,如果是对于父布局而言,也是先调用onDraw绘制自己,然后调用dispatchDraw去绘制子view
    3. dispatchDraw绘制子view
    4. 滑动边缘渐变和滑动条
    5. 前景(foreGround)(前景的支持是从Android6.0开始的,之前的只是支持framelayout),但是我们貌似一般都不用。这个是被放在一个onDrawForeground方法里面的, 该方法是可以被重写的,做一些自己的设置。当然也可以利用API自带的方法通过xml中的android:scrollbarXXX系列属性设置或者在java代码中调用对应的set方法来进行设置。如果重写了这个那么在super.onDrawForeground()方法的前后写代码则可以控制绘制内容和和滑动边缘以及前景的遮盖关系

    关于绘制方法的调度概述

    为什么上面的方法会按照那样的如下的顺序:背景—onDraw—dispatchDraw—滑动边缘渐变和滑动条—foreGround的顺序来绘制呢?这是因为有一个方法在进行总调度,它就是draw方法,所以如果想要在所有的绘制之前或者所有绘制方法都调用完成后做一些事情,那么就可以重写这个draw方法了,所以如果将自己的绘制代码写在了super.draw(canvas);前面,那么相当于自己绘制的代码会被所有后面的绘制覆盖,如果写在了super.draw(canvas);后面,那么相当于自己的绘制代码会覆盖所有后面的绘制,其实将代码写在super.draw(canvas)后面相当于将代码写在了super.onDrawForeground后面了,因为执行到onDrawForeground就已经执行到绘制的结束时候了

    关于绘制代码书写位置的概述

    • 出于效率考虑,viewgroup默认会绕过draw,onDraw方法,换而直接执行dispatchdraw,以此来简化绘制流程,所以如果你自定义了某个 ViewGroup 的子类(比如 LinearLayout)并且需要在它的除 dispatchDraw() 以外的任何一个绘制方法内绘制内容,你可能会需要调用 View.setWillNotDraw(false) 这行代码来切换到完整的绘制流程
    • 有时候代码写在ondraw里面可以,也可以写在dispatchDraw,但是推荐写在onDraw里面,因为对于这个方法android有优化,可以在不需要重绘时候自动跳过onDraw避免重复执行

      以上就是关于绘制顺序的全部内容,有问题欢迎批评指正,以上内容参考了扔物线大神的作品。

    展开全文
  • 继承View的绘制顺序 继承View时,无论在super.onDraw(canvas)方法上面还是下面自定义绘制代码时,效果都是只会绘制你的自定义绘制代码。因为View中的onDraw方法是空实现。 public class MyView extends View { ... ...

    一.继承View的绘制顺序

    继承View时,无论在super.onDraw(canvas)方法上面还是下面自定义绘制代码时,效果都是只会绘制你的自定义绘制代码。因为View中的onDraw方法是空实现。

    public class MyView extends View {
        ...
        protected void onDraw(Canvas canvas) {
        	//在super.onDraw(canvas)方法上面自定义绘制代码
            super.onDraw(canvas);
            //在下面自定义绘制代码
        }
        
        ...
    }
    

    二.继承其他已有的控件

    继承其他已有的控件(如TextView,EditView等),目的是对它们原有的功能进行扩展,加入自己想要的功能。但这些控件都重写了父类的onDraw方法,因此需要留意绘制顺序的问题。

    如果把绘制代码写在 super.onDraw() 的上面,由于绘制代码会执行在原有内容的绘制之前,所以绘制的内容会被控件的原内容盖住。简单来说就是先绘制的会被后面的盖住。

    public class MyTextView extends TextView {
        ...
    
        @Override
        protected void onDraw(Canvas canvas) {
        	//在onDraw方法上面绘制背景
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(Color.YELLOW);
            canvas.drawRect(getLeft(), getTop(), getRight(), getBottom(), paint);
            super.onDraw(canvas);
        }
    }
    

    效果图如下:
    在这里插入图片描述
    如果将onDraw方法上面几行自定义绘制代码移到它的下面,就会出现下面的效果:
    在这里插入图片描述
    因此在继承其他控件时一定要注意上面的绘制顺序,以免出现上面的错误。

    三.主体和子View的绘制顺序

    在继承其他的布局,实现自定义布局时,如果按照上面的步骤给这个自定义布局中添加自定义绘制代码,并且在xml文件中给此布局添加子VIew,你会发现你的自定义绘制代码不起作用了。这时就要提到dispatchDraw(),它是绘制子 View 的方法。
    它和onDraw()的绘制顺序如下:
    在这里插入图片描述
    如果你想让自己的自定义图形在最上面显示,如下面的效果,就需要在重写父类dispatchDraw()方法,将自定义绘制代码移到super.dispatchDraw()方法下面.
    而如果在super.dispatchDraw()方法上面绘制,就会又出现自定义绘制图形被盖住的情况.

    效果图

    public class SpottedLinearLayout extends LinearLayout {
        ...
        protected void dispatchDraw(Canvas canvas) {
           super.dispatchDraw(canvas);
           ... // 自定义绘制代码
        }
    }
    

    参考文章:
    自定义View的绘制顺序

    展开全文
  • 07_文字测量和几何变换本质与实用技巧(三)自定义 View 1-5 绘制顺序1 super.onDraw() 前 or 后?1.1 写在 super.onDraw() 下面1.2 写在 super.onDraw() 上面2 dispatchDraw():绘制子 View 方法2.1 写在...
  • [size=medium]Android系统中要自定义view,首先需要了解Androidview加载机制。主要有三个方法: 1、onMeasure() //计算出view自身大小 2、onLayout() //仅在ViewGroup中,用来为子view指定位置(left,top) 3...
  • 自定义View-绘制顺序

    2019-08-13 16:48:17
    // 直接继承View的话,是无所谓的,因为onDraw()方法是空实现 // 继承某一个已知的控件,就有分别了 // super.onDraw()下面:绘制内容覆盖原有内容,比如打印图像尺寸信息 // super.onDraw()上...
  • 一 绘制方法简单介绍在自定义View中的绘制方法有以下几种:1 最常用的onDraw方法,此方法绘制的是View的主体内容2 绘制子View的dispatchDraw方法,一般在以ViewGroup为父类的View中被用到,此方法绘制的是View中的子...
  • 这个一个系列,本系列讲都是本人自定义 View 学习笔记。目的是加深影响,便于在以后工作中遇到相关问题时候,能够有个印象知道到哪里去寻找答案。 这是我学习扔物线大神的自定义 View 教程,自己记录笔记。...
  • 以一个小案例打印记录下自定义View各个方法执行顺序。 public class ProcessLinearLayout extends LinearLayout { public ProcessLinearLayout(Context context) { this(context,null); } public ...
  • Android系统中要自定义view,首先需要了解Androidview加载机制。主要有三个方法: 1、onMeasure() //计算出view自身大小 2、onLayout() //仅在ViewGroup中,用来为子view指定位置(left,top) 3、onDraw() //...
  • 《HenCoder Android 开发进阶:自定义 View 1-5 绘制顺序练习项目
  • 因为工作原因,想写一篇自定义view的初级心得。 一、一般而言写自定义view有大体6个步骤(以下顺序不分先后):继承View的某个子类,包括ViewGroup的子类(毕竟ViewGroup也是View的子类嘛╮(╯_╰)╭) 2. 重写继承...
  • onMeasure 调用该方法来检查View组件及它所包含所有子组件大小 onDraw 当该组件需要绘制它内容时回调该方法进行绘制 onLayout 当该组件需要分配其子组件位置,大小时,该方法就会被回调 onSizeCha

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 440
精华内容 176
热门标签
关键字:

自定义view的顺序