让Android Support V4中的SwipeRefreshLayout支持上拉加载更多

来源:互联网 发布:淘宝网app 电脑版下载 编辑:程序博客网 时间:2024/06/05 06:07
 

让Android Support V4中的SwipeRefreshLayout支持上拉加载更多

标签: AndroidSwipeRefreshLayout下拉刷新上拉加载
 14931人阅读 评论(33) 收藏 举报
 分类:
 

目录(?)[+]

前言

原来的Android SDK中并没有下拉刷新组件,但是这个组件确实绝大多数APP必备的一个部件。好在google在v4包中出了一个SwipeRefreshLayout,但是这个组件只支持下拉刷新,不支持上拉加载更多的操作。因此,我们就来简单的扩展一下这个组件以实现上拉下载的目的。

基本原理

上拉加载或者说滚动到底部时自动加载,都是通过判断是否滚动到了ListView或者其他View的底部,然后触发相应的操作,这里我们以ListView来说明。因此我们需要在监听ListView的滚动事件,当ListView滚动到底部时自动触发加载操作;但是当用户支持手指滑动屏幕,没有滚动时,我们也需要让它加载,因此这种情形就是上拉加载更多。所以我们需要在触摸事件里面进行判断,如果到了底部,且用户是上拉操作,那么执行加载更多。更多关于下拉刷新、上拉加载请参考打造通用的Android下拉刷新组件(适用于ListView、GridView等各类View)。
时间有限,直接上代码吧。

