以前将这篇稿子发到专题 《Android 开发经验谈》 和 《Android 开发知识》的时候,过了很久,《Android开发知识》审核没通过,《Android开发经验谈》被我自己撤回了。开始没明白原因,重新重新读了下文章,果然有问题,所以重新修改下。
上一次的错误
第一次发稿的时候,错误的将问题指向了view的高度,重新测试发现,当控件为隐藏的时候,高度为0,问题在margin高度
问题:tabLayout会距离上面负几个dp
怀疑:fitSystemWindow 设置的问题
求证:将顶部的元素节点的fitSystemWindow设置为true和false都没有效果,并且距离顶部负的地方在tabLayout显示动态一栏的前面,(开始没想到这点)
定位问题:元素是否滚动是由appBarLayout控制
求证:查看appBarLayout 代码,很容易就发现一段计算滚动范围的代码
/** * Returns the scroll range of all children.
* * @return the scroll range in px */
public final int getTotalScrollRange() {
if (mTotalScrollRange != INVALID_SCROLL_RANGE) {
return mTotalScrollRange;
}
int range = 0;
for (int i = 0, z = getChildCount(); i < z; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int childHeight = child.getMeasuredHeight();
final int flags = lp.mScrollFlags;
if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
// We're set to scroll so add the child's height
range += childHeight + lp.topMargin + lp.bottomMargin;
if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
// For a collapsing scroll, we to take the collapsed height into account.
// We also break straight away since later views can't scroll beneath
// us
range -= ViewCompat.getMinimumHeight(child);
break;
}
} else {
// As soon as a view doesn't have the scroll flag, we end the range calculation.
// This is because views below can not scroll under a fixed view. break;
}
}
return mTotalScrollRange = Math.max(0, range - getTopInset());
}
简单的翻译下:判断当前滚动范围是否=-1,如果是开始往下执行,遍历子元素,获取子元素的高度,判断该元素是否可以滚动,如果可以滚动加上该元素的高度和距离顶部以及底部的高度,如果子元素设置了exitUntilCollapsed,则减去该元素的最小高度。如果没有设置Scroll 则什么都不做
寻找解决方案
我的tab 栏上面的一个元素的确设置了滚动,还设置了距离顶部和底部的Margin,用模拟器debug 到这行发现代码没有判断是否隐藏,并且将margin值加到了range 中,
<code>
childHeight = 0;
lp.topMargin = 39
lp.bottomMargin = 42
</code>
问题就是应该就是margin惹得祸,将margin去掉后,果然好了,另外一种方法,在view上再嵌套一个父元素,在计算高度的时候,没计算子孙元素的margin
代码
为了让大家直观的看到这个错误,这里将问题代码简化后贴出
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
tools:context="wdwd.com.behave.MainActivity">
<!--toolbar-->
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"
android:id="@+id/toolbar" />
<TextView
android:id="@+id/tv_problem_view"
android:layout_width="match_parent"
android:background="@android:color/black"
app:layout_scrollFlags="scroll"
android:layout_marginBottom="10dip"
android:layout_marginTop="40dip"
android:layout_height="wrap_content"
android:text="我是好人"
android:visibility="visible">
</TextView>
<TextView
android:layout_width="match_parent"
android:layout_height="41dip"
android:text="alsdjfalksdfj"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
大家可以试试将tv_problem_view设置为隐藏看看,本来底部停靠的文本还能往上滚动。
其他一些坑
CoordinaLayout的坑还么完,如果直接加Pulltorefresh 的话会出现拉一半就刷新的问题,这个问题网上能搜到解决方案,监听appbarLayoutOffsetChange事件。
coordinatorLayout 的子scrollview必须实现NestedChild,实际使用中发现在部分手机上有问题,结果全换成了recyclerview,webview网上找了段代码,虽然能嵌套滑动,但是没惯性,时间有限没深入研究,希望有知道的同学分享,大家一起进步。
这里捎带提下md的tablayout,因为这期也用到了,md的tablayout很强大,强大在哪里,支持固定宽度,通俗讲显示一屏,加权重,也支持scrollable,超出屏幕滑动,但是用过的肯定知道tablayout不定自定义下面指示器的 红色部分的宽度,我用的是简书里的hackware 大神写的magiclayout。