@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方法的一些了解就到这里啦,期待下一篇博文吧