为什么自定义ViewGroup ondraw方法不会被调用
2016-07-28 23:05
337 查看
viewgroup的绘制严格来说是在dispatchDraw中完成,作为一个容器,绘制自己的孩子该通过dispatchDraw(canvas)实现。但是你非要在ondraw中也不会出错。
但自定义ViewGroup ondraw方法不会被调用的根本原因是你的ViewGroup中还没有可绘制的内容。
下面是详细解释:
<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的值的计算代码如下:
当View初始他时,它会调用一个私有方法:computeOpaqueFlags,这里面列出了不透明的三个条件:
// Opaque if:
// - Has a background
// - Background is opaque
// - Doesn't have scrollbars or scrollbars are inside overlay
View还提供了一个重要的方法:setWillNotDraw,我们看一看它的实现:
从这个方法的注释,我们可以看出,如果你想重写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 ondraw方法不会被调用的根本原因是你的ViewGroup中还没有可绘制的内容。
下面是详细解释:
一,现象
<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的值的计算代码如下:
// Opaque if:
// - Has a background
// - Background is opaque
// - Doesn't have scrollbars or scrollbars are inside overlay
View还提供了一个重要的方法:setWillNotDraw,我们看一看它的实现:
三,总结一下:
1)ViewGroup默认情况下,会被设置成WILL_NOT_DRAW,这是从性能考虑,这样一来,onDraw就不会被调用了。2)如果我们要重要一个ViweGroup的onDraw方法,有两种方法:
1,在构造函数里面,给其设置一个颜色,如#00000000。
2,在构造函数里面,调用setWillNotDraw(false),去掉其WILL_NOT_DRAW flag。
相关文章推荐
- 麻雀虽小五脏俱全 Dojo自定义控件应用
- WinForm自定义控件应用实例
- Android组合控件实现功能强大的自定义控件
- C++ 自定义控件的移植问题
- C#实现用户自定义控件中嵌入自己的图标
- Asp.net自定义控件之加载层
- 百度地图自定义控件分享
- 用javascript添加控件自定义属性解析
- Android自定义控件简单实现侧滑菜单效果
- Android自定义控件实现边缘凹凸的卡劵效果
- 详解Android自定义控件属性
- Android自定义控件深入学习 Android生成随机验证码
- 详解Android自定义控件属性TypedArray以及attrs
- Android自定义控件之圆形/圆角的实现代码
- 浅析Android手机卫士自定义控件的属性
- Android自定义控件之仿优酷菜单
- Android自定义控件实现简单写字板功能
- Android自定义控件实现可左右滑动的导航条
- Android自定义控件实现简单的轮播图控件
- Android自定义表格控件满足人们对视觉的需求