引言
前段時(shí)間在網(wǎng)上又看到小伙伴提出SwipeRefreshLayout的指示器不能顯示的問(wèn)題,該問(wèn)題的出現(xiàn)情景是在Activity或者Fragmen的onCreate方法中直接調(diào)用SwipeRefreshLayout.setRefreshing(true)。
其實(shí)這個(gè)問(wèn)題我在14年底的時(shí)候就遇到過(guò)了,后來(lái)在android issues上找到解決方案。本來(lái)不想寫,后來(lái)想想時(shí)間過(guò)去兩年了,Google還沒對(duì)這個(gè)bug進(jìn)行fix,那倒不如根據(jù)那個(gè)android issues做一個(gè)整理幫助更多未找到原因和解決方案的小伙伴們。
原因
在SwipeRefreshLayout.onMeasure()之前,調(diào)用SwipeRefreshLayout.setRefreshing(true)。
解決方案
- 很簡(jiǎn)單,那就是在SwipeRefreshLayout.onMeasure()之后,調(diào)用SwipeRefreshLayout.setRefreshing(true)。
- 我把解決方案按照調(diào)用方式簡(jiǎn)單的分為兩類:主調(diào)和回調(diào)。
主調(diào)
Handler延遲時(shí)間執(zhí)行,這個(gè)方案不好,因?yàn)檠舆t時(shí)間很難有一個(gè)準(zhǔn)確數(shù)據(jù),確保在任何機(jī)器上都是可行和完美的。
handler.postDelayed(new Runnable() {
@Override
public void run() {
initiateRefresh();
}
}, 1000); // 時(shí)間可以按自己需要設(shè),不一定是1秒
感謝無(wú)奈的凍魚提供的意見,使用Handler.post(runnable)。 那么為什么Handler.post(runnable)比較好呢?
原因非常簡(jiǎn)單,因?yàn)閍ctivity的onCreate()生命周期方法在調(diào)用setContentVIew()后,UI消息隊(duì)列會(huì)包含繪制view的消息(view的繪制流程——measure,layout,draw),而UI消息隊(duì)列又是按順序執(zhí)行的,所以這時(shí)候handler.post發(fā)出的消息會(huì)后執(zhí)行,因此就相當(dāng)于在view繪制完成后執(zhí)行
通過(guò)設(shè)置指示器的偏移間接地調(diào)用onMeasure():
TypedValue typed_value = new TypedValue();
getTheme().resolveAttribute(android.support.v7.appcompat.R.attr.actionBarSize, typed_value, true);
swipeRefreshLayout.setProgressViewOffset(false, 0, getResources().getDimensionPixelSize(typed_value.resourceId));
SwipeRefreshLayout.setProgressViewOffset()源碼:
public void setProgressViewOffset(boolean scale, int start, int end) {
mScale = scale;
mCircleView.setVisibility(View.GONE);
mOriginalOffsetTop = mCurrentTargetOffsetTop = start;
mSpinnerFinalOffset = end;
mUsingCustomStart = true;
mCircleView.invalidate();// onMeasure()就是由此觸發(fā)
}
回調(diào)
重寫SwipeRefreshLayout的onMeasure()和setRefreshing():
private boolean mMeasured = false;
private boolean mPreMeasureRefreshing = false;
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!mMeasured) {
mMeasured = true;
setRefreshing(mPreMeasureRefreshing);
}
}
@Override
public void setRefreshing(boolean refreshing) {
if (mMeasured) {
super.setRefreshing(refreshing);
} else {
mPreMeasureRefreshing = refreshing;
}
}
監(jiān)聽OnGlobalLayoutListener:
private class OnLayoutReadyListener implements OnGlobalLayoutListener {
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
if (!mLayoutReady) {
mLayoutReady = true;
setRefreshing(mPreLayoutReadyRefreshing);
}
}
}
好消息
經(jīng)過(guò)兩年的時(shí)間后,該issues終于反饋到Android開發(fā)團(tuán)隊(duì):
