美文网首页Android 踩坑记Android知识Android技术知识
那些年我们踩过的坑-SwipeRefreshLayout

那些年我们踩过的坑-SwipeRefreshLayout

作者: Liuuuuuuzi | 来源:发表于2016-10-27 23:37 被阅读1708次

    SwipeRefreshLayout 作为google提供的刷新库,相当简单实用,然而却也存在着问题,本文将简单讲述一下 SwipeRefreshLayout 的使用,和 使用过程中出现的问题及其解决方案,重点 谈谈 SwipeRefreshLayout 出现问题的原因。

    简单使用

    <com.nanke.cook.view.AutoSwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white">
    
        <com.kevin.wraprecyclerview.WrapRecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/recycleView"
            android:padding="4dp"
            />
    
    </com.nanke.cook.view.AutoSwipeRefreshLayout>t>
    
    

    出现的问题:在刚进入到界面的时候需要显示刷新进度条,通过直接设置setRefreshing(true); 没有效果, 并没有显示

    原因分析:

    日志

    由日志可以看出,在onMeasure 绘制之前,就调用了 setRefreshing,而在activity获取焦点过后,即onResume执行完毕后,View才会相应地调用onMeasure测量自身的大小,再来看 setRefreshing(boolean refreshing) 的源码:

        public void setRefreshing(boolean refreshing) {
            if (refreshing && mRefreshing != refreshing) {
                // scale and show
                mRefreshing = refreshing;
                int endTarget = 0;
                if (!mUsingCustomStart) {
                    endTarget = (int) (mSpinnerFinalOffset + mOriginalOffsetTop);
                } else {
                    endTarget = (int) mSpinnerFinalOffset;
                }
              //设置 显示刷新进度条的位置
                setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop,
                        true /* requires update */);
                mNotify = false;
                startScaleUpAnimation(mRefreshListener);
            } else {
                setRefreshing(refreshing, false /* notify */);
            }
        }
    

    由上面可以看出,主要通过 setTargetOffsetTopAndBottom 来确定所要显示的位置,接着来看一下 setTargetOffsetTopAndBottom 的实现:

    private void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) {
            mCircleView.bringToFront();
            mCircleView.offsetTopAndBottom(offset);
            mCurrentTargetOffsetTop = mCircleView.getTop();
            if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) {
                invalidate();
            }
        }
    

    可以看到,只是对 mCircleView 的属性进行设置,并没有主动调用 invalidate 去绘制,只有当 sdk<11时,做了调用。
    所以也就很好理解,我们在还没有绘制之前,就设置显示刷新进度条,显示的位置都还没有确定,当然就不会显示了。

    下面分析一下,网上出现的几种解决方案

    方案一

    refresh.setProgressViewOffset(false, 0, CommonUtil.dip2px(context, 24));
    refresh.setRefreshing(true);
    

    通过 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();
        }
    

    在 setProgressViewOffset 中 ,最终 执行了mCircleView.invalidate(),去主动绘制。

    方案二

    mSwipeRefreshLayout.post(new Runnable() {
                   
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(true);
            }
        });
    

    通过post(Runnable runnable)方法放到UI线程排队执行。

    总结

    总结一下解决方法,就是在 SwipeRefreshLayout.onMeasure()之后,调用SwipeRefreshLayout.setRefreshing(true) 就好了。 总的来说,从这个问题可以看出,在Activity的生命周期以及 View的生命周期 ,它们是相互影响的,通过SwipeRefreshLayout出现的问题,也可以更好的理解它们之间的关系。

    上面的分析也只是我个人的理解,如果有什么不对的地方,希望大家能指出,多多指教。

    相关文章

      网友评论

        本文标题:那些年我们踩过的坑-SwipeRefreshLayout

        本文链接:https://www.haomeiwen.com/subject/ueysuttx.html