如何做交易网站,wordpress类似的,有内涵的广告公司名字,wordpress ini主题ViewGroup#xff0c;它本身并没有任何可画的东西#xff0c;它是一个透明的控件#xff0c;因些并不会触发onDraw#xff0c;但是你现在给LinearLayout设置一个背景色#xff0c;其实这个背景色不管你设置成什么颜色#xff0c;系统会认为#xff0c;这个LinearLayout上…ViewGroup它本身并没有任何可画的东西它是一个透明的控件因些并不会触发onDraw但是你现在给LinearLayout设置一个背景色其实这个背景色不管你设置成什么颜色系统会认为这个LinearLayout上面有东西可画了因此会调用onDraw方法。 android代码一直在优化我看了几个版本的源码目前我用的是API30的源码再去看ViewGroup为什么不走onDraw的时候已经不是一句 if (!dirtyOpaque) 就能决定是否执行onDraw()的事了。 原因详解 在API27中还是我们熟悉的那个 if 判断决定 onDraw()的执行
在API27以后你会发现在draw()方法里找不到 上面这个 if 语句那么问题来了他是如何控制 ViewGroup 不执行 onDraw() 的呢
这个时候我们的目光该放在这两个片段上了还是在 View 这个类里面 片段一
view.java
/*** This method is called by ViewGroup.drawChild() to have each child view draw itself.** This is where the View specializes rendering behavior based on layer type,* and hardware acceleration.*/boolean draw(Canvas canvas, ViewGroup parent, long drawingTime)方法...// Fast path for layouts with no backgroundsif ((mPrivateFlags PFLAG_SKIP_DRAW) PFLAG_SKIP_DRAW) {mPrivateFlags ~PFLAG_DIRTY_MASK;dispatchDraw(canvas);} else {draw(canvas);}...
从这一段我们能获取两个信息 注释
ViewGroup.drawChild调用此方法使每个子视图都绘制自己。这是视图根据图层类型专门处理渲染行为的地方硬件加速。是否走draw()方法由两个标志决定 mPrivateFlags PFLAG_SKIP_DRAW
片段二
public RenderNode updateDisplayListIfDirty() {// Fast path for layouts with no backgroundsif ((mPrivateFlags PFLAG_SKIP_DRAW) PFLAG_SKIP_DRAW) {dispatchDraw(canvas);drawAutofilledHighlight(canvas);if (mOverlay ! null !mOverlay.isEmpty()) {mOverlay.getOverlayView().draw(canvas);}if (isShowingLayoutBounds()) {debugDrawFocus(canvas);}} else {draw(canvas);}
}从这一段我们能获取这么个信息是否走draw()方法由两个标志决定 mPrivateFlags PFLAG_SKIP_DRAW
硬件加速
现在Android默认开启硬件加速什么是硬件加速呢为了加快Android绘制速度适当解放cpu资源Android将一部分绘制放到gpu执行。而对应的Android里面的canvas也分为是否支持硬件加速因此绘制流程也有所差异流程图简示如下
[]表示该调用该类里的对应方法。 ()表示方法里的参数 从上图可以看出不管是否开启硬件加速都会经历“跳过绘制”的逻辑判断而该判断的分支就决定了viewGroup的ondraw()方法是否执行。如果“跳过绘制”成立那么调用dispatchDraw()方法继而调用子view进行绘制如果有子view。如果“跳过绘制”不成立那么调用draw(x1)该方法上面分析过了会调用dispatchDraw()和ondraw()方法。
draw(x1)的方法如下 public void draw(Canvas canvas) {//省略boolean horizontalEdges (viewFlags FADING_EDGE_HORIZONTAL) ! 0;boolean verticalEdges (viewFlags FADING_EDGE_VERTICAL) ! 0;if (!verticalEdges !horizontalEdges) {// 绘制自身内容onDraw(canvas);// 绘制子viewdispatchDraw(canvas);//省略// were done...return;}//省略}
viewGroup和View初始化时对于PFLAG_SKIP_DRAW标记做了不同的处理。 viewGroup初始化的时候默认设置了WILL_NOT_DRAW从字面意思来看是“不会绘制”标记这个标记是否和PFLAG_SKIP_DRAW有联系呢继续查看setFlags方法
vew.java setFlags方法//省略if ((changed DRAW_MASK) ! 0) {if ((mViewFlags WILL_NOT_DRAW) ! 0) {if (mBackground ! null|| mDefaultFocusHighlight ! null|| (mForegroundInfo ! null mForegroundInfo.mDrawable ! null)) {mPrivateFlags ~PFLAG_SKIP_DRAW;} else {mPrivateFlags | PFLAG_SKIP_DRAW;}} else {mPrivateFlags ~PFLAG_SKIP_DRAW;}requestLayout();invalidate(true);}//省略
到此处就比较明朗将两个标记值联系起来了
1、如果设置了WILL_NOT_DRAW标记那么继续检查background、foreground(mDrawable字段)、focusHighLight是否有值如果三者任意一个设置了那么将PFLAG_SKIP_DRAW标记清除否则将该标记加上。
2、如果没有设置WILL_NOT_DRAW标记那么将PFLAG_SKIP_DRAW标记清除。如何让viewGroup onDraw()执行
既然知道了MyFrameLayout没有绘制的原因那么就有方法让它执行绘制流程。 先来看看WILL_NOT_DRAW
view.java/*** If this view doesnt 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(android.graphics.Canvas)}* 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);}/*** Returns whether or not this View draws on its own.** return true if this view has nothing to draw, false otherwise*/ViewDebug.ExportedProperty(category drawing)public boolean willNotDraw() {return (mViewFlags DRAW_MASK) WILL_NOT_DRAW;}
View类里暴露了设置WILL_NOT_DRAW标记的接口 setWillNotDraw(boolean willNotDraw)可以在viewgroups里使用setWillNotDraw(false)。 不想设置该标记也是可行的前面说过即使设置了WILL_NOT_DRAW后面还是有判断background、foreground、focusHighLight是否有值。 background:view背景 foreground(mDrawable字段):view前景 focusHighLight:view获得焦点时高亮 我们只要设置了其中一个值PFLAG_SKIP_DRAW标记将会被清空。 来看看这三个值如何影响PFLAG_SKIP_DRAW标记
view.java
public void setBackgroundDrawable(Drawable background) {
if (background ! null) {if ((mPrivateFlags PFLAG_SKIP_DRAW) ! 0) {mPrivateFlags ~PFLAG_SKIP_DRAW;requestLayout true;}}
}public void setForeground(Drawable foreground) {if (foreground ! null) {if ((mPrivateFlags PFLAG_SKIP_DRAW) ! 0) {mPrivateFlags ~PFLAG_SKIP_DRAW;}}
}private void setDefaultFocusHighlight(Drawable highlight) {mDefaultFocusHighlight highlight;mDefaultFocusHighlightSizeChanged true;if (highlight ! null) {if ((mPrivateFlags PFLAG_SKIP_DRAW) ! 0) {mPrivateFlags ~PFLAG_SKIP_DRAW;}}}
总结
若要ViewGroup onDraw()执行只需要setWillNotDraw(false)、设置背景、设置前景、设置焦点高亮4个选项其中一项满足即可。当然也可以重写dispatchDraw()方法在该方法里绘制自定义view的内容。