@RemotableViewMethod
public void setVisibility(@Visibility int visibility) {
setFlags(visibility, VISIBILITY_MASK);
}
public void setFocusable(boolean focusable) {
if (!focusable) {
setFlags(0, FOCUSABLE_IN_TOUCH_MODE);
}
setFlags(focusable ? FOCUSABLE : NOT_FOCUSABLE, FOCUSABLE_MASK);
}
public void setEnabled(boolean enabled) {
if (enabled == isEnabled()) return;
setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK);
/*
* The View most likely has to change its appearance, so refresh
* the drawable state.
視圖大多數可能改變它的樣子,是以重新整理drawable的狀态
*/
refreshDrawableState();
// Invalidate too, since the default behavior for views is to be
// be drawn at 50% alpha rather than to change the drawable.
//同時也要重新整理,因為預設的View enable為false的行為是透明度為原來的50%而不是改變drawable
invalidate(true);
if (!enabled) {
cancelPendingInputEvents();
}
}
/**
* Set flags controlling behavior of this view.
*設定标記來控制視圖的狀态
*
* @param flags Constant indicating the value which should be set 表示應該要被設定的值常量
* @param mask Constant indicating the bit range that should be changed 表示應該要被改變的位的常量
*/
該函數在View中多處被調用,例如 View.setEnable()、View.setClickable(),setFocusable()等很多函數都調用到該函數。
在View中使用mViewFlags和mPrivateFlags變量儲存大多數的屬性:
– mViewFlags:該标記用來儲存和視圖狀态相關的屬性。
– mPrivateFlags 該标記用來儲存和内部邏輯相關的屬性
如Visible相關的Flag:
public static final int VISIBLE = 0x00000000;
public static final int INVISIBLE = 0x00000004;
public static final int GONE = 0x00000008;
static final int VISIBILITY_MASK = 0x0000000C;
void setFlags(int flags, int mask) { final boolean accessibilityEnabled = AccessibilityManager.getInstance(mContext).isEnabled(); final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility();
int old = mViewFlags;//記錄原來的視圖狀态标記 mViewFlags = (mViewFlags & ~mask) | (flags & mask);//更新視圖狀态标記
int changed = mViewFlags ^ old;//異或判斷狀态是否發生改變 if (changed == 0) {//如果沒有改變,立刻傳回 return; } int privateFlags = mPrivateFlags;//記錄目前邏輯屬性标記
檢查Focusable位有沒有改變 if (((changed & FOCUSABLE_MASK) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) !=0)) { if (((old & FOCUSABLE_MASK) == FOCUSABLE) && ((privateFlags & PFLAG_FOCUSED) != 0)) { 如果不再是focusable清空焦點。 clearFocus(); } else if (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE) && ((privateFlags & PFLAG_FOCUSED) == 0)) { if (mParent != null) mParent.focusableViewAvailable(this); } }
final int newVisibility = flags & VISIBILITY_MASK; if (newVisibility == VISIBLE) { if ((changed & VISIBILITY_MASK) != 0) { mPrivateFlags |= PFLAG_DRAWN; invalidate(true);
needGlobalAttributesUpdate(true);
// a view becoming visible is worth notifying the parent // about in case nothing has focus. even if this specific view // isn't focusable, it may contain something that is, so let // the root view try to give this focus if nothing else does. 一個視圖将要變成可見的值得通知父控件假設沒有東西有焦點。即使指定的視圖不是 可擷取焦點的,它可能包含了一些能擷取焦點的,是以讓根視圖嘗試讓其擷取焦點。 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) {//可見需要擷取焦點 mParent.focusableViewAvailable(this); } } }
檢查GONE标志位是否發生改變 if ((changed & GONE) != 0) { needGlobalAttributesUpdate(false); requestLayout();//如果Gone的标志位發生了改變,必然會請求重新Layout
if (((mViewFlags & VISIBILITY_MASK) == GONE)) { if (hasFocus()) clearFocus();//如果變為gone,且目前是有焦點的,清除焦點 clearAccessibilityFocus();//清除可達的焦點 destroyDrawingCache(); if (mParent instanceof View) { // GONE views noop invalidation, so invalidate the parent ((View) mParent).invalidate(true);//Gone的View不需要重新整理,是以重新整理它的父控件。 } // Mark the view drawn to ensure that it gets invalidated properly the next // time it is visible and gets invalidated 設定DRAWN标記保證其正确地得到重新整理下次為可見并且重新整理的時候 mPrivateFlags |= PFLAG_DRAWN; } if (mAttachInfo != null) { mAttachInfo.mViewVisibilityChanged = true; } }
if ((changed & INVISIBLE) != 0) { needGlobalAttributesUpdate(false); mPrivateFlags |= PFLAG_DRAWN; = 0x00000020;
if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { // root view becoming invisible shouldn't clear focus and accessibility focus 如果這是根視圖的話,不應該清除焦點和可達的焦點。 if (getRootView() != this) { if (hasFocus()) clearFocus(); clearAccessibilityFocus(); } } if (mAttachInfo != null) { mAttachInfo.mViewVisibilityChanged = true; } }
if ((changed & VISIBILITY_MASK) != 0) { // If the view is invisible, cleanup its display list to free up resources 如果視圖不可見,清除它的顯示清單以釋放資源 if (newVisibility != VISIBLE && mAttachInfo != null) { cleanupDraw(); }
if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), newVisibility);//回調可見性發生變化 ((View) mParent).invalidate(true); } else if (mParent != null) { mParent.invalidateChild(this, null); }
if (mAttachInfo != null) { dispatchVisibilityChanged(this, newVisibility);//分發可見性發生變化 notifySubtreeAccessibilityStateChangedIfNeeded(); } }
if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { destroyDrawingCache(); }
if ((changed & DRAWING_CACHE_ENABLED) != 0) { destroyDrawingCache(); mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; invalidateParentCaches(); }
if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { destroyDrawingCache(); mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; } static final int DRAW_MASK = 0x00000080;16*8=128---10000000 if ((changed & DRAW_MASK) != 0) {//檢查DRAW_MASK标志位是否發生改變 if ((mViewFlags & WILL_NOT_DRAW) != 0) { if (mBackground != null || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { mPrivateFlags &= ~PFLAG_SKIP_DRAW; } else { mPrivateFlags |= PFLAG_SKIP_DRAW; } } else { mPrivateFlags &= ~PFLAG_SKIP_DRAW; } requestLayout();//這裡也會重新請求Layout,如果draw_mask标志位發生了改變,也會重新Layout invalidate(true); }
if ((changed & KEEP_SCREEN_ON) != 0) { if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { mParent.recomputeViewAttributes(this); } }
if (accessibilityEnabled) { //focus,visibilty,click,longclick,contextClick if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 || (changed & CONTEXT_CLICKABLE) != 0) { if (oldIncludeForAccessibility != includeForAccessibility()) { notifySubtreeAccessibilityStateChangedIfNeeded();// Notifies that the accessibility state of this view changed. } else { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } else if ((changed & ENABLED_MASK) != 0) { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } }
總結一下: ①View的許多關于屬性的set方法,内部都會調用setFlag方法,來通過Flag标志控制View的行為。其中: mViewFlags:該标記用來儲存和視圖狀态相關的屬性。 mPrivateFlags 該标記用來儲存和内部邏輯相關的屬性 ②View的可見性變為Gone的時候,都會調用requestLayout方法,請求parent重新measure和Layout。 ③此外,如果DRAW_MASK标志位發生了改變,也會調用requestLayout方法和invalidate方法來重新整理。 ④可見性發生變化的時候,會設定PFLAG_DRAWN标志來確定重新整理的時候得到重繪。
⑤如果視圖不可見,清除它的顯示清單以釋放資源,調用cleanupDraw()方法。
今天,關于setFlag方法的一些了解就到這裡啦,期待下一篇博文吧