TwinklingRefreshLayout 小而强大的刷新控件,自带顺滑的越界回弹,v1.04 版精心重构,完美发布啦!

TwinklingRefreshLayout v1.04 版精心重构,优化 UI、刷新及越界动画效果,修复众多 bug,完美发布!

TwinklingRefreshLayout延伸了Google的SwipeRefreshLayout的思想,不在列表控件上动刀,而是使用一个ViewGroup来包含列表控件,以保持其较低的耦合性和较高的通用性。其主要特性有:

  1. 支持RecyclerView、ScrollView、AbsListView系列(ListView、GridView)、WebView以及其它可以获取到scrollY的控件
  2. 支持加载更多
  3. 默认支持 越界回弹,随手势速度有不同的效果
  4. 可开启没有刷新控件的纯净越界回弹模式
  5. setOnRefreshListener中拥有大量可以回调的方法
  6. 将Header和Footer抽象成了接口,并回调了滑动过程中的系数,方便实现个性化的Header和Footer

Demo

下载Demo

    

You can download the Video for more details.

使用方法

1.添加gradle依赖

将libray模块复制到项目中,或者直接在build.gradle中依赖:

compile ‘com.lcodecorex:tkrefreshlayout:1.0.4‘

2.在xml中添加TwinklingRefreshLayout

<?xml version="1.0" encoding="utf-8"?>
<com.lcodecore.tkrefreshlayout.TwinklingRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/refreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:tr_wave_height="180dp"
    app:tr_head_height="100dp">

    <android.support.v7.widget.RecyclerView        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:overScrollMode="never"
        android:background="#fff" />
</com.lcodecore.library.TwinklingRefreshLayout>

Android系统为了跟iOS不一样,当界面OverScroll的时候会显示一个阴影。为了达到更好的显示效果,最好禁用系统的overScroll,如上给RecyclerView添加android:overScrollMode="never"

3.在Activity或者Fragment中配置

TwinklingRefreshLayout不会自动结束刷新或者加载更多,需要手动控制
refreshLayout.setOnRefreshListener(new RefreshListenerAdapter(){            @Override
            public void onRefresh(final TwinklingRefreshLayout refreshLayout) {                new Handler().postDelayed(new Runnable() {                    @Override
                    public void run() {
                        refreshLayout.finishRefreshing();
                    }
                },2000);
            }            @Override
            public void onLoadMore(final TwinklingRefreshLayout refreshLayout) {                new Handler().postDelayed(new Runnable() {                    @Override
                    public void run() {
                        refreshLayout.finishLoadmore();
                    }
                },2000);
            }
        });
    }

使用finishRefreshing()方法结束刷新,finishLoadmore()方法结束加载更多。此处OnRefreshListener还有其它方法,可以选择需要的来重写。

如果你想进入到界面的时候主动调用下刷新,可以调用startRefresh()/startLoadmore()方法。

setWaveHeight、setHeaderHeight、setBottomHeight、setOverScrollHeight
  • setWaveHeight 设置头部可拉伸的最大高度。
  • setHeaderHeight 头部固定高度(在此高度上显示刷新状态)
  • setBottomHeight 底部高度
  • setOverScrollHeight 设置最大的越界高度

setEnableRefresh、setEnableLoadmore

灵活的设置是否禁用上下拉。

setHeaderView(IHeaderView headerView)、setBottomView(IBottomView bottomView)

设置头部/底部个性化刷新效果,头部需要实现IHeaderView,底部需要实现IBottomView。

setEnableOverScroll

是否允许越界回弹。

setOverScrollTopShow、setOverScrollBottomShow、setOverScrollRefreshShow

是否允许在越界的时候显示刷新控件,默认是允许的,也就是Fling越界的时候Header或Footer照常显示,反之就是不显示;可能有特殊的情况,刷新控件会影响显示体验才设立了这个状态。

setPureScrollModeOn()

开启纯净的越界回弹模式,也就是所有刷新相关的View都不显示,只显示越界回弹效果

setAutoLoadMore

是否在底部越界的时候自动切换到加载更多模式

addFixedExHeader

添加一个固定在顶部的Header(效果还需要优化)

startRefresh、startLoadMore、finishRefreshing、finishLoadmore
setFloatRefresh(boolean)

支持切换到像SwipeRefreshLayout一样的悬浮刷新模式了。

