INVISIBLE、GONE、VISIBLE这三个变量,应该是我们最常用的了,有没有思考系统是怎么实现的呢?
ViewGroup
首先要明确一点,通常使用的View都是放在ViewGroup以及ViewGroup子类的,大小都是在父控件的onMeasure和onLayout来进行确定。我们从最简单的FrameLayout原来来看看,它是怎么实现View的GONE操作的。
onMeasure阶段:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
//判断自己是不是EXACTLY,对应的就是判断自己是不是Match_Parent
final boolean measureMatchParentChildren =
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
mMatchParentChildren.clear();
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
//获取最大宽度与高度
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
//需要测量所有子view||不为GONE时,才需要测量
if (mMeasureAllChildren || child.getVisibility() != GONE) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
maxWidth = Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
maxHeight = Math.max(maxHeight,
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
childState = combineMeasuredStates(childState, child.getMeasuredState());
if (measureMatchParentChildren) {
if (lp.width == LayoutParams.MATCH_PARENT ||
lp.height == LayoutParams.MATCH_PARENT) {
mMatchParentChildren.add(child);
}
}
}
}
//加上pandding
maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
//.....
//设置好FrameLayout的高度和宽度.此时FrameLayout的measureHeight与MeasureWidth已经有值了
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
childState << MEASURED_HEIGHT_STATE_SHIFT));
//.....
}
}
上面的onMeasure其实就做一件事,就是把FrameLayout的maxWidth和maxHeight算出来。在计算时过滤掉mMeasureAllChildren = false是的child是gone的情况,那么问题来了,这个mMeasureAllChildren是做什么的呢?看源码的赋值,我们找到方法
/**
* Sets whether to consider all children, or just those in
* the VISIBLE or INVISIBLE state, when measuring. Defaults to false.
*
* @param measureAll true to consider children marked GONE, false otherwise.
* Default value is false.
*
* @attr ref android.R.styleable#FrameLayout_measureAllChildren
*/
@android.view.RemotableViewMethod
public void setMeasureAllChildren(boolean measureAll) {
mMeasureAllChildren = measureAll;
}
看注释的意思是,当为true时,为GONE的所有children也会被测量。所以,也并不是说GONE了,我们就不会去测量这个child。得是FrameLayout这个measureAllChildren的属性为false时,GONE才不会去测量。为了验证我们的阅读的源码。我写出了以下例子:
假设我们有如下xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:measureAllChildren="true"
android:background="@color/black"
tools:context=".MainActivity">

本文深入探讨了Android中View的可见性控制,包括GONE、INVISIBLE和VISIBLE的实现原理。通过分析FrameLayout的onMeasure和onLayout方法,揭示了GONE如何在测量阶段被过滤以及在布局时不占用空间。同时,详细解释了INVISIBLE在测量阶段与VISIBLE相同,但在布局阶段依然占据位置。通过对View的setVisibility源码分析,理解了如何切换这三个状态并影响视图的绘制和更新。文章强调了自定义ViewGroup时处理GONE事件的重要性,并指出INVISIBLE的控制不在ViewGroup层面,而是在View的可见性设置中完成。
最低0.47元/天 解锁文章
434

被折叠的 条评论
为什么被折叠?



