当前位置:网站首页>Drawing mechanism of view (3)
Drawing mechanism of view (3)
2022-07-02 07:27:00 【android_ Mr_ summer】
brief introduction
Last time we analyzed ViewRootImpl Objects and view Of measure() Methods to analyze , Let's continue to analyze layout() and draw() Method .
Catalog
- layout()
- draw()
layout()
We learned from the last blog ViewRootImpl Medium performTraversals() Method is called performLayout(), First look at the source code :
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
...
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
try {
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
...
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
mInLayout = false;
}
In this method, we mainly look at host.layout(),host It's our root layout DecorView,DecorView Inherited from FrameLayout, The call layout() Methods , So we can continue to check view In the middle of layout Method :
public void layout(int l, int t, int r, int b) {
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
//layoutoutMode by Optical It will be transferred to setOpticalFrame()
//setOpticalFrame() The passed in parameters will be adjusted , But still call setFrame() Method
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
// If this is a ViewGroup, Also traverses the sub View Of layout() Method
// If it's ordinary View, Notice the specific implementation class layout change notice
onLayout(changed, l, t, r, b);
// eliminate PFLAG_LAYOUT_REQUIRED Mark
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
``````
// Layout monitoring notification
}
// eliminate PFLAG_FORCE_LAYOUT Mark
mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
}
viewGroup Medium layout()
public final void layout(int l, int t, int r, int b) {
if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
// If there is no animation , Or the animation is not running
super.layout(l, t, r, b);
} else {
// Wait for the animation to complete before calling requestLayout()
mLayoutCalledWhileSuppressed = true;
}
}
@Override
protected abstract void onLayout(boolean changed,
int l, int t, int r, int b);
Above we know view in layout The way is not to be final Embellished , Its subclasses can duplicate the method , in addition onLayout() Method is an empty method , So we need to View Subclasses of can rewrite the method according to their own needs to complete layout technological process .
and viewGroup Medium layout The way is to be final Embellished , We inherit viewGroup Method must override onLayout Abstract method of .
The first call setFrame() Method , The return value of the method indicates whether the layout has changed from the last time . The four parameters passed in represent , Layout left 、 Top 、 Right 、 The value at the bottom , These four values indicate a rectangular area .
protected boolean setFrame(int left, int top, int right, int bottom) {
boolean changed = false;
if (DBG) {
Log.d("View", this + " View.setFrame(" + left + "," + top + ","
+ right + "," + bottom + ")");
}
if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
changed = true;
// Remember our drawn bit
int drawn = mPrivateFlags & PFLAG_DRAWN;
int oldWidth = mRight - mLeft;
int oldHeight = mBottom - mTop;
int newWidth = right - left;
int newHeight = bottom - top;
boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);
// Invalidate our old position
invalidate(sizeChanged);
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;
mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
mPrivateFlags |= PFLAG_HAS_BOUNDS;
// Callbacks onSizeChanged() Method
if (sizeChanged) {
sizeChange(newWidth, newHeight, oldWidth, oldHeight);
}
...
}
return changed;
}
This method is relatively simple , It mainly saves the area passed in by the parent class to View Of mLeft、mTop、mRight、mBottom. The execution of the setFrame() Then it will be executed to onLayout() Method .
draw()
draw The process is also in ViewRootImpl Of performTraversals() Internally dispatched , The calling sequence is measure() and layout() after ,ViewRootImpl The code in will create a Canvas object , And then call View Of draw() Method to perform a specific drawing process . So it's back to ViewGroup And View Tree recursion of draw The process .
public void draw(Canvas canvas) {
. . .
// Draw the background , Only dirtyOpaque by false And then draw , The same below
int saveCount;
if (!dirtyOpaque) {
drawBackground(canvas);
}
. . .
// Draw your own content
if (!dirtyOpaque) onDraw(canvas);
// Sketcher View
dispatchDraw(canvas);
. . .
// Draw scrollbars, etc
onDrawForeground(canvas);
}
First step , Yes View Draw against the background of .
private void drawBackground(Canvas canvas) {
// obtain xml Pass through android:background Property or code setBackgroundColor()、setBackgroundResource() Background of assignment by such methods Drawable
final Drawable background = mBackground;
......
// according to layout Determined by the process View Position to set the drawing area of the background
if (mBackgroundSizeChanged) {
background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
mBackgroundSizeChanged = false;
rebuildOutline();
}
......
// call Drawable Of draw() Method to complete the background rendering
background.draw(canvas);
......
}
The second step , Yes View Draw the contents of .
/** * Implement this to do your drawing. * * @param canvas the canvas on which the background will be drawn */
protected void onDraw(Canvas canvas) {
}
This is an empty method . Because of every View The content parts of are different , So you need subclasses to implement specific logic .
The third step , For the current View All son View Drawing , If the current View No children View You don't need to draw .
Let's see View Of draw Methods dispatchDraw(canvas); Method source code , You can see the following :
protected void dispatchDraw(Canvas canvas) {}
View Of dispatchDraw() Method is an empty method , We need to take a look ViewGroup Of dispatchDraw Method source code ( This is what I just said right now View All son View Drawing , If the current View No children View The reason why you don't need to draw , Because if it is View The method is empty , and ViewGroup Only then can we achieve ), as follows :
@Override
protected void dispatchDraw(Canvas canvas) {
......
final int childrenCount = mChildrenCount;
final View[] children = mChildren;
......
for (int i = 0; i < childrenCount; i++) {
......
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
more |= drawChild(canvas, child, drawingTime);
}
}
......
// Draw any disappearing views that have animations
if (mDisappearingChildren != null) {
......
for (int i = disappearingCount; i >= 0; i--) {
......
more |= drawChild(canvas, child, drawingTime);
}
}
......
}
Can see ,ViewGroup It did rewrite View Of dispatchDraw() Method , The method internally traverses each child View, And then call drawChild() Method , We can look at it ViewGroup Of drawChild Method , as follows :
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
return child.draw(canvas, this, drawingTime);
}
Can see drawChild() Method to transfer the son View Of draw() Method . So ViewGroup Class has been overridden for us dispatchDraw() Function realization of , We generally don't need to rewrite this method , But you can overload the parent function to achieve specific functions .
Step four , Yes View Scroll bar to draw .
protected final void onDrawScrollBars(Canvas canvas) {
......
}
You can see that actually any one View All have ( Horizontal and vertical ) Scrollbar's , It's just that it's not displayed in general .
Here we are ,View Of draw Drawing part of the source code analysis is completed .
invalidate
We know invalidate()( In the main thread ) and postInvalidate()( Can be in the sub thread ) Are used to request View Redrawing method .
invalidate Method source code analysis :
public void invalidate(Rect dirty) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
// The essence is transportation invalidateInternal Method
invalidateInternal(dirty.left - scrollX, dirty.top - scrollY,
dirty.right - scrollX, dirty.bottom - scrollY, true, false);
}
public void invalidate(int l, int t, int r, int b) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
// The essence is transportation invalidateInternal Method
invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false);
}
public void invalidate() {
//invalidate The essence of it is transportation invalidateInternal Method
invalidate(true);
}
void invalidate(boolean invalidateCache) {
// The essence is transportation invalidateInternal Method
invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
}
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
boolean fullInvalidate) {
......
// Propagate the damage rectangle to the parent view.
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
if (p != null && ai != null && l < r && t < b) {
final Rect damage = ai.mTmpInvalRect;
// Set refresh area
damage.set(l, t, r, b);
// Delivery and transportation Parent ViewGroup Of invalidateChild Method
p.invalidateChild(this, damage);
}
......
}
public final void invalidateChild(View child, final Rect dirty) {
ViewParent parent = this;
final AttachInfo attachInfo = mAttachInfo;
......
do {
......
// Circulate the superior transportation layer by layer , until ViewRootImpl Returns the null
parent = parent.invalidateChildInParent(location, dirty);
......
} while (parent != null);
}
This process is finally passed to ViewRootImpl Of invalidateChildInParent Method end , So let's take a look at ViewRootImpl Of invalidateChildInParent Method , as follows :
@Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
......
//View Dispatching invalidate Finally, it is uploaded to ViewRootImpl Finally triggered the method
scheduleTraversals();
......
}
The above code is finally uploaded to ViewRootImpl Finally triggered the method .
postInvalidate
public void postInvalidate() {
postInvalidateDelayed(0);
}
Continue to look at his transportation methods postInvalidateDelayed, as follows :
public void postInvalidateDelayed(long delayMilliseconds) {
// We try only with the AttachInfo because there's no point in invalidating
// if we are not attached to our window
final AttachInfo attachInfo = mAttachInfo;
// The core , The essence is to transfer ViewRootImpl.dispatchInvalidateDelayed Method
if (attachInfo != null) {
attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);
}
}
We continue to watch his luck ViewRootImpl Class dispatchInvalidateDelayed Method , The following source code :
public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
mHandler.sendMessageDelayed(msg, delayMilliseconds);
}
adopt ViewRootImpl Class Handler Sent a MSG_INVALIDATE news , Continuing to track the processing of this message can find :
public void handleMessage(Message msg) {
......
switch (msg.what) {
case MSG_INVALIDATE:
((View) msg.obj).invalidate();
break;
......
}
......
}
handleMessage Running in main thread , So the essence is again UI Thread It's been transferred View Of invalidate(); Method , then View Of invalidate().
requestLayout
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
From this, we can see that the method is changed and continues to call scheduleTraversals()
requestLayout and invalidate What's the difference? ?
We can simply think that mLayoutRequested by true Will trigger perfomMeasure( Internally it will call onMeasure) and performLayout( Internally it will call onLayout). And then in performDraw Inside onDraw In the process of discovery mDirty It's empty , therefore onDraw Will not be called , No redrawing .
So it seems requestLayout Will not lead to onDraw Called ?
Let's continue to recall the setFrame():
protected boolean setFrame(int left, int top, int right, int bottom) {
boolean changed = false;
if (DBG) {
Log.d("View", this + " View.setFrame(" + left + "," + top + ","
+ right + "," + bottom + ")");
}
if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
changed = true;
// Remember our drawn bit
int drawn = mPrivateFlags & PFLAG_DRAWN;
int oldWidth = mRight - mLeft;
int oldHeight = mBottom - mTop;
int newWidth = right - left;
int newHeight = bottom - top;
boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);
// Invalidate our old position
invalidate(sizeChanged);
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;
mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
...
}
We know requestLayout It can lead to perfomMeasure and performLayout, If in layout It was found in the process that l,t,r,b Different from before , Then it will trigger once invalidate. Code in View Of setFrame in , This will be in layout When called . therefore requestLayout Could lead to onDraw Called , It may not lead to onDraw Called , Depending on view Of l,t,r,b Whether to change .
边栏推荐
- Conda 创建,复制,分享虚拟环境
- CSRF attack
- Delete the contents under the specified folder in PHP
- CRP实施方法论
- Message queue fnd in Oracle EBS_ msg_ pub、fnd_ Application of message in pl/sql
- 【MEDICAL】Attend to Medical Ontologies: Content Selection for Clinical Abstractive Summarization
- [Bert, gpt+kg research] collection of papers on the integration of Pretrain model with knowledge
- MySQL无order by的排序规则因素
- ORACLE APEX 21.2安装及一键部署
- 【Torch】最简洁logging使用指南
猜你喜欢
Alpha Beta Pruning in Adversarial Search
[introduction to information retrieval] Chapter 3 fault tolerant retrieval
Oracle 11g uses ords+pljson to implement JSON_ Table effect
ssm人事管理系统
Proteus -- RS-232 dual computer communication
【MEDICAL】Attend to Medical Ontologies: Content Selection for Clinical Abstractive Summarization
ORACLE EBS 和 APEX 集成登录及原理分析
ssm超市订单管理系统
CSRF attack
【信息检索导论】第六章 词项权重及向量空间模型
随机推荐
【调参Tricks】WhiteningBERT: An Easy Unsupervised Sentence Embedding Approach
ssm超市订单管理系统
@Transational踩坑
RMAN incremental recovery example (1) - without unbacked archive logs
Oracle EBS database monitoring -zabbix+zabbix-agent2+orabbix
中年人的认知科普
[introduction to information retrieval] Chapter 7 scoring calculation in search system
JSP intelligent community property management system
TCP attack
实现接口 Interface Iterable&lt;T&gt;
Module not found: Error: Can't resolve './$$_ gendir/app/app. module. ngfactory'
Oracle EBS数据库监控-Zabbix+zabbix-agent2+orabbix
Classloader and parental delegation mechanism
ORACLE EBS中消息队列fnd_msg_pub、fnd_message在PL/SQL中的应用
Oracle rman自动恢复脚本(生产数据向测试迁移)
ORACLE EBS ADI 开发步骤
CSRF attack
【模型蒸馏】TinyBERT: Distilling BERT for Natural Language Understanding
【Torch】最简洁logging使用指南
解决万恶的open failed: ENOENT (No such file or directory)/(Operation not permitted)