首页 > 其他分享 >Android View VISIBLE,INVISIBLE和GONE的区别

Android View VISIBLE,INVISIBLE和GONE的区别

时间:2023-01-27 00:22:06浏览次数:42  
标签:GONE mParent changed VISIBLE INVISIBLE view

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();
            }
        }
    }

    // 剩下是对于其他标志位的处理,此处省略
    ......
}

简单整理一下:

View对于INVISIBLEGONE处理的区别,对于前者,仅仅是将焦点进行清理,并不会删除缓存,也就是常说的不可见,但是保留了布局,而对于后者,进行了焦点和缓存的清除,也就是不会对布局进行保留。

标签:GONE,mParent,changed,VISIBLE,INVISIBLE,view
From: https://www.cnblogs.com/zhenji-li/p/17068436.html

相关文章