Android开源:TwinklingRefreshLayout-小而强大的刷新控件

Rashad25T 8年前
   <h2>TwinklingRefreshLayout</h2>    <p>TwinklingRefreshLayout延伸了Google的SwipeRefreshLayout的思想,不在列表控件上动刀,而是使用一个ViewGroup来包含列表控件,以保持其较低的耦合性和较高的通用性。其主要特性有:</p>    <ol>     <li>支持RecyclerView、ScrollView、AbsListView系列(ListView、GridView)、WebView以及其它可以获取到scrollY的控件</li>     <li>支持加载更多</li>     <li>默认支持 <strong>越界回弹</strong> ,随手势速度有不同的效果</li>     <li>可开启没有刷新控件的纯净越界回弹模式</li>     <li>setOnRefreshListener中拥有大量可以回调的方法</li>     <li>将Header和Footer抽象成了接口,并回调了滑动过程中的系数,方便实现个性化的Header和Footer</li>    </ol>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b8b064d85d167b9311e1a5208d341523.png"></p>    <h2>Demo</h2>    <p> </p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/42a6ae41a9880a2c53a75df4bbc891ae.gif"> <img src="https://simg.open-open.com/show/92e69d442493a6ddd40808da9bcbde77.gif"> <img src="https://simg.open-open.com/show/4bc9571b64ab0b0d138f7d03fa9c5515.gif"> <img src="https://simg.open-open.com/show/ef68c5f9ddd48169fbb2511afec85ebf.gif"> <img src="https://simg.open-open.com/show/84f36c14a71d65567c00d1ef91b61c5a.gif"> <img src="https://simg.open-open.com/show/9b3602c5d976271791b85bf6ad5e11f1.gif"></p>    <p>You can download the Video for more details.</p>    <ul>     <li><a href="/misc/goto?guid=4959729105056338697" rel="nofollow,noindex">Music - ListView - FixedHeader</a></li>     <li><a href="/misc/goto?guid=4959729105164142524" rel="nofollow,noindex">Food - RecyclerView - PureScrollMode</a></li>     <li><a href="/misc/goto?guid=4959729105241027088" rel="nofollow,noindex">Science - GridView - SinaHeader</a></li>     <li><a href="/misc/goto?guid=4959729105329237729" rel="nofollow,noindex">Photo - RecyclerView - BezierLayout</a></li>     <li><a href="/misc/goto?guid=4959729105414143448" rel="nofollow,noindex">Story - ScrollView - GoogleDotView</a></li>     <li><a href="/misc/goto?guid=4959729105494635280" rel="nofollow,noindex">Dribbble - WebView - FloatRefresh</a></li>    </ul>    <h2>使用方法</h2>    <p>1.添加gradle依赖</p>    <p>将libray模块复制到项目中,或者直接在build.gradle中依赖:</p>    <pre>  <code class="language-java">compile 'com.lcodecorex:tkrefreshlayout:1.0.4'</code></pre>    <p>2.在xml中添加TwinklingRefreshLayout</p>    <pre>  <code class="language-java"><?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></code></pre>    <p>Android系统为了跟iOS不一样,当界面OverScroll的时候会显示一个阴影。为了达到更好的显示效果,最好禁用系统的overScroll,如上给RecyclerView添加 android:overScrollMode="never" 。</p>    <p>3.在Activity或者Fragment中配置</p>    <p>TwinklingRefreshLayout不会自动结束刷新或者加载更多,需要手动控制</p>    <pre>  <code class="language-java">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);              }          });      }</code></pre>    <p>使用finishRefreshing()方法结束刷新,finishLoadmore()方法结束加载更多。此处OnRefreshListener还有其它方法,可以选择需要的来重写。</p>    <p>如果你想进入到界面的时候主动调用下刷新,可以调用startRefresh()/startLoadmore()方法。</p>    <p>setWaveHeight、setHeaderHeight、setBottomHeight、setOverScrollHeight</p>    <ul>     <li>setWaveHeight 设置头部可拉伸的最大高度。</li>     <li>setHeaderHeight 头部固定高度(在此高度上显示刷新状态)</li>     <li>setBottomHeight 底部高度</li>     <li>setOverScrollHeight 设置最大的越界高度</li>    </ul>    <p>setEnableRefresh、setEnableLoadmore</p>    <p>灵活的设置是否禁用上下拉。</p>    <p>setHeaderView(IHeaderView headerView)、setBottomView(IBottomView bottomView)</p>    <p>设置头部/底部个性化刷新效果,头部需要实现IHeaderView,底部需要实现IBottomView。</p>    <p>setEnableOverScroll</p>    <p>是否允许越界回弹。</p>    <p>setOverScrollTopShow、setOverScrollBottomShow、setOverScrollRefreshShow</p>    <p>是否允许在越界的时候显示刷新控件,默认是允许的,也就是Fling越界的时候Header或Footer照常显示,反之就是不显示;可能有特殊的情况,刷新控件会影响显示体验才设立了这个状态。</p>    <p>setPureScrollModeOn()</p>    <p>开启纯净的越界回弹模式,也就是所有刷新相关的View都不显示,只显示越界回弹效果</p>    <p>setAutoLoadMore</p>    <p>是否在底部越界的时候自动切换到加载更多模式</p>    <p>addFixedExHeader</p>    <p>添加一个固定在顶部的Header(效果还需要优化)</p>    <p>startRefresh、startLoadMore、finishRefreshing、finishLoadmore</p>    <p>setFloatRefresh(boolean)</p>    <p>支持切换到像SwipeRefreshLayout一样的悬浮刷新模式了。</p>    <p>4.扩展属性</p>    <ul>     <li>tr_wave_height 头部拉伸允许的最大高度</li>     <li>tr_head_height 头部高度</li>     <li>tr_bottom_height 底部高度</li>     <li>tr_overscroll_height 允许越界的最大高度</li>     <li>tr_enable_loadmore 是否允许加载更多,默认为true</li>     <li>tr_pureScrollMode_on 是否开启纯净的越界回弹模式</li>     <li>tr_overscroll_top_show - 否允许顶部越界时显示顶部View</li>     <li>tr_overscroll_bottom_show 是否允许底部越界时显示底部View</li>     <li>tr_enable_overscroll 是否允许越界回弹</li>    </ul>    <h2>其它说明</h2>    <h3>1.默认支持越界回弹,并可以随手势越界不同的高度</h3>    <p>这一点很多类似SwipeRefreshLayout的刷新控件都没有做到(包括SwipeRefreshLayout),因为没有拦截下来的时间会传递给列表控件,而列表控件的滚动状态很难获取。解决方案就是给列表控件设置了OnTouchListener并把事件交给GestureDetector处理,然后在列表控件的OnScrollListener中监听View是否滚动到了顶部(没有OnScrollListener的则采用延时监听策略)。</p>    <h3>2.setOnRefreshListener大量可以回调的方法</h3>    <ul>     <li>onPullingDown(TwinklingRefreshLayout refreshLayout, float fraction) 正在下拉的过程</li>     <li>onPullingUp(TwinklingRefreshLayout refreshLayout, float fraction) 正在上拉的过程</li>     <li>onPullDownReleasing(TwinklingRefreshLayout refreshLayout, float fraction) 下拉释放过程</li>     <li>onPullUpReleasing(TwinklingRefreshLayout refreshLayout, float fraction) 上拉释放过程</li>     <li>onRefresh(TwinklingRefreshLayout refreshLayout) 正在刷新</li>     <li>onLoadMore(TwinklingRefreshLayout refreshLayout) 正在加载更多</li>    </ul>    <p>其中fraction表示当前下拉的距离与Header高度的比值(或者当前上拉距离与Footer高度的比值)。</p>    <h3>3.Header和Footer</h3>    <p>BezierLayout(pic 4)</p>    <ul>     <li>setWaveColor</li>     <li>setRippleColor</li>    </ul>    <p>GoogleDotView(pic 5)</p>    <p>SinaRefreshView(pic 3)</p>    <ul>     <li>setArrowResource</li>     <li>setTextColor</li>     <li>setPullDownStr</li>     <li>setReleaseRefreshStr</li>     <li>setRefreshingStr</li>    </ul>    <p>ProgressLayout(SwipeRefreshLayout pic 6)</p>    <ul>     <li>setProgressBackgroundColorSchemeResource(@ColorRes int colorRes)</li>     <li>setProgressBackgroundColorSchemeColor(@ColorInt int color)</li>     <li>setColorSchemeResources(@ColorRes int... colorResIds)</li>    </ul>    <p>Footer</p>    <p>BottomProgressView(pic 2)</p>    <ul>     <li>setNormalColor(@ColorInt int color)</li>     <li>setAnimatingColor(@ColorInt int color)</li>    </ul>    <p>LoadingView(pic 3)</p>    <h3>3.实现个性化的Header和Footer</h3>    <p>相关接口分别为IHeaderView和IBottomView,代码如下:</p>    <pre>  <code class="language-java">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();  }</code></pre>    <p>其中getView()方法用于在TwinklingRefreshLayout中获取到实际的Header,因此不能返回null。</p>    <p>实现像新浪微博那样的刷新效果(有部分修改,具体请看源码),实现代码如下:</p>    <p>1.首先定义SinaRefreshHeader继承自FrameLayout并实现IHeaderView方法</p>    <p>2.getView()方法中返回this</p>    <p>3.在onAttachedToWindow()或者构造函数方法中获取一下需要用到的布局</p>    <pre>  <code class="language-java">@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);          }      }</code></pre>    <p>4.实现其它方法</p>    <pre>  <code class="language-java">@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);      }</code></pre>    <p>5.布局文件</p>    <pre>  <code class="language-java"><?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></code></pre>    <p>注意fraction的使用,比如上面的代码 refreshArrow.setRotation(fraction * headHeight / maxHeadHeight * 180) , fraction * headHeight 表示当前头部滑动的距离,然后算出它和最大高度的比例,然后乘以180,可以使得在滑动到最大距离时Arrow恰好能旋转180度。</p>    <p>onPullingDown/onPullingUp表示正在下拉/正在上拉的过程。 onPullReleasing表示向上拉/下拉释放时回调的状态。 startAnim则是在onRefresh/onLoadMore之后才会回调的过程(此处是显示了加载中的小菊花)</p>    <p>如上所示,轻而易举就可以实现一个个性化的Header或者Footer。(更简单的实现请参考Demo中的 <strong>TextHeaderView(图四)</strong> )。</p>    <h2>TODO</h2>    <ul>     <li>制作一个star相关的动效</li>     <li>CoordinateLayout及NestedScroll支持</li>     <li>带视差效果的Header</li>    </ul>    <h2>更新日志</h2>    <p>v1.04</p>    <p>新增功能</p>    <ul>     <li><strong>第二次重构完成</strong> ,将核心逻辑拆分为RefreshProcessor、AnimProcessor、OverScrollProcessor、CoProcessor</li>     <li><strong>优化越界策越,手势决定越界高度</strong></li>     <li><strong>优化界面流畅度</strong></li>     <li>添加类似SwipeRefreshLayout的 <strong>悬浮刷新</strong> 功能(ProgressLayout)</li>     <li>滑到底部 <strong>自动加载更多</strong> or回弹可选,默认为回弹</li>     <li>允许在结束刷新之前执行一个动效:IHeadView.onFinish(animEndListener)</li>     <li>新增支持Header(Beta)</li>     <li>优化BezierLayout、SinaRefreshLayout等的显示并增加调节属性</li>     <li>新增支持设置是否允许OverScroll</li>    </ul>    <p>fixed bugs</p>    <ul>     <li>修复刷新或加载更多时,列表item没有铺满列表控件,滑动无效的问题</li>     <li>添加主动刷新/加载更多的方法:startRefresh(),startLoadMore()</li>     <li>修复顶部和底部越界高度不一致的问题</li>     <li>修复WebView在底部fling时不能越界的问题</li>     <li>动画执行时间与高度相关,动效更加柔和</li>    </ul>    <p>v1.03</p>    <ul>     <li>扩展了更多的属性</li>     <li>修复Fragment回收导致的空指针异常问题</li>     <li>加入x方向判断,减小了滑动冲突</li>     <li>优化加载更多列表显示问题</li>     <li>可以灵活的设置是否禁用上下拉</li>     <li>修复GridView滑动过程中出现的白条问题</li>     <li>Demo中添加轮播条展示</li>    </ul>    <p>v1.02</p>    <ul>     <li>修复加载更多列表控件的显示问题</li>    </ul>    <p>v1.01</p>    <ul>     <li>支持了RecyclerView、ScrollView、AbsListView、WebView</li>     <li>支持越界回弹</li>     <li>支持个性化Header、Footer</li>    </ul>    <p> </p>    <p> </p>    <p>来自:https://github.com/lcodecorex/TwinklingRefreshLayout/blob/master/README_CN.md</p>    <p> </p>