Under normal circumstances, we will rewrite the ondraw method of linearlayout and it will not be called. This article will analyze the causes and solutions.
I. symptom
<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>
The general architecture is that mylinearlayout is derived from linearlayout, and ondraw (canvas) is reloaded in the program ). However, ondraw will not be called. We may encounter this problem: if we do not set a background for linearlayout, the system will not call ondraw, that is, the ondraw we override will not be called. When a background is set, ondraw is called.
2. Cause
The reason for this phenomenon is that it inherits from linearlayout, while linearlayout is a container and viewgroup. It does not have anything to draw. It is a transparent control, because it does not trigger ondraw, but now you set a background color for linearlayout. In fact, no matter what color you set, the system will think that there is something on linearlayout that can be painted, therefore, the ondraw method is called.
We can carefully analyze the source code of the view. There is a method view # Draw (canvas). Here there are two conditions for ondraw to be called:
If (! Dirtyopaque) ondraw (canvas );
That is to say, if dirtyopaque is true, ondraw will not call it, and the dirtyopaque value calculation code is as follows:
final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE && (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
When a view is started, it calls a private method: computeopaqueflags, which lists the three opacity conditions:
// Opaque if:
//-Has a background
//-Background is opaque
//-Doesn' t have scrollbars or scrollbars are inside overlay
View also provides an important method: setwillnotdraw. Let's take a look at its implementation:
/** * 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); }
From the comments of this method, we can see that if you want to rewrite ondraw, you should call this method to clear the flag, so if we want to rewrite the ondraw of linearlayout, we can also call the setwillnotdraw method in its constructor. When the viewgroup is initially called, it calls a private method: initviewgroup, which contains a setflags (will_not_draw, draw_mask); It is equivalent to calling setwillnotdraw (true, for viewgroup, it is regarded as transparent. If we want to override ondraw, we need to call setwillnotdraw (false)
Iii. Summary:
1) viewgroup is set to will_not_draw by default. This is based on performance considerations, so that ondraw will not be called.
2) if we want to consider an ondraw method of viwegroup, there are two methods:
1. In the constructor, set a color for it, for example, #00000000.
2. In the constructor, call setwillnotdraw (false) to remove its will_not_draw flag.