Android View VISIBLE,INVISIBLE和GONE的区别
首先整理一下View的三种显示的形式,VISIBLE,INVISIBLE和GONE。
/**
* This view is visible.
* Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int VISIBLE = 0x00000000;
/**
* This view is invisible, but it still takes up space for layout purposes.
* Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int INVISIBLE = 0x00000004;
/**
* This view is invisible, and it doesn't take any space for layout
* purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int GONE = 0x00000008;
/**
* Mask for use with setFlags indicating bits used for visibility.
* {@hide}
*/
static final int VISIBILITY_MASK = 0x0000000C;
由上面的官方注释可以看到:
VISIBLE
是让试图可视,通过setVisibility
方法或者android:visibility
标签来进行设置
INVISIBLE
是让试图不可见,但是仍然为布局占据这空间
GONE
是让试图不可见,但是仍然不为布局占据空间
VISIBILITY_MASK
是用来设置是否可见的标签
/**
* Set the visibility state of this view.
*
* @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
* @attr ref android.R.styleable#View_visibility
*/
@RemotableViewMethod
public void setVisibility(@Visibility int visibility) {
setFlags(visibility, VISIBILITY_MASK);
}
接着来看用的比较多的setVisibility
方法:
这个方法就是用来设置View是否可见的。
/**
* 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
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
void setFlags(int flags, int mask) {
final boolean accessibilityEnabled =
AccessibilityManager.getInstance(mContext).isEnabled();
final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility();
// mViewFlags 保存着视图的状态信息。
int old = mViewFlags;
// 在进行标志位的存储时,需要进行一些位运算
mViewFlags = (mViewFlags & ~mask) | (flags & mask);
int changed = mViewFlags ^ old;
// 如果和旧的值相同,则直接return 不做任何变化
if (changed == 0) {
return;
}
......
// 中间还会进行一些其他的位运算存储到mViewFlags当中,比如focus相关的,这里先不予关注
final int newVisibility = flags & VISIBILITY_MASK;
// 首先检查是否是修改为 VISIBLE 属性,如果是,就通知其父类,并且对标志位进行更新
if (newVisibility == VISIBLE) {
if ((changed & VISIBILITY_MASK) != 0) {
/*
* If this view is becoming visible, invalidate it in case it changed while
* it was not visible. Marking it drawn ensures that the invalidation will
* go through.
*/
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.
shouldNotifyFocusableAvailable = hasSize();
}
}
// flag for the view is enabled (ENABLED_MASK)
......
/* Check if the GONE bit has changed */
if ((changed & GONE) != 0) {
// 在这里是处理GONE相关的逻辑,可以看到,在处理GONE时,回去清除焦点以及清理缓存
needGlobalAttributesUpdate(false);
requestLayout();
if (((mViewFlags & VISIBILITY_MASK) == GONE)) {
if (hasFocus()) {
clearFocus();
if (mParent instanceof ViewGroup) {
((ViewGroup) mParent).clearFocusedInCluster();
}
}
clearAccessibilityFocus();
destroyDrawingCache();
if (mParent instanceof View) {
// GONE views noop invalidation, so invalidate the parent
((View) mParent).invalidate(true);
}
// Mark the view drawn to ensure that it gets invalidated properly the next
// time it is visible and gets invalidated
mPrivateFlags |= PFLAG_DRAWN;
}
if (mAttachInfo != null) {
mAttachInfo.mViewVisibilityChanged = true;
}
}
/* Check if the VISIBLE bit has changed */
if ((changed & INVISIBLE) != 0) {
// 如果是INVISIBLE,可以看到对比GONE,并没有清理缓存的操作,这里是不对父类进行焦点清理的操作。
needGlobalAttributesUpdate(false);
/*
* If this view is becoming invisible, set the DRAWN flag so that
* the next invalidate() will not be skipped.
*/
mPrivateFlags |= PFLAG_DRAWN;
if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) {
// root view becoming invisible shouldn't clear focus and accessibility focus
if (getRootView() != this) {
if (hasFocus()) {
clearFocus();
if (mParent instanceof ViewGroup) {
((ViewGroup) mParent).clearFocusedInCluster();
}
}
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 parent = (ViewGroup) mParent;
parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK),
newVisibility);
parent.invalidate(true);
} else if (mParent != null) {
mParent.invalidateChild(this, null);
}
if (mAttachInfo != null) {
dispatchVisibilityChanged(this, newVisibility);
// Aggregated visibility changes are dispatched to attached views
// in visible windows where the parent is currently shown/drawn
// or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot),
// discounting clipping or overlapping. This makes it a good place
// to change animation states.
if (mParent != null && getWindowVisibility() == VISIBLE &&
((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) {
dispatchVisibilityAggregated(newVisibility == VISIBLE);
}
// If this view is invisible from visible, then sending the A11y event by its
// parent which is shown and has the accessibility important.
if ((old & VISIBILITY_MASK) == VISIBLE) {
notifySubtreeAccessibilityStateChangedByParentIfNeeded();
} else {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
}
// 剩下是对于其他标志位的处理,此处省略
......
}
简单整理一下:
标签:GONE,mParent,changed,VISIBLE,INVISIBLE,view From: https://www.cnblogs.com/zhenji-li/p/17068436.htmlView对于
INVISIBLE
和GONE
处理的区别,对于前者,仅仅是将焦点进行清理,并不会删除缓存,也就是常说的不可见,但是保留了布局,而对于后者,进行了焦点和缓存的清除,也就是不会对布局进行保留。