4.扩展属性

  • tr_wave_height 头部拉伸允许的最大高度
  • tr_head_height 头部高度
  • tr_bottom_height 底部高度
  • tr_overscroll_height 允许越界的最大高度
  • tr_enable_loadmore 是否允许加载更多,默认为true
  • tr_pureScrollMode_on 是否开启纯净的越界回弹模式
  • tr_overscroll_top_show - 否允许顶部越界时显示顶部View
  • tr_overscroll_bottom_show 是否允许底部越界时显示底部View
  • tr_enable_overscroll 是否允许越界回弹

其它说明

1.默认支持越界回弹,并可以随手势越界不同的高度

这一点很多类似SwipeRefreshLayout的刷新控件都没有做到(包括SwipeRefreshLayout),因为没有拦截下来的时间会传递给列表控件,而列表控件的滚动状态很难获取。解决方案就是给列表控件设置了OnTouchListener并把事件交给GestureDetector处理,然后在列表控件的OnScrollListener中监听View是否滚动到了顶部(没有OnScrollListener的则采用延时监听策略)。

2.setOnRefreshListener大量可以回调的方法

  • onPullingDown(TwinklingRefreshLayout refreshLayout, float fraction) 正在下拉的过程
  • onPullingUp(TwinklingRefreshLayout refreshLayout, float fraction) 正在上拉的过程
  • onPullDownReleasing(TwinklingRefreshLayout refreshLayout, float fraction) 下拉释放过程
  • onPullUpReleasing(TwinklingRefreshLayout refreshLayout, float fraction) 上拉释放过程
  • onRefresh(TwinklingRefreshLayout refreshLayout) 正在刷新
  • onLoadMore(TwinklingRefreshLayout refreshLayout) 正在加载更多

其中fraction表示当前下拉的距离与Header高度的比值(或者当前上拉距离与Footer高度的比值)。

3.Header和Footer

BezierLayout(pic 4)
  • setWaveColor
  • setRippleColor
GoogleDotView(pic 5)
SinaRefreshView(pic 3)
  • setArrowResource
  • setTextColor
  • setPullDownStr
  • setReleaseRefreshStr
  • setRefreshingStr
ProgressLayout(SwipeRefreshLayout pic 6)
  • setProgressBackgroundColorSchemeResource(@ColorRes int colorRes)
  • setProgressBackgroundColorSchemeColor(@ColorInt int color)
  • setColorSchemeResources(@ColorRes int... colorResIds)

Footer

BottomProgressView(pic 2)
  • setNormalColor(@ColorInt int color)
  • setAnimatingColor(@ColorInt int color)
LoadingView(pic 3)

更多动效可以参考AVLoadingIndicatorView库。

3.实现个性化的Header和Footer

相关接口分别为IHeaderView和IBottomView,代码如下:

public interface IHeaderView {    View getView();    void onPullingDown(float fraction,float maxHeadHeight,float headHeight);    void onPullReleasing(float fraction,float maxHeadHeight,float headHeight);    void startAnim(float maxHeadHeight,float headHeight);    void reset();
}

其中getView()方法用于在TwinklingRefreshLayout中获取到实际的Header,因此不能返回null。

实现像新浪微博那样的刷新效果(有部分修改,具体请看源码),实现代码如下:

1.首先定义SinaRefreshHeader继承自FrameLayout并实现IHeaderView方法

2.getView()方法中返回this

3.在onAttachedToWindow()或者构造函数方法中获取一下需要用到的布局

@Override
    protected void onAttachedToWindow() {        super.onAttachedToWindow();        if (rootView == null) {
            rootView = View.inflate(getContext(), R.layout.view_sinaheader, null);
            refreshArrow = (ImageView) rootView.findViewById(R.id.iv_arrow);
            refreshTextView = (TextView) rootView.findViewById(R.id.tv);
            loadingView = (ImageView) rootView.findViewById(R.id.iv_loading);
            addView(rootView);
        }
    }

4.实现其它方法

@Override
    public void onPullingDown(float fraction, float maxHeadHeight, float headHeight) {        if (fraction < 1f) refreshTextView.setText(pullDownStr);        if (fraction > 1f) refreshTextView.setText(releaseRefreshStr);
        refreshArrow.setRotation(fraction * headHeight / maxHeadHeight * 180);

    }    @Override
    public void onPullReleasing(float fraction, float maxHeadHeight, float headHeight) {        if (fraction < 1f) {
            refreshTextView.setText(pullDownStr);
            refreshArrow.setRotation(fraction * headHeight / maxHeadHeight * 180);            if (refreshArrow.getVisibility() == GONE) {
                refreshArrow.setVisibility(VISIBLE);
                loadingView.setVisibility(GONE);
            }
        }
    }    @Override
    public void startAnim(float maxHeadHeight, float headHeight) {
        refreshTextView.setText(refreshingStr);
        refreshArrow.setVisibility(GONE);
        loadingView.setVisibility(VISIBLE);
    }

