android SwipeRefreshLayout使用遇到問題分(一)--佈局
阿新 • • 發佈:2019-02-05
1) SwipeRefreshLayout佈局中添多個控制元件時只能顯示一個:
問題程式碼:
這裡我以為將兩個TextView會顯示出來結果只將HelloWorld這個元件顯示出來了<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.zyhust.swiperefreshlayouttest.MainActivity"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="Hello World!" /> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="This is two" /> </android.support.v4.widget.SwipeRefreshLayout>
原因:
這裡主要的原因是SwipeRefreshLayout生成機制引起的。檢視SwipeRefreshLayout的onLayout和onMeasure兩個佈局相關的函式很容易就發現出現這個問題的原因。
onMeasure函式:
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(mCircleWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mCircleHeight, MeasureSpec.EXACTLY)); if (!mUsingCustomStart && !mOriginalOffsetCalculated) { mOriginalOffsetCalculated = true; mCurrentTargetOffsetTop = mOriginalOffsetTop = -mCircleView.getMeasuredHeight(); } mCircleViewIndex = -1; // Get the index of the circleview. for (int index = 0; index < getChildCount(); index++) { if (getChildAt(index) == mCircleView) { mCircleViewIndex = index; break; } } }
onLayout函式:
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { final int width = getMeasuredWidth(); final int height = getMeasuredHeight(); if (getChildCount() == 0) { return; } if (mTarget == null) { ensureTarget(); } if (mTarget == null) { return; } final View child = mTarget; final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); final int childWidth = width - getPaddingLeft() - getPaddingRight(); final int childHeight = height - getPaddingTop() - getPaddingBottom(); child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); int circleWidth = mCircleView.getMeasuredWidth(); int circleHeight = mCircleView.getMeasuredHeight(); mCircleView.layout((width / 2 - circleWidth / 2), mCurrentTargetOffsetTop, (width / 2 + circleWidth / 2), mCurrentTargetOffsetTop + circleHeight); }
由上面可以看出SwipeRefreshLayout佈局中的測量和佈局只對mTarget和mCircleView進行操作。mCircleView容易理解就是重新整理是顯示的ProgressBar了。那麼主要就是mTarget了。mTarget的獲取是通過ensureTarget得到的,通過檢視這個函式可以明白mTarget是什麼:
ensureTarget函式:
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;
}
}
}
}
通過這個函式可以知道mTarget就是在SwipeRefreshLayout中不為mCircleView的第一個檢視控制元件,這也就解釋了為啥只有HelloWorld這個TextView顯示出來了的原因了