一般情況下,我們都是把 SwipeRefreshLayout 當做需要有刷新功能的父布局使用,類似這樣:
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--content-->
</android.support.v4.widget.NestedScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
在這種情況下, SwipeRefreshLayout 會自動找到子布局,進行刷新判斷等操作,一切正常。但是,最近一直都在使用 ConstraintLayout,并且是否能觸發(fā)下拉刷新需要我設(shè)置 OnChildScrollUpCallback 自己進行判斷。于是乎布局變成了這樣:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="@+id/scroll_view"
app:layout_constraintLeft_toLeftOf="@+id/scroll_view"
app:layout_constraintRight_toRightOf="@+id/scroll_view"
app:layout_constraintTop_toTopOf="@+id/scroll_view"/>
<android.support.v4.widget.NestedScrollView
android:id="@+id/scroll_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<!--content-->
</android.support.v4.widget.NestedScrollView>
</android.support.constraint.ConstraintLayout>
SwipeRefreshLayout 里面沒有了子布局,這樣問題就出現(xiàn)了,會發(fā)現(xiàn)無論如何設(shè)置都不能觸發(fā)下拉刷新動作了。以前有子布局的時候是正常的,現(xiàn)在沒了,難道是這里出了問題?能想到的就是在 SwipeRefreshLayout 里面搜索 getChildAt 方法在什么地方有調(diào)用,調(diào)用來干嘛來。
首先找到的是在 ensureTarget() 中有調(diào)用,源碼如下:
private void ensureTarget() {
// Don't bother getting the parent height if the parent hasn't been laid
// out yet.
if (mTarget == null) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (!child.equals(mCircleView)) {
mTarget = child;
break;
}
}
}
}
這段代碼就是用來確定刷新的子布局,由于我們并沒有設(shè)置子布局,所以 mTarget 在運行完之后應(yīng)該還是 null。
下一段代碼是在 onMeasure 中:
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mTarget == null) {
ensureTarget();
}
if (mTarget == null) {
return;
}
mTarget.measure(MeasureSpec.makeMeasureSpec(
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
mCircleView.measure(MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY));
mCircleViewIndex = -1;
// Get the index of the circleview.
for (int index = 0; index < getChildCount(); index++) {
if (getChildAt(index) == mCircleView) {
mCircleViewIndex = index;
break;
}
}
}
這段代碼使用 getChildAt 是為了確定 mCircleView 的位置,也就是刷新時候的那個圓環(huán)。乍看無關(guān),仔細一看,就發(fā)現(xiàn)了問題所在。在針對 SwipeRefreshLayout 本身做完測量之后,先是確定了 mTarget,要是 mTarget 為 null 的話,就直接返回了。要是不為空,才會對 mCircleView 進行測量操作。也就是說在沒有子布局的情況下,mCircleView 是沒有進行測量的操作的,所以 mCircleView 的 getMeasuredHeight() 和 getMeasuredWidth() 都將返回0,這就導(dǎo)致了刷新小圓圈顯示不出來。
所以在使用 SwipeRefreshLayout 的時候一定要記得給它添加一個子布局。