5.布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">
    <ImageView
        android:id="@+id/iv_arrow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_arrow"/>

    <ImageView
        android:id="@+id/iv_loading"
        android:visibility="gone"
        android:layout_width="34dp"
        android:layout_height="34dp"
        android:src="@drawable/anim_loading_view"/>

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:textSize="16sp"
        android:text="下拉刷新"/>
</LinearLayout>

注意fraction的使用,比如上面的代码refreshArrow.setRotation(fraction * headHeight / maxHeadHeight * 180)fraction * headHeight表示当前头部滑动的距离,然后算出它和最大高度的比例,然后乘以180,可以使得在滑动到最大距离时Arrow恰好能旋转180度。

onPullingDown/onPullingUp表示正在下拉/正在上拉的过程。 onPullReleasing表示向上拉/下拉释放时回调的状态。 startAnim则是在onRefresh/onLoadMore之后才会回调的过程(此处是显示了加载中的小菊花)

如上所示,轻而易举就可以实现一个个性化的Header或者Footer。(更简单的实现请参考Demo中的 TextHeaderView(图四))。

TODO

  • 制作一个star相关的动效
  • CoordinateLayout及NestedScroll支持
  • 带视差效果的Header

更新日志

v1.04

新增功能
  • 第二次重构完成,将核心逻辑拆分为RefreshProcessor、AnimProcessor、OverScrollProcessor、CoProcessor
  • 优化越界策越,手势决定越界高度
  • 优化界面流畅度
  • 添加类似SwipeRefreshLayout的悬浮刷新功能(ProgressLayout)
  • 滑到底部自动加载更多or回弹可选,默认为回弹
  • 允许在结束刷新之前执行一个动效:IHeadView.onFinish(animEndListener)
  • 新增支持Header(Beta)
  • 优化BezierLayout、SinaRefreshLayout等的显示并增加调节属性
  • 新增支持设置是否允许OverScroll
fixed bugs
  • 修复刷新或加载更多时,列表item没有铺满列表控件,滑动无效的问题
  • 添加主动刷新/加载更多的方法:startRefresh(),startLoadMore()
  • 修复顶部和底部越界高度不一致的问题
  • 修复WebView在底部fling时不能越界的问题
  • 动画执行时间与高度相关,动效更加柔和

v1.03

  • 扩展了更多的属性
  • 修复Fragment回收导致的空指针异常问题
  • 加入x方向判断,减小了滑动冲突
  • 优化加载更多列表显示问题
  • 可以灵活的设置是否禁用上下拉
  • 修复GridView滑动过程中出现的白条问题
  • Demo中添加轮播条展示

v1.02

  • 修复加载更多列表控件的显示问题

v1.01

  • 支持了RecyclerView、ScrollView、AbsListView、WebView
  • 支持越界回弹
  • 支持个性化Header、Footer

ps:如有任何问题或者是建议,可以邮箱联系我!([email protected])

时间: 2024-10-29 20:32:41

TwinklingRefreshLayout 小而强大的刷新控件,自带顺滑的越界回弹,v1.04 版精心重构,完美发布啦!的相关文章

自定义下拉刷新控件

一.功能效果 1.在很多app中,在信息展示页面,当我们向下拖拽时,页面会加载最新的数据,并有一个短暂的提示控件出现,有些会有加载进度条,有些会记录加载日期.条目,有些还带有加载动画.其基本实现原理都相仿,本文中将探讨其实现原理,并封装出一个简单的下拉刷新控件 2.自定义刷新工具简单的示例 二.系统提供的下拉刷新工具 1.iOS6.0以后系统提供了自己的下拉刷新的控件:UIRefreshControl .例如,refreshControl,作为UITableViewController中的一个属

Android下拉刷新控件SwipeRefreshLayout源码浅析

SwipeRefreshLayout是Android官方的下拉刷新控件,使用简单,界面美观,不熟悉的朋友可以随便搜索了解一下,这里就不废话了,直接进入正题. 这种下拉刷新控件的原理不难,基本就是监听手指的运动,获取手指的坐标,通过计算判断出是哪种操作,然后就是回调相应的接口了.SwipeRefreshLayout是继承自ViewGroup的,根据Android的事件分发机制,触摸事件应该是先传递到ViewGroup,根据onInterceptTouchEvent的返回值决定是否拦截事件的,那么就

新浪微博项目-上下拉刷新控件经验总结

1.下拉控件的刷新:  原理:通过监听UIRefresh下拉刷新控件的拖拽,向服务器发送请求数据,当将获取的数据插入到模型最前面,更新并加载到tableView上时,结束刷新:>创建UIRefresh下拉刷新控件,绑定监听并添加到tableView上面:>当控件下拉时: 1.向服务器发送请求数据,当将获取的数据存入模型,更新并加载到tableView上时,结束刷新: 2.下拉刷新的时间距离上次下拉时间间隔太短时,不再向服务器发送请求数据,直接返回,结束刷新: (补充:当下拉刷新控件同时下拉多次

github上开源项目MJRefresh自定义刷新控件

前言:在项目开发过程中经常有需要进行刷新操作,MJ博主开源的MJRefresh为我们节省了大量的时间.只需要几行代码就可给UITableview,UICollectionview,UISCrollview,UIWebview集成上拉或下拉操作.更强大的是自定义功能,无论产品经理要什么上拉下拉动态效果,MJRefresh带你装逼带你酷炫下拉刷新.先来看看自定义下拉的动态效果. 1 利用cocoapods安装MJRefresh,如果不明白cocoapods使用方法,请参照cocopods安装和使用教

Android SwipeRefreshLayout下拉刷新控件源码简单分析

咱们在做Android APP开发的时候经常碰到有下拉刷新和上拉加载跟多的需求,这篇文章咱们先说说下来刷新,咱们就以google的原生的下拉刷新控件SwipeRefreshLayout来看看大概的实现过程. SwipeRefreshLayout是google自己推出的下拉刷新控件.使用起来也非常的简单,在满足条件的情况下下拉的时候会显示一个圆形的loading的动画效果,然后回调到上层,上层自己做刷新的一系列的处理,处理结束后调用SwipeRefreshLayout的setRefreshing(

所闻所获4:下拉刷新控件2

在上一篇博文讨论了下拉刷新控件的框架,这一篇博文将会主要讨论刷新过程中控件的动画效果. 1.首先回顾一下在GMPullToRefresh类中的初始化方法: - (id)initWithScrollView:(UIScrollView *)scrollView { //初始化 ... //定制提示文字 ... //矩形上升动画图 self.activityView=[self activityIndicatorView]; //圆圈转动动画 self.circleView=[[CircleProg

android官方下拉刷新控件SwipeRefreshLayout的使用

可能开发安卓的人大多数都用过很多下拉刷新的开源组件,但是今天用了官方v4支持包的SwipeRefreshLayout觉得效果也蛮不错的,特拿出来分享. 简介:SwipeRefreshLayout组件只接受一个子组件:即需要刷新的那个组件.它使用一个侦听机制来通知拥有该组件的监听器有刷新事件发生,换句话说我们的Activity必须实现通知的接口.该Activity负责处理事件刷新和刷新相应的视图.一旦监听者接收到该事件,就决定了刷新过程中应处理的地方.如果要展示一个“刷新动画”,它必须调用setR

【转】Android官方下拉刷新控件 SwipeRefreshLayout

今天在Google+上看到了SwipeRefreshLayout这个名词,遂搜索了下,发现竟然是刚刚google更新sdk新增加的一个widget,于是赶紧抢先体验学习下. SwipeRefreshLayout SwipeRefreshLayout字面意思就是下拉刷新的布局,继承自ViewGroup,在support v4兼容包下,但必须把你的support library的版本升级到19.1. 提到下拉刷新大家一定对ActionBarPullToRefresh比较熟悉,而如今google推出了

[Android]下拉刷新控件RefreshableView的实现

需求:自定义一个ViewGroup,实现可以下拉刷新的功能.下拉一定距离后(下拉时显示的界面可以自定义任何复杂的界面)释放手指可以回调刷新的功能,用户处理完刷新的内容后,可以调用方法onCompleteRefresh()通知刷新完毕,然后回归正常状态.效果如下:     源代码:RefreshableView(https://github.com/wangjiegulu/RefreshableView) 分析: 我们的目的是不管什么控件,只要在xml中外面包一层标签,那这个标签下面的所有子标签所