前言
此场景为 NestedScrollView 嵌套多个布局 ,大致结构为 NestedScrollView+TabLayout+ViewPager+fragment +其它View,如下图 ,
一、ViewPager 设置高度才会显示内容问题
原因:NestedScrollView 计算高度先于 ViewPager 渲染前,所以 ViewPager 的高度才会一直是0,所以设定高度才会显示,但这不符合实际开发需求,实际开发需要根据子布局的高度填充内容,一般 ViewPager 的高度为 wrap_content,所以此时设置 NestedScrollView 的fillViewport 属性 android:fillViewport="true"
<android.support.v4.widget.NestedScrollView
android:fillViewport="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v4.widget.NestedScrollView>
二、其它View 超出屏幕不显示问题
但是设置 android:fillViewport="true" 后发现 其它View 不显示了 ,这是因为该属性它用于在ScrollView
中填充视图的高度,以便在内容不足以填满屏幕时也能填充整个屏幕。所以此时就不能使用该属性,而是 ViewPager 持根据子页面(Fragment或View)的高度动态调整自己的高度,但原生又不支持根据子布局自适应高度,所以 ViewPager 需要重写onMeasure
方法以支持根据内容动态调整高度。
public class DynamicHeightViewPager extends ViewPager {
public DynamicHeightViewPager(Context context) {
super(context);
}
public DynamicHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
(int) Math.max(height, child.getMeasuredHeight()), MeasureSpec.UNSPECIFIED));
height = Math.max(height, child.getMeasuredHeight());
}
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
height, MeasureSpec.EXACTLY));
}
}
在 onMeasure 方法中 首先,它遍历所有子视图(即ViewPager中将要显示的页面),对于每个子视图,它尝试测量其高度,但这里有一个逻辑上的小错误。在第一次调用child.measure
时,child.getMeasuredHeight()
很可能为0,因为子视图还没有被真正测量过。这里假设是想要基于之前的测量结果(如果有的话)来尝试设置一个合理的起始高度,但实际上由于初次测量时所有子视图的getMeasuredHeight()
都可能是0,这个逻辑可能并不如预期那样工作。一个更稳妥的做法是直接给子视图一个较大的初始高度或完全不受限制的高度(如MeasureSpec.UNSPECIFIED
),然后根据实际需要调整。然后,它更新height
变量为当前找到的最大子视图高度。最后,它使用找到的最大高度作为ViewPager的高度,并调用super.onMeasure
来设置最终的测量规格,
在布局中直接替换 ViewPager 即可,
总结
如果对你有所帮助的话,不妨 点赞收藏
如果你有什么疑问的话,不妨 评论私信
青山不改,绿水长流 ,有缘江湖再见 ~