`
iaiai
  • 浏览: 2196392 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

ViewGroup为什么不会调用onDraw

 
阅读更多
正常情况下,我们重写LinearLayout的onDraw方法,它是不会被调用的,这篇文章就来分析一下原因和解决方法。

一,现象
<com.test.demo.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/ll_absolute"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:background="#FF000000">

</com.test.demo.MyLinearLayout> 

大概的架构是,MyLinearLayout从LinearLayout派生出来,然后在程序中重载OnDraw(Canvas canvas)。但是,onDraw不会被调用。我们可能会遇到这个问题:如果不给LinearLayout设置一个背景,系统是不会调用onDraw时,也就是说,我们重写的onDraw是不会调用的。当设置一个背景后,onDraw就会被调用。

二,原因
造成这种现象的原因是继承自LinearLayout,而LinearLayout这是一个容器,ViewGroup嘛,它本身并没有任何可画的东西,它是一个透明的控件,因些并不会触发onDraw,但是你现在给LinearLayout设置一个背景色,其实这个背景色不管你设置成什么颜色,系统会认为,这个LinearLayout上面有东西可画了,因此会调用onDraw方法。

我们可以仔细分析View的源码,它有一个方法View#draw(Canvas)方法,这里面有两个地方调用onDraw,它的条件都是:

if (!dirtyOpaque) onDraw(canvas);
也就是说,如果dirtyOpaque是true的话,onDraw就不会调用,而dirtyOpaque的值的计算代码如下:
final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&  
                (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);

当View初始他时,它会调用一个私有方法:computeOpaqueFlags,这里面列出了不透明的三个条件:
        // Opaque if:

        //   - Has a background

        //   - Background is opaque

        //   - Doesn't have scrollbars or scrollbars are inside overlay
View还提供了一个重要的方法:setWillNotDraw,我们看一看它的实现:
/** 
  * If this view doesn't do any drawing on its own, set this flag to 
  * allow further optimizations. By default, this flag is not set on 
  * View, but could be set on some View subclasses such as ViewGroup. 
  * 
  * Typically, if you override {@link #onDraw} you should clear this flag. 
  * 
  * @param willNotDraw whether or not this View draw on its own 
  */  
 public void setWillNotDraw(boolean willNotDraw) {  
     setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);  
  
 }

从这个方法的注释,我们可以看出,如果你想重写onDraw的话,你应该调用这个方法来清除flag,所以如果我们想要重写LinearLayout的onDraw的话,我们也可以在其构造方法中调用setWillNotDraw方法。 在ViewGroup初始他时,它调用了一个私有方法:initViewGroup,它里面会有一句setFlags(WILL_NOT_DRAW, DRAW_MASK); 相当于调用了setWillNotDraw(true),所以说,对于ViewGroup,它就认为是透明的了。如果我们想要重写onDraw,就需要调用setWillNotDraw(false)

三,总结一下
1)ViewGroup默认情况下,会被设置成WILL_NOT_DRAW,这是从性能考虑,这样一来,onDraw就不会被调用了。

2)如果我们要重要一个ViweGroup的onDraw方法,有两种方法:

        1,在构造函数里面,给其设置一个颜色,如#00000000。

        2,在构造函数里面,调用setWillNotDraw(false),去掉其WILL_NOT_DRAW flag。
分享到:
评论

相关推荐

    自定义ViewGroup组合控件

    我们需要调用`measure()`方法为每个子视图测量尺寸,并使用`setMeasuredDimension()`设置自定义ViewGroup自身的大小。 3. **重写onLayout()**:此方法用于确定子视图的位置。根据布局需求,遍历并设置每个子视图的...

    创建定制的ViewGroup

    4. **onDraw()**:尽管`ViewGroup`通常不直接绘制内容,但在某些情况下,如背景或者特殊边框,可能需要重写`onDraw()`进行绘制。这里可以使用`Canvas`对象进行绘图操作。 5. **onTouchEvent()**:`ViewGroup`负责...

    ViewGroup实现VIewpager的效果

    3. **绘制(Draw)**:虽然`ViewGroup`一般不需要直接进行绘制,但为了实现滑动效果,我们可能需要覆盖`onDraw()`方法来画出当前可见的子`View`的一部分。 4. **触摸事件(Touch Event)**:`onTouchEvent()`是处理用户...

    Android 手把手教您自定义ViewGroup(一)

    我们需要根据特定的布局策略来设置MeasureSpecs,然后调用`measure()`方法为每个子视图测量尺寸。 2. **onLayout()**: 在确定了所有子视图的尺寸后,这个方法将它们放置在正确的位置。你需要编写逻辑来决定每个子...

    自定义ViewGroup 显示两个TextView

    我们需要调用`measure()`方法来测量每个TextView,并使用`setMeasuredDimension()`设置自定义ViewGroup的大小。 ```java @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int...

    Android中的View与ViewGroup绘制过程,手势监听顺序与使用

    最后,onDraw()会被调用来实际绘制View的内容。 接下来,我们关注ViewGroup,它是View的容器,可以包含多个子View。ViewGroup不仅管理子View的布局,还参与到绘制过程中。在布局时,ViewGroup会调用measure()和...

    自定义ViewGroup实现拖动跟快速滚动的效果实例

    避免在`onDraw()`方法中执行耗时操作,尽量减少对硬件层的调用,合理使用`ViewGroup#removeView()`和`ViewGroup#addView()`来动态管理子View。 总结来说,自定义MoveViewGroup涉及的关键技术包括手势识别、布局管理...

    Scroller_view_ViewGroup

    Scroller_view_ViewGroup是一个关于Android自定义滚动视图的专题,主要探讨如何在Android中...通过深入理解Scroller的工作原理和ViewGroup的布局管理机制,开发者可以为自己的应用程序创造出更加流畅、自然的用户界面。

    自定义ViewGroup实现滑屏等动作

    你需要为每个子View指定合适的尺寸,并返回ViewGroup自身的尺寸。 2. **onLayout()**:在测量完成后,这个方法会布局所有的子View。开发者需要根据特定的需求定位每个子View的位置。 3. **onTouchEvent()**:处理...

    android 自动换行的自定义viewgroup

    4. `onDraw()`方法:虽然在这个例子中我们主要关注布局,但有时可能需要在此方法中绘制额外的内容。 5. `addView()`方法:添加子视图时,可能需要额外的逻辑来确保自动换行功能正常工作。 对于描述中提到的“支持...

    Android自定义ViewGroup(一)

    2. 测量子View:在onMeasure()方法中,我们需要遍历所有子View,调用measure()方法,为它们指定测量模式和大小。测量模式有MeasureSpec.EXACTLY(指定大小)、MeasureSpec.AT_MOST(最大不超过指定大小)和...

    android自定义ViewGroup总结

    2. **测量子视图**:在onMeasure()中,通过调用measure()方法为每个子视图设定合适的尺寸。MeasureSpec是Android提供的测量模式,用于限制子视图的大小。 3. **布局子视图**:在onLayout()中,你需要根据自己的布局...

    自定义ViewGroup仿ViewPager

    在自定义ViewGroup中,我们需要在`onDraw()`或者`drawChild()`方法中调用`Scroller.computeScrollOffset()`获取当前应该滚动到的位置,并更新视图的坐标。 当我们要仿制ViewPager的效果时,这意味着我们需要实现...

    time_java_DEMO_

    时间轴实现效果源码,demo由于设置了颜色,所以ViewGroup会调用onDraw方法,在没有颜色的情况下,如果linearlayout的divider为空,是不会执行onDraw方法的,这里把它设定为执行。

    time line_timelineactivity_energyl2h_DEMO_android_

    时间轴实现效果源码,demo由于设置了颜色,所以ViewGroup会调用onDraw方法,在没有颜色的情况下,如果linearlayout的divider为空,是不会执行onDraw方法的,这里把它设定为执行。

    自定义ViewGroup

    你需要调用measure()方法为每个子视图设置合适的测量规格,然后根据测量结果计算整个ViewGroup的尺寸。 2. **onLayout()**:此方法负责布局子视图。你需要根据你的布局策略,如网格布局、流式布局等,来决定每个子...

    自定义viewgroup

    4. 绘制(Draw):虽然ViewGroup通常不直接绘制内容,但如果你的自定义ViewGroup需要添加额外的视觉元素,可以在onDraw()方法中进行。 5. 处理触摸事件:自定义ViewGroup可能会拦截和分发触摸事件。在...

    继承ViewGroup Demo

    在这个方法中,你需要调用`getChildMeasureSpec()`为每个子视图生成测量规格,然后调用`measure()`和`layout()`方法来确定子视图的位置。 5. **绘制(Draw)**:虽然`ViewGroup`默认不绘制任何内容,但如果你想在`...

    android一个简单的时间轴实现效果源码.zip

    android一个简单的时间轴实现效果源码,demo由于设置了颜色,所以ViewGroup会调用onDraw方法,在没有颜色的情况下,如果linearlayout的divider为空,是不会执行onDraw方法的,这里把它设定为执行。

Global site tag (gtag.js) - Google Analytics