SwipeRefreshLayout手动显示刷新动画

来源:互联网 发布:giga365新域名 编辑:程序博客网 时间:2024/06/14 11:22

简述

比如说要服务器取新闻数据,界面将会一个列表形式,支持下拉刷新功能。通常做法都会在进入界面时,把下拉刷新的动画显示出来,数据获取成功后隐藏刷新动画,这样的做法很普遍。然后在Google在supperV4包也添加一个支持下拉刷新控件SwipeRefreshLayout后, 只能说小小惊喜,好不好用自己体会咯。那么今天讲手动调用显示刷新动画。

分析源码

下拉刷新数据完成后调用setRefreshing(false)停止刷新动画,那么是不是参数为true就是显示动画呢?可恶的SwipeRefreshLayout在onCreate()中调用setRefreshing(true)不显示刷新动画,拉门奇怪看看源码吧

    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方法来偏移下拉动画的位置,我们打个断点瞧瞧,额,setRefreshingmCurrentTargetOffsetTop竟然是0

非UI线程列队

但继续断点到setTargetOffsetTopAndBottom中,mCurrentTargetOffsetTop值为192了,既然有值为什么手动调用显示不了动画呢?继续跟踪!发现在onMeasure中值为负数了

Paste_Image.png

来看看onMeasure方法,mCurrentTargetOffsetTop为-140,我去这值肯定是跑到手机屏幕外面显示了,哈哈~都跟到这里了,再跟踪一下吧onLayout

Paste_Image.png

onLayout还调用了动画圆圈控件mCircleView.layout

Paste_Image.png

经过刚才的断点跟踪,源码调用顺序如下:
setRefreshing(boolean refreshing) -> setTargetOffsetTopAndBottom - >onMeasure -> onLayout -> onMeasure -> onLayout
这样看来知道原因了吧,在setTargetOffsetTopAndBottommCurrentTargetOffsetTop是有值的,可后面又执行了onMeasure导致mCurrentTargetOffsetTop为负数

实现方式一

那我们是不是可以这样想,等onLayout绘制个控件的位置完成后,最后执行我们调用的setRefreshing(true)呢?这有点思路了,可以用post(Runnable action)的方法把setRefreshing(true)加入到UI线程列队中,所以用下面代码来试试,惊喜动画有显示了。成功!

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        final SwipeRefreshLayout mSwipeRefreshLayout =                (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);//        mSwipeRefreshLayout.setRefreshing(true);        mSwipeRefreshLayout.post(new Runnable() {            @Override            public void run() {                mSwipeRefreshLayout.setRefreshing(true);            }        });    }

再看断点后执行顺序
onMeasure -> onLayout -> setRefreshing(boolean refreshing) -> setTargetOffsetTopAndBottom -> onMeasure -> onLayout
那么问题来了,后面不还是执行了onMeasure吗?是,是执行了,但关键代码在mOriginalOffsetCalculated这个变量,第一次执行onMeasure后,此变量已经为true,所以第二onMeasure不会进入if分支中,源码如下

Paste_Image.png

实现方式二

正如onMeasure中那段给mCurrentTargetOffsetTop赋值的代码块,如果能让mUsingCustomStart为true的话,那么也能不进入if分支,那么我们就找找mUsingCustomStart在何时有赋值为true的方法,功夫不负有心人,在setProgressViewOffset方法中有,并且看方法名字的意思可以知道,设置进度视图偏移,mSpinnerFinalOffset = end应该是偏移结束位置。

Paste_Image.png

尝试用以下代码试试,果然这样也是成功的

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        final SwipeRefreshLayout mSwipeRefreshLayout =                (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);        mSwipeRefreshLayout.setProgressViewOffset(false, 0, 52);        mSwipeRefreshLayout.setRefreshing(true);//        mSwipeRefreshLayout.post(new Runnable() {//            @Override//            public void run() {//                mSwipeRefreshLayout.setRefreshing(true);//            }//        });    }

总结

二种方式手动显示下拉动画
- UI线程列队

        mSwipeRefreshLayout.post(new Runnable() {        @Override        public void run() {            mSwipeRefreshLayout.setRefreshing(true);        }    });
  • 偏移
mSwipeRefreshLayout.setProgressViewOffset(false, 0, 100);mSwipeRefreshLayout.setRefreshing(true);

最后奉上一个我自己封装的下拉刷新库,封装的不妥地方欢迎提出宝贵意见

我也建了个Q群:435173211,一起交流交流!
这里写图片描述

0 0
原创粉丝点击