实现代码

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 继承自SwipeRefreshLayout,从而实现滑动到底部时上拉加载更多的功能. 
  3.  *  
  4.  * @author mrsimple 
  5.  */  
  6. public class RefreshLayout extends SwipeRefreshLayout implements OnScrollListener {  
  7.   
  8.     /** 
  9.      * 滑动到最下面时的上拉操作 
  10.      */  
  11.   
  12.     private int mTouchSlop;  
  13.     /** 
  14.      * listview实例 
  15.      */  
  16.     private ListView mListView;  
  17.   
  18.     /** 
  19.      * 上拉监听器, 到了最底部的上拉加载操作 
  20.      */  
  21.     private OnLoadListener mOnLoadListener;  
  22.   
  23.     /** 
  24.      * ListView的加载中footer 
  25.      */  
  26.     private View mListViewFooter;  
  27.   
  28.     /** 
  29.      * 按下时的y坐标 
  30.      */  
  31.     private int mYDown;  
  32.     /** 
  33.      * 抬起时的y坐标, 与mYDown一起用于滑动到底部时判断是上拉还是下拉 
  34.      */  
  35.     private int mLastY;  
  36.     /** 
  37.      * 是否在加载中 ( 上拉加载更多 ) 
  38.      */  
  39.     private boolean isLoading = false;  
  40.   
  41.     /** 
  42.      * @param context 
  43.      */  
  44.     public RefreshLayout(Context context) {  
  45.         this(context, null);  
  46.     }  
  47.   
  48.     public RefreshLayout(Context context, AttributeSet attrs) {  
  49.         super(context, attrs);  
  50.   
  51.         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  
  52.   
  53.         mListViewFooter = LayoutInflater.from(context).inflate(R.layout.listview_footer, null,  
  54.                 false);  
  55.     }  
  56.   
  57.     @Override  
  58.     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  59.         super.onLayout(changed, left, top, right, bottom);  
  60.   
  61.         // 初始化ListView对象  
  62.         if (mListView == null) {  
  63.             getListView();  
  64.         }  
  65.     }  
  66.   
  67.     /** 
  68.      * 获取ListView对象 
  69.      */  
  70.     private void getListView() {  
  71.         int childs = getChildCount();  
  72.         if (childs > 0) {  
  73.             View childView = getChildAt(0);  
  74.             if (childView instanceof ListView) {  
  75.                 mListView = (ListView) childView;  
  76.                 // 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载  
  77.                 mListView.setOnScrollListener(this);  
  78.                 Log.d(VIEW_LOG_TAG, "### 找到listview");  
  79.             }  
  80.         }  
  81.     }  
  82.   
  83.     /* 
  84.      * (non-Javadoc) 
  85.      * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent) 
  86.      */  
  87.     @Override  
  88.     public boolean dispatchTouchEvent(MotionEvent event) {  
  89.         final int action = event.getAction();  
  90.   
  91.         switch (action) {  
  92.             case MotionEvent.ACTION_DOWN:  
  93.                 // 按下  
  94.                 mYDown = (int) event.getRawY();  
  95.                 break;  
  96.   
  97.             case MotionEvent.ACTION_MOVE:  
  98.                 // 移动  
  99.                 mLastY = (int) event.getRawY();  
  100.                 break;  
  101.   
  102.             case MotionEvent.ACTION_UP:  
  103.                 // 抬起  
  104.                 if (canLoad()) {  
  105.                     loadData();  
  106.                 }  
  107.                 break;  
  108.             default:  
  109.                 break;  
  110.         }  
  111.   
  112.         return super.dispatchTouchEvent(event);  
  113.     }  
  114.   
  115.     /** 
  116.      * 是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作. 
  117.      *  
  118.      * @return 
  119.      */  
  120.     private boolean canLoad() {  
  121.         return isBottom() && !isLoading && isPullUp();  
  122.     }  
  123.   
  124.     /** 
  125.      * 判断是否到了最底部 
  126.      */  
  127.     private boolean isBottom() {  
  128.   
  129.         if (mListView != null && mListView.getAdapter() != null) {  
  130.             return mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1);  
  131.         }  
  132.         return false;  
  133.     }  
  134.   
  135.     /** 
  136.      * 是否是上拉操作 
  137.      *  
  138.      * @return 
  139.      */  
  140.     private boolean isPullUp() {  
  141.         return (mYDown - mLastY) >= mTouchSlop;  
  142.     }  
  143.   
  144.     /** 
  145.      * 如果到了最底部,而且是上拉操作.那么执行onLoad方法 
  146.      */  
  147.     private void loadData() {  
  148.         if (mOnLoadListener != null) {  
  149.             // 设置状态  
  150.             setLoading(true);  
  151.             //  
  152.             mOnLoadListener.onLoad();  
  153.         }  
  154.     }  
  155.   
  156.     /** 
  157.      * @param loading 
  158.      */  
  159.     public void setLoading(boolean loading) {  
  160.         isLoading = loading;  
  161.         if (isLoading) {  
  162.             mListView.addFooterView(mListViewFooter);  
  163.         } else {  
  164.             mListView.removeFooterView(mListViewFooter);  
  165.             mYDown = 0;  
  166.             mLastY = 0;  
  167.         }  
  168.     }  
  169.   
  170.     /** 
  171.      * @param loadListener 
  172.      */  
  173.     public void setOnLoadListener(OnLoadListener loadListener) {  
  174.         mOnLoadListener = loadListener;  
  175.     }  
  176.   
  177.     @Override  
  178.     public void onScrollStateChanged(AbsListView view, int scrollState) {  
  179.   
  180.     }  
  181.   
  182.     @Override  
  183.     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,  
  184.             int totalItemCount) {  
  185.         // 滚动时到了最底部也可以加载更多  
  186.         if (canLoad()) {  
  187.             loadData();  
  188.         }  
  189.     }  
  190.   
  191.     /** 
  192.      * 加载更多的监听器 
  193.      *  
  194.      * @author mrsimple 
  195.      */  
  196.     public static interface OnLoadListener {  
  197.         public void onLoad();  
  198.     }  
  199. }  

listview_footer.xml:
[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="wrap_content"  
  5.     android:background="@color/umeng_comm_comments_bg"  
  6.     android:gravity="center"  
  7.     android:paddingBottom="8dip"  
  8.     android:paddingTop="5dip" >  
  9.   
  10.     <ProgressBar  
  11.         android:id="@+id/pull_to_refresh_load_progress"  
  12.         style="@android:style/Widget.ProgressBar.Small.Inverse"  
  13.         android:layout_width="wrap_content"  
  14.         android:layout_height="wrap_content"  
  15.         android:layout_centerVertical="true"  
  16.         android:layout_centerHorizontal="true"  
  17.         android:paddingRight="100dp"  
  18.         android:indeterminate="true" />  
  19.   
  20.     <TextView  
  21.         android:id="@+id/pull_to_refresh_loadmore_text"  
  22.         android:layout_width="fill_parent"  
  23.         android:layout_height="wrap_content"  
  24.         android:layout_gravity="center"  
  25.         android:gravity="center"  
  26.         android:paddingTop="5dip"  
  27.         android:text="@string/load"  
  28.         android:textAppearance="?android:attr/textAppearanceMedium"  
  29.         android:textColor="@android:color/darker_gray"  
  30.         android:textSize="14sp"  
  31.         android:textStyle="bold" />  
  32.   
  33. </RelativeLayout>  

使用示例

refresh.xml布局文件:
[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <myview.RefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:id="@+id/swipe_layout"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent" >  
  6.   
  7.     <ListView  
  8.         android:id="@+id/listview"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="match_parent" >  
  11.     </ListView>  
  12.   
  13. </myview.RefreshLayout>  

activity中的使用 : 
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * @author mrsimple 
  3.  */  
  4. public class MainActivity extends Activity {  
  5.   
  6.     @Override  
  7.     protected void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.     
  10.         setContentView(R.layout.refresh);  
  11.   
  12.         // 模拟一些数据  
  13.         final List<String> datas = new ArrayList<String>();  
  14.         for (int i = 0; i < 20; i++) {  
  15.             datas.add("item - " + i);  
  16.         }  
  17.   
  18.         // 构造适配器  
  19.         final BaseAdapter adapter = new ArrayAdapter<String>(this,  
  20.                 android.R.layout.simple_list_item_1,  
  21.                 datas);  
  22.         // 获取listview实例  
  23.         ListView listView = (ListView) findViewById(R.id.listview);  
  24.         listView.setAdapter(adapter);  
  25.   
  26.         // 获取RefreshLayout实例  
  27.         final RefreshLayout myRefreshListView = (RefreshLayout)  
  28.                 findViewById(R.id.swipe_layout);  
  29.   
  30.         // 设置下拉刷新时的颜色值,颜色值需要定义在xml中  
  31.         myRefreshListView  
  32.                 .setColorScheme(R.color.umeng_comm_text_topic_light_color,  
  33.                         R.color.umeng_comm_yellow, R.color.umeng_comm_green,  
  34.                         R.color.umeng_comm_linked_text);  
  35.         // 设置下拉刷新监听器  
  36.         myRefreshListView.setOnRefreshListener(new OnRefreshListener() {  
  37.   
  38.             @Override  
  39.             public void onRefresh() {  
  40.   
  41.                 Toast.makeText(MainActivity.this"refresh", Toast.LENGTH_SHORT).show();  
  42.   
  43.                 myRefreshListView.postDelayed(new Runnable() {  
  44.   
  45.                     @Override  
  46.                     public void run() {  
  47.                         // 更新数据  
  48.                         datas.add(new Date().toGMTString());  
  49.                         adapter.notifyDataSetChanged();  
  50.                         // 更新完后调用该方法结束刷新  
  51.                         myRefreshListView.setRefreshing(false);  
  52.                     }  
  53.                 }, 1000);  
  54.             }  
  55.         });  
  56.   
  57.         // 加载监听器  
  58.         myRefreshListView.setOnLoadListener(new OnLoadListener() {  
  59.   
  60.             @Override  
  61.             public void onLoad() {  
  62.   
  63.                 Toast.makeText(MainActivity.this"load", Toast.LENGTH_SHORT).show();  
  64.   
  65.                 myRefreshListView.postDelayed(new Runnable() {  
  66.   
  67.                     @Override  
  68.                     public void run() {  
  69.                         datas.add(new Date().toGMTString());  
  70.                         adapter.notifyDataSetChanged();  
  71.                         // 加载完后调用该方法  
  72.                         myRefreshListView.setLoading(false);  
  73.                     }  
  74.                 }, 1500);  
  75.   
  76.             }  
  77.         });  
  78.     }  
  79.   
  80.     }  

效果图





github链接 : 下拉刷新库 。
示例在android_my_pull_demo工程中,进入demo后点击最后一个按钮查看效果即可。注意,在刷新和加载时,需要有一定的延时才能看到效果,这里我们用postDelay来模拟网络请求等延时操作,否则将看不到加载效果。这里只提供一个实现思路,代码不太完善,需要用的请自行完善并测试。

注意
如果出现HeaderViewListAdapter转换异常,那么请使用RefreshLvLayout中的setAdapter函数为ListView设置Adapter,
这样可以确保在设置Adapter之前已经添加了Footer。

3
0 0
原创粉丝点击