国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

requestlayout,onlayout,onDraw,invalidate區別與聯系

2019-11-09 18:45:28
字體:
來源:轉載
供稿:網友

invalidate

流程圖: 流程圖

11764 void More ...invalidate(boolean invalidateCache) {11765 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);11766 }void More ...invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,11769 boolean fullInvalidate) {11770 if (mGhostView != null) {11771 mGhostView.invalidate(true);11772 return;11773 }1177411775 if (skipInvalidate()) {11776 return;11777 }1177811779 if ((mPRivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)11780 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)11781 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED11782 || (fullInvalidate && isOpaque() != mLastIsOpaque)) {11783 if (fullInvalidate) {11784 mLastIsOpaque = isOpaque();11785 mPrivateFlags &= ~PFLAG_DRAWN;11786 }1178711788 mPrivateFlags |= PFLAG_DIRTY;1178911790 if (invalidateCache) {11791 mPrivateFlags |= PFLAG_INVALIDATED;11792 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;11793 }1179411795 // Propagate the damage rectangle to the parent view.11796 final AttachInfo ai = mAttachInfo;11797 final ViewParent p = mParent;11798 if (p != null && ai != null && l < r && t < b) {11799 final Rect damage = ai.mTmpInvalRect;11800 damage.set(l, t, r, b);11801 p.invalidateChild(this, damage);11802 }1180311804 // Damage the entire projection receiver, if necessary.11805 if (mBackground != null && mBackground.isProjected()) {11806 final View receiver = getProjectionReceiver();11807 if (receiver != null) {11808 receiver.damageInParent();11809 }11810 }1181111812 // Damage the entire IsolatedZVolume receiving this view's shadow.11813 if (isHardwareAccelerated() && getZ() != 0) {11814 damageShadowReceiver();11815 }11816 }11817 }

如上面源碼所示,View的invalidate會調到invalidateInternal,里面會設置2個標志位PFLAG_INVALIDATED和PFLAG_DRAWING_CACHE_VALID,PFLAG_INVALIDATED置為1,PFLAG_DRAWING_CACHE_VALID置為0. 并且11801行調用invalidateChild()。

ViewGroup中的invalidateChild方法:

public final void More ...invalidateChild(View child, final Rect dirty) {4609 ViewParent parent = this;46104611 final AttachInfo attachInfo = mAttachInfo;4612 if (attachInfo != null) {4613 // If the child is drawing an animation, we want to copy this flag onto4614 // ourselves and the parent to make sure the invalidate request goes4615 // through4616 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION)4617 == PFLAG_DRAW_ANIMATION;46184619 // Check whether the child that requests the invalidate is fully opaque4620 // Views being animated or transformed are not considered opaque because we may4621 // be invalidating their old position and need the parent to paint behind them.4622 Matrix childMatrix = child.getMatrix();4623 final boolean isOpaque = child.isOpaque() && !drawAnimation &&4624 child.getAnimation() == null && childMatrix.isIdentity();4625 // Mark the child as dirty, using the appropriate flag4626 // Make sure we do not set both flags at the same time4627 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;46284629 if (child.mLayerType != LAYER_TYPE_NONE) {4630 mPrivateFlags |= PFLAG_INVALIDATED;4631 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;4632 }46334634 final int[] location = attachInfo.mInvalidateChildLocation;4635 location[CHILD_LEFT_INDEX] = child.mLeft;4636 location[CHILD_TOP_INDEX] = child.mTop;4637 if (!childMatrix.isIdentity() ||4638 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {4639 RectF boundingRect = attachInfo.mTmpTransformRect;4640 boundingRect.set(dirty);4641 Matrix transformMatrix;4642 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {4643 Transformation t = attachInfo.mTmpTransformation;4644 boolean transformed = getChildStaticTransformation(child, t);4645 if (transformed) {4646 transformMatrix = attachInfo.mTmpMatrix;4647 transformMatrix.set(t.getMatrix());4648 if (!childMatrix.isIdentity()) {4649 transformMatrix.preConcat(childMatrix);4650 }4651 } else {4652 transformMatrix = childMatrix;4653 }4654 } else {4655 transformMatrix = childMatrix;4656 }4657 transformMatrix.mapRect(boundingRect);4658 dirty.set((int) (boundingRect.left - 0.5f),4659 (int) (boundingRect.top - 0.5f),4660 (int) (boundingRect.right + 0.5f),4661 (int) (boundingRect.bottom + 0.5f));4662 }46634664 do {4665 View view = null;4666 if (parent instanceof View) {4667 view = (View) parent;4668 }46694670 if (drawAnimation) {4671 if (view != null) {4672 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;4673 } else if (parent instanceof ViewRootImpl) {4674 ((ViewRootImpl) parent).mIsAnimating = true;4675 }4676 }46774678 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque4679 // flag coming from the child that initiated the invalidate4680 if (view != null) {4681 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&4682 view.getSolidColor() == 0) {4683 opaqueFlag = PFLAG_DIRTY;4684 }4685 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {4686 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;4687 }4688 }46894690 parent = parent.invalidateChildInParent(location, dirty);4691 if (view != null) {4692 // Account for transform on current parent4693 Matrix m = view.getMatrix();4694 if (!m.isIdentity()) {4695 RectF boundingRect = attachInfo.mTmpTransformRect;4696 boundingRect.set(dirty);4697 m.mapRect(boundingRect);4698 dirty.set((int) (boundingRect.left - 0.5f),4699 (int) (boundingRect.top - 0.5f),4700 (int) (boundingRect.right + 0.5f),4701 (int) (boundingRect.bottom + 0.5f));4702 }4703 }4704 } while (parent != null);4705 }4706 }

可以看到invalidateChild內部有個dowhile循環,不停調用父view的invalidateChildInParent,一直到調用ViewRootImpl的invalidateChildInParent。我們看invalidateChild的L21,把PFLAG_DRAWING_CACHE_VALID置為0,在dowhile循環后,當前view的所有父view,父view的父view。。。都會被PFLAG_DRAWING_CACHE_VALID置為0.調用invalidateChildInParent會傳進去一個Rect叫dirty,代表子窗口需要刷新的rect,父窗口會根據這個rect和父窗口本身做union,從而得到父窗口需要刷新的rect區域,然后再傳給父窗口的父窗口,一直遞歸直到ViewRootImpl。

908 public ViewParent More ...invalidateChildInParent(int[] location, Rect dirty) {909 checkThread();910 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);911 912 if (dirty == null) {913 invalidate();914 return null;915 } else if (dirty.isEmpty() && !mIsAnimating) {916 return null;917 }918 919 if (mCurScrollY != 0 || mTranslator != null) {920 mTempRect.set(dirty);921 dirty = mTempRect;922 if (mCurScrollY != 0) {923 dirty.offset(0, -mCurScrollY);924 }925 if (mTranslator != null) {926 mTranslator.translateRectInAppWindowToScreen(dirty);927 }928 if (mAttachInfo.mScalingRequired) {929 dirty.inset(-1, -1);930 }931 }932 933 final Rect localDirty = mDirty;934 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {935 mAttachInfo.mSetIgnoreDirtyState = true;936 mAttachInfo.mIgnoreDirtyState = true;937 }938 939 // Add the new dirty rect to the current one940 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);941 // Intersect with the bounds of the window to skip942 // updates that lie outside of the visible region943 final float appScale = mAttachInfo.mapplicationScale;944 final boolean intersected = localDirty.intersect(0, 0,945 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));946 if (!intersected) {947 localDirty.setEmpty();948 }949 if (!mWillDrawSoon && (intersected || mIsAnimating)) {950 scheduleTraversals();951 }952 953 return null;954 }

再來看ViewRootImpl的invalidateChildInParent,這個ViewRootImpl類的invalidateChildInParent方法直接返回了null,也就是上面ViewGroup中說的,層層上級傳遞到ViewRootImpl的invalidateChildInParent方法結束了那個do while循環。這里重點是調用scheduleTraversals,scheduleTraversals會通過Handler的Runnable發送一個異步消息,調用doTraversal方法,然后最終調用performTraversals()執行重繪。performTraversals就是整個View數開始繪制的起始調用地方,所以說View調運invalidate方法的實質是層層上傳到父級,直到傳遞到ViewRootImpl后觸發了scheduleTraversals方法,然后整個View樹開始重新按照View繪制流程進行重繪任務。

requestLayout.

872 public void More ...requestLayout() {873 if (!mHandlingLayoutInLayoutRequest) {874 checkThread();875 mLayoutRequested = true;876 scheduleTraversals();877 }878 }

以上就是ViewRootImpl的requestLayout方法,可以看到mLayoutRequested變true了,然后觸發了scheduleTraversals 方法,requestLayout與invalidate的調用過程類似,只是設置的標志位不同,導致View的繪制流程中執行方法不同而已。

我們可以簡單的認為mLayoutRequested為true會觸發perfomMeasure(內部會調用onMeasure)和performLayout(內部會調用onLayout)。然后在performDraw內部draw的過程中發現mDirty為空,所以onDraw不會被調用,不重繪。 這么看來requestLayout不會導致onDraw調用了?

也不見得,我們知道requestLayout會導致perfomMeasure和performLayout,如果在layout過程中發現l,t,r,b和以前不一樣,那就會觸發一次invalidate。代碼在View的setFrame中,這個會在layout時被調用。

requestLayout是否會導致全部View都觸發Layout和measure?

一個view調用了requestLayout,那么他自己與他的父族view都會被設置為PFLAG_FORCE_LAYOUT,我們在看看measure過程,measure的核心代碼處必須滿足3個條件之一,而他自己與他的父族view都會被設置為PFLAG_FORCE_LAYOUT,所以他們都必然會被重新measure,但是其他的view就不一定了,就看這3個條件是否會滿足。 結論是requestLayout會導致部分view重新measure和layout。a的requestLayout必然會導致a,ap…的重新measure,ap的requestLayout必定會導致ap的measure,但不一定會導致a的measure。 tip: 因為onMeasure后會設置了PFLAG_LAYOUT_REQUIRED標志位,這會導致調用onLayout。

總結:

requestLayout()方法會調用measure過程和layout過程,不會調用draw過程,也不會重新繪制任何View包括該調用者本身 invalidate系列方法請求重繪View樹(也就是draw方法),在performTraversals方法中,mLayoutRequested為false,所有onMeasure和onLayout都不會被調用。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 揭西县| 尤溪县| 富锦市| SHOW| 桃园市| 稷山县| 秀山| 静宁县| 临沭县| 定边县| 虹口区| 江西省| 藁城市| 河东区| 玉林市| 万山特区| 长丰县| 云林县| 商城县| 宾阳县| 龙里县| 常熟市| 峨眉山市| 淅川县| 房产| 格尔木市| 阳朔县| 团风县| 桑植县| 松潘县| 两当县| 开封县| 平阳县| 乐陵市| 台东县| 泰宁县| 静安区| 孟州市| 黑山县| 介休市| 长治县|