zoukankan      html  css  js  c++  java
  • 安卓开发笔记——关于开源组件PullToRefresh实现下拉刷新和上拉加载(一分钟搞定,超级简单)

    前言

      以前在实现ListView下拉刷新和上拉加载数据的时候都是去继承原生的ListView重写它的一些方法,实现起来非常繁杂,需要我们自己去给ListView定制下拉刷新和上拉加载的布局文件,然后添加ScrollView和OnTouch监听,设置回调接口获取数据,为了更好的交互体验,我们还不能直接利用setVisibility隐藏显示布局等等一大堆的操作,累都累死了。(题外话:关于下拉刷新在新版的android-support-v4.jar里,其实谷歌已经为我们提供了一个控件叫SwipeRefreshLayout,使用方法也非常简单,有兴趣的朋友可以自己网上了解下)它的实现效果大致是这样的:

      今天来说下关于开源项目PullToRefresh的使用方法,轻轻松松几行代码就可以把下拉刷新和上拉加载功能给实现了。(开源的东西虽然好用,但作为学习,还是建议大家先不用开源组件自己去实现一遍所需要的效果,毕竟原理需要懂),好了,言归正传,我尽量的言简意赅,进入主题。

    先看下最后的实现效果图:

      

    准备工作

    1、既然是利用PullToRefresh组件来实现下拉刷新和上拉加载数据的效果,那么首先我们需要先把它下载下来。

    这是PullToRefresh在GitHub上的下载地址:https://github.com/chrisbanes/Android-PullToRefresh/wiki/Quick-Start-Guide

    很简单,下载完毕后我们就可以开始进入开发工作了。

    磨刀不误砍柴工

    1、首先先导入该项目

    在导入项目后,我们会发现出现了很多红叉,不用担心,这个只是引用库路径出错罢了,我们右键点击有红叉的文件选择Properties,选择Andorid下拉,把对应的library重新 引入即可,依样画葫芦,其他出现的红叉的文件也都这样做。

      

    把红叉都解决完之后,有个很重要的事情要做,把刚导入的所有文件夹里的android-support-v4.jar和你自己的项目里的v4包统一了,避免v4包版本不一致导致项目运行出错。

    干活干活!

    布局文件,非常简单,只放了一个可下拉刷新的ListView

     1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:tools="http://schemas.android.com/tools"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent">
     5 
     6     <com.handmark.pulltorefresh.library.PullToRefreshListView
     7         android:id="@+id/mylistview"
     8         android:layout_width="match_parent"
     9         android:layout_height="match_parent"
    10         >
    11         </com.handmark.pulltorefresh.library.PullToRefreshListView>
    12 
    13 </RelativeLayout>

    主代码文件:

      1 package com.rabbit.pulltorefreshdemo;
      2 
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 
      6 import android.app.Activity;
      7 import android.os.AsyncTask;
      8 import android.os.Bundle;
      9 import android.widget.ArrayAdapter;
     10 import android.widget.ListView;
     11 
     12 import com.handmark.pulltorefresh.library.PullToRefreshBase;
     13 import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
     14 import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener;
     15 import com.handmark.pulltorefresh.library.PullToRefreshListView;
     16 
     17 public class MainActivity extends Activity {
     18     
     19     //声明下拉刷新ListView组件
     20     private PullToRefreshListView myListView;
     21     //声明数据源
     22     private List<String> data;
     23     //声明适配器
     24     private ArrayAdapter<String> adapter;
     25 
     26     @Override
     27     protected void onCreate(Bundle savedInstanceState) {
     28         super.onCreate(savedInstanceState);
     29         setContentView(R.layout.activity_main);
     30         //获取下拉刷新ListView组件
     31         this.myListView=(PullToRefreshListView) findViewById(R.id.mylistview);
     32         //模拟数据
     33         this.data=new ArrayList<String>();
     34         data.add("JAVA");
     35         data.add("PHP");
     36         data.add("C++");
     37         data.add("C#");
     38         //实例化Adapter
     39         this.adapter=new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, data);
     40         //设置Adapter
     41         myListView.setAdapter(adapter);
     42         //设置支持上下拉动和监听
     43         myListView.setMode(Mode.BOTH);
     44         myListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
     45 
     46             @Override
     47             public void onRefresh(PullToRefreshBase<ListView> refreshView) {
     48                 
     49                     if(refreshView.isShownHeader()){
     50                         //判断头布局是否可见,如果可见执行下拉刷新
     51                         //设置尾布局样式文字
     52                         myListView.getLoadingLayoutProxy().setRefreshingLabel("正在刷新");
     53                         myListView.getLoadingLayoutProxy().setPullLabel("下拉刷新数据");
     54                         myListView.getLoadingLayoutProxy().setReleaseLabel("释放开始刷新");
     55                         //模拟加载数据线程休息3秒
     56                         new AsyncTask<Void, Void, Void>() {
     57                             @Override
     58                             protected Void doInBackground(Void... params) {
     59                                 try {
     60                                     Thread.sleep(3000);
     61                                     data.add("刷新数据1");
     62                                     data.add("刷新数据2");
     63                                     data.add("刷新数据3");
     64                                 } catch (InterruptedException e) {
     65                                     e.printStackTrace();
     66                                 }
     67                                 return null;
     68                             }
     69                             
     70                             @Override
     71                             protected void onPostExecute(Void result) {
     72                                 super.onPostExecute(result);
     73                                 //完成对下拉刷新ListView的更新操作
     74                                 adapter.notifyDataSetChanged();
     75                                 //将下拉视图收起
     76                                 myListView.onRefreshComplete();
     77                             }
     78                         }.execute();
     79                     }
     80                     if(refreshView.isShownFooter()){
     81                         //判断尾布局是否可见,如果可见执行上拉加载更多
     82                         //设置尾布局样式文字
     83                         myListView.getLoadingLayoutProxy().setRefreshingLabel("正在加载");
     84                         myListView.getLoadingLayoutProxy().setPullLabel("上拉加载更多");
     85                         myListView.getLoadingLayoutProxy().setReleaseLabel("释放开始加载");
     86                         //模拟加载数据线程休息3秒
     87                         new AsyncTask<Void, Void, Void>() {
     88                             @Override
     89                             protected Void doInBackground(Void... params) {
     90                                 try {
     91                                     Thread.sleep(3000);
     92                                     data.add("更多数据1");
     93                                     data.add("更多数据2");
     94                                     data.add("更多数据3");
     95                                 } catch (InterruptedException e) {
     96                                     e.printStackTrace();
     97                                 }
     98                                 return null;
     99                             }
    100                             
    101                             @Override
    102                             protected void onPostExecute(Void result) {
    103                                 super.onPostExecute(result);
    104                                 //完成对下拉刷新ListView的更新操作
    105                                 adapter.notifyDataSetChanged();
    106                                 //将下拉视图收起
    107                                 myListView.onRefreshComplete();
    108                             }
    109                         }.execute();
    110                         
    111                         
    112                     }
    113                     
    114             }
    115         });
    116         
    117     }
    118 
    119 
    120 }

    其实和普通ListView的使用方式差不多,只是多了一些属性的设置,这里有几个要注意的地方:

    1、模式的设置,默认下PullToRefresh的刷新模式只支持下拉刷新,我们可以通过setMode(Mode.XXXX)来设置它

    1 BOTH:上拉刷新和下拉刷新都支持
    2 DISABLED:禁用上拉下拉刷新
    3 PULL_FROM_START:仅支持下拉刷新(默认)
    4 PULL_FROM_END:仅支持上拉刷新
    5 MANUAL_REFRESH_ONLY:只允许手动触发

    2、补充上述描述第1点,当我们设置模式为BOTH的时候,我们就可以实现下拉和上拉了,但这里的它们的样式是一样的,我们需要的场景应该是下拉的时候显示"下拉刷新数据,正在刷新数据,数据刷新成功....",而在我们上拉的时候应该出现的场景是"上拉加载数据,正在加载数据,加载数据成功...",所以这里我们需要对样式进行设置。

    由于PullToRefresh默认是没给我们判断到底是上拉还是下拉的方法,所以我们需要去源代码里修改下它的代码,Ctrl+Shift+T搜索下PullToRefreshBase类,打开后再后最后面我们补上这样一段代码,我们可以根据当头布局可见的时候执行下拉刷新,当尾布局可见的时候执行下拉加载,这样我们就可以根据头尾布局来判断用户到底是执行上拉还是下拉操作了。

    1     //判别头部是否展示出来,如果展示出来代表下拉使得头部展示。true为下拉
    2     public boolean isShownHeader() {
    3         return getHeaderLayout().isShown();
    4     }
    5     //判别低部是否展示出来,如果展示出来代表上拉使得低部展示。true为上拉
    6     public boolean isShownFooter() {
    7         return getFooterLayout().isShown();
    8     }

    3、这是关于PullToRefresh的一些属性设置,在源码中可以找到,这里我做了下翻译:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <resources>
     3     <declare-styleable name="PullToRefresh">
     4         <!-- A drawable to use as the background of the Refreshable View -->
     5         <!-- 设置整个刷新列表的背景色 -->
     6         <attr name="ptrRefreshableViewBackground" format="reference|color" />
     7         <!-- A drawable to use as the background of the Header and Footer Loading Views -->
     8         <!--  设置下拉Header或者上拉Footer的背景色 -->
     9         <attr name="ptrHeaderBackground" format="reference|color" />
    10         <!-- Text Color of the Header and Footer Loading Views -->
    11         <!-- 用于设置Header与Footer中文本的颜色 -->
    12         <attr name="ptrHeaderTextColor" format="reference|color" />
    13         <!-- Text Color of the Header and Footer Loading Views Sub Header -->
    14         <!-- 用于设置Header与Footer中上次刷新时间的颜色 -->
    15         <attr name="ptrHeaderSubTextColor" format="reference|color" />
    16         <!-- Mode of Pull-to-Refresh that should be used -->
    17         <attr name="ptrMode">
    18             <flag name="disabled" value="0x0" /><!-- 禁用下拉刷新 -->
    19             <flag name="pullFromStart" value="0x1" /><!-- 仅支持下拉刷新 -->
    20             <flag name="pullFromEnd" value="0x2" /><!-- 仅支持上拉刷新 -->
    21             <flag name="both" value="0x3" /><!-- 上拉刷新和下拉刷新都支持 -->
    22             <flag name="manualOnly" value="0x4" /><!-- 只允许手动触发 -->
    23 
    24             <!-- These last two are depreacted -->
    25             <flag name="pullDownFromTop" value="0x1" />
    26             <flag name="pullUpFromBottom" value="0x2" />
    27         </attr>
    28         <!-- Whether the Indicator overlay(s) should be used -->
    29         <!-- 如果为true会在mPullRefreshListView中出现icon,右上角和右下角,挺有意思的 -->
    30         <attr name="ptrShowIndicator" format="reference|boolean" />
    31         <!-- Drawable to use as Loading Indicator. Changes both Header and Footer. -->
    32         <!-- 同时改变头部和底部的图标 -->
    33         <attr name="ptrDrawable" format="reference" />
    34         <!-- Drawable to use as Loading Indicator in the Header View. Overrides value set in ptrDrawable. -->
    35         <!-- 头部视图的图标-->
    36         <attr name="ptrDrawableStart" format="reference" />
    37 
    38         <!-- Drawable to use as Loading Indicator in the Footer View. Overrides value set in ptrDrawable. -->
    39         <!-- 底部视图的图标 -->
    40         <attr name="ptrDrawableEnd" format="reference" />
    41         <!-- Whether Android's built-in Over Scroll should be utilised for Pull-to-Refresh. -->
    42         <attr name="ptrOverScroll" format="reference|boolean" />
    43         <!-- Base text color, typeface, size, and style for Header and Footer Loading Views -->
    44          <!-- 分别设置拉Header或者上拉Footer中字体的类型颜色等等 -->
    45         <attr name="ptrHeaderTextAppearance" format="reference" />
    46         <!-- Base text color, typeface, size, and style for Header and Footer Loading Views Sub Header -->
    47         <attr name="ptrSubHeaderTextAppearance" format="reference" />
    48         <!-- Style of Animation should be used displayed when pulling. -->
    49         <attr name="ptrAnimationStyle">
    50             <flag name="rotate" value="0x0" /><!-- flip(翻转动画), rotate(旋转动画)  -->
    51             <flag name="flip" value="0x1" />
    52         </attr>
    53         <!-- Whether the user can scroll while the View is Refreshing -->
    54         <!-- 刷新的时候,是否允许ListView或GridView滚动 -->
    55         <attr name="ptrScrollingWhileRefreshingEnabled" format="reference|boolean" />
    56         <!--
    57             Whether PullToRefreshListView has it's extras enabled. This allows the user to be 
    58             able to scroll while refreshing, and behaves better. It acheives this by adding
    59             Header and/or Footer Views to the ListView.
    60         -->
    61         <!-- 决定了Header,Footer以何种方式加入mPullRefreshListView,true为headView方式加入,就是滚动时刷新头部会一起滚动 -->
    62         <attr name="ptrListViewExtrasEnabled" format="reference|boolean" />
    63         <!--
    64             Whether the Drawable should be continually rotated as you pull. This only
    65             takes effect when using the 'Rotate' Animation Style.
    66         -->
    67         <attr name="ptrRotateDrawableWhilePulling" format="reference|boolean" />
    68         <!-- BELOW HERE ARE DEPRECEATED. DO NOT USE. -->
    69         <attr name="ptrAdapterViewBackground" format="reference|color" />
    70         <attr name="ptrDrawableTop" format="reference" />
    71         <attr name="ptrDrawableBottom" format="reference" />
    72     </declare-styleable>
    73 </resources>

    设置属性也很简单,在对应的布局文件里直接设置就可以,比如字体颜色:

    1     <com.handmark.pulltorefresh.library.PullToRefreshListView
    2         xmlns:ptr="http://schemas.android.com/apk/res-auto"  
    3         android:id="@+id/lv_friendsline"
    4         android:layout_width="fill_parent"
    5         android:layout_height="fill_parent" 
    6         ptr:ptrHeaderTextColor="#000000"
    7         >

    其他的一些,大家看我代码注释吧,写的非常详细了。

    补充:关于这个PullToRefresh它不仅仅支持ListView,比如ScrollView,GridView等等,只要是能滚动到控件它都通吃,具体使用方法大家可以参考我们一开始导入的项目里的LauncherActivity。

    作者:Balla_兔子
    出处:http://www.cnblogs.com/lichenwei/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
    正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!

  • 相关阅读:
    微信开发第一步—接入指南
    摸不着
    dubbo监控中心安装部署
    解决mapper映射文件不发布问题
    单例设计模式
    Spring与Hibernate集成、Spring与Struts2集成
    Spring MVC对日期处理的不友好问题
    常用的系统存储过程
    这就是成长(刚开始经常犯的错误随记)
    一些简单的查询
  • 原文地址:https://www.cnblogs.com/lichenwei/p/4452321.html
Copyright © 2011-2022 走看看