正常情况下,我们重写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。
分享到:
相关推荐
我们需要调用`measure()`方法为每个子视图测量尺寸,并使用`setMeasuredDimension()`设置自定义ViewGroup自身的大小。 3. **重写onLayout()**:此方法用于确定子视图的位置。根据布局需求,遍历并设置每个子视图的...
4. **onDraw()**:尽管`ViewGroup`通常不直接绘制内容,但在某些情况下,如背景或者特殊边框,可能需要重写`onDraw()`进行绘制。这里可以使用`Canvas`对象进行绘图操作。 5. **onTouchEvent()**:`ViewGroup`负责...
3. **绘制(Draw)**:虽然`ViewGroup`一般不需要直接进行绘制,但为了实现滑动效果,我们可能需要覆盖`onDraw()`方法来画出当前可见的子`View`的一部分。 4. **触摸事件(Touch Event)**:`onTouchEvent()`是处理用户...
我们需要根据特定的布局策略来设置MeasureSpecs,然后调用`measure()`方法为每个子视图测量尺寸。 2. **onLayout()**: 在确定了所有子视图的尺寸后,这个方法将它们放置在正确的位置。你需要编写逻辑来决定每个子...
我们需要调用`measure()`方法来测量每个TextView,并使用`setMeasuredDimension()`设置自定义ViewGroup的大小。 ```java @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int...
最后,onDraw()会被调用来实际绘制View的内容。 接下来,我们关注ViewGroup,它是View的容器,可以包含多个子View。ViewGroup不仅管理子View的布局,还参与到绘制过程中。在布局时,ViewGroup会调用measure()和...
避免在`onDraw()`方法中执行耗时操作,尽量减少对硬件层的调用,合理使用`ViewGroup#removeView()`和`ViewGroup#addView()`来动态管理子View。 总结来说,自定义MoveViewGroup涉及的关键技术包括手势识别、布局管理...
Scroller_view_ViewGroup是一个关于Android自定义滚动视图的专题,主要探讨如何在Android中...通过深入理解Scroller的工作原理和ViewGroup的布局管理机制,开发者可以为自己的应用程序创造出更加流畅、自然的用户界面。
你需要为每个子View指定合适的尺寸,并返回ViewGroup自身的尺寸。 2. **onLayout()**:在测量完成后,这个方法会布局所有的子View。开发者需要根据特定的需求定位每个子View的位置。 3. **onTouchEvent()**:处理...
4. `onDraw()`方法:虽然在这个例子中我们主要关注布局,但有时可能需要在此方法中绘制额外的内容。 5. `addView()`方法:添加子视图时,可能需要额外的逻辑来确保自动换行功能正常工作。 对于描述中提到的“支持...
2. 测量子View:在onMeasure()方法中,我们需要遍历所有子View,调用measure()方法,为它们指定测量模式和大小。测量模式有MeasureSpec.EXACTLY(指定大小)、MeasureSpec.AT_MOST(最大不超过指定大小)和...
2. **测量子视图**:在onMeasure()中,通过调用measure()方法为每个子视图设定合适的尺寸。MeasureSpec是Android提供的测量模式,用于限制子视图的大小。 3. **布局子视图**:在onLayout()中,你需要根据自己的布局...
在自定义ViewGroup中,我们需要在`onDraw()`或者`drawChild()`方法中调用`Scroller.computeScrollOffset()`获取当前应该滚动到的位置,并更新视图的坐标。 当我们要仿制ViewPager的效果时,这意味着我们需要实现...
时间轴实现效果源码,demo由于设置了颜色,所以ViewGroup会调用onDraw方法,在没有颜色的情况下,如果linearlayout的divider为空,是不会执行onDraw方法的,这里把它设定为执行。
时间轴实现效果源码,demo由于设置了颜色,所以ViewGroup会调用onDraw方法,在没有颜色的情况下,如果linearlayout的divider为空,是不会执行onDraw方法的,这里把它设定为执行。
你需要调用measure()方法为每个子视图设置合适的测量规格,然后根据测量结果计算整个ViewGroup的尺寸。 2. **onLayout()**:此方法负责布局子视图。你需要根据你的布局策略,如网格布局、流式布局等,来决定每个子...
4. 绘制(Draw):虽然ViewGroup通常不直接绘制内容,但如果你的自定义ViewGroup需要添加额外的视觉元素,可以在onDraw()方法中进行。 5. 处理触摸事件:自定义ViewGroup可能会拦截和分发触摸事件。在...
在这个方法中,你需要调用`getChildMeasureSpec()`为每个子视图生成测量规格,然后调用`measure()`和`layout()`方法来确定子视图的位置。 5. **绘制(Draw)**:虽然`ViewGroup`默认不绘制任何内容,但如果你想在`...
android一个简单的时间轴实现效果源码,demo由于设置了颜色,所以ViewGroup会调用onDraw方法,在没有颜色的情况下,如果linearlayout的divider为空,是不会执行onDraw方法的,这里把它设定为执行。