Android——调用SwipeRefreshLayout.setRefreshing(true),刷新指示器不显示

引言

前段时间在网上又看到小伙伴提出SwipeRefreshLayout的指示器不能显示的问题,该问题的出现情景是在Activity或者Fragmen的onCreate方法中直接调用SwipeRefreshLayout.setRefreshing(true)。

其实这个问题我在14年底的时候就遇到过了,后来在android issues上找到解决方案。本来不想写,后来想想时间过去两年了,Google还没对这个bug进行fix,那倒不如根据那个android issues做一个整理帮助更多未找到原因和解决方案的小伙伴们。

原因

在SwipeRefreshLayout.onMeasure()之前,调用SwipeRefreshLayout.setRefreshing(true)。

解决方案

  • 很简单,那就是在SwipeRefreshLayout.onMeasure()之后,调用SwipeRefreshLayout.setRefreshing(true)。
  • 我把解决方案按照调用方式简单的分为两类:主调和回调。

主调

Handler延迟时间执行,这个方案不好,因为延迟时间很难有一个准确数据,确保在任何机器上都是可行和完美的。

handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        initiateRefresh();
    }
}, 1000); // 时间可以按自己需要设,不一定是1秒

感谢无奈的冻鱼提供的意见,使用Handler.post(runnable)。 那么为什么Handler.post(runnable)比较好呢?

原因非常简单,因为activity的onCreate()生命周期方法在调用setContentVIew()后,UI消息队列会包含绘制view的消息(view的绘制流程——measure,layout,draw),而UI消息队列又是按顺序执行的,所以这时候handler.post发出的消息会后执行,因此就相当于在view绘制完成后执行

通过设置指示器的偏移间接地调用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()就是由此触发
}

回调

重写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;
    }
}

监听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);
            }
        }
    }

好消息

经过两年的时间后,该issues终于反馈到Android开发团队:


屏幕快照 2016-03-03 17.11.29.png

你可能感兴趣的:(Android——调用SwipeRefreshLayout.setRefreshing(true),刷新指示器不显示)