金田

下拉刷新是一种比较常用的效果,Android 5.0之前官方并未提供类似的控件,App中主要是用的第三方库,例如PullToRefresh,ActionBar-PullToRefresh等。刚好现在项目中需要处理 Android 5.0 材质设计部分的东西,就顺带学习下这部分。

大体介绍一下;

  1. SwipeRefreshLayout是Google在support v4 19.1版本的library更新的一个下拉刷新控件 (android-support-v4.jar)
  2. 目前只支持下拉刷新,不支持上拉加载更多的操作(需要自行进行扩展)
  3. 作为官方自带的控件,相对能能够保证比较好的通用性及风格(这里不包括各种自家定制的系统 L)
  4. SwipeRefreshLayout继承于ViewGroup,ViewGroup中可以包含其他不同控件,so UI定制起来也相对比较容易
  5. 使用起来比较方便,可以很容易的实现Google Now的刷新效果

SwipeRefreshLayout布局中目前只能包含一个子布局,使用侦听机制来通知刷新事件。例如当用户使用下拉手势时,SwipeRefreshLayout会触发OnRefreshListener,然后刷新事件会在onRefresh()方法中进行处理。当需要结束刷新的时候,可以调用setRefreshing(false)。如果要禁用手势和进度动画,调用setEnabled(false)即可。

接下来介绍一下其大体使用方法:

1.布局文件(示例代码)

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent" >
  6.  
  7. <android.support.v4.widget.SwipeRefreshLayout
  8. android:id="@+id/id_explore_swipe_ly"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:background="#ffffff" >
  12.  
  13. <ListView
  14. android:id="@+id/id_listview"
  15. android:layout_width="match_parent"
  16. android:layout_height="match_parent" >
  17. </ListView>
  18. </android.support.v4.widget.SwipeRefreshLayout>
  19.  
  20. </FrameLayout>

2.java逻辑代码:

首先需要实现 SwipeRefreshLayout.OnRefreshListener  接口,然后重写方法 onRefresh():

  1. @Override
  2. public void onRefresh() {
  3. new Handler().postDelayed(new Runnable() {
  4.  
  5. @Override
  6. public void run() {
  7. // 设置SwipeRefreshLayout当前是否处于刷新状态,一般是在请求数据的时候设置为true,在数据被加载到View中后,设置为false。
  8. mSwipeRefreshLayout.setRefreshing(false);
  9. }
  10. }, 3000);
  11. }

现在我们初始化该控件:

  1. public void initSwipeRefreshParameters() {
  2. // 设置进度条的颜色变化,最多可以设置4种颜色
  3. mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_green_dark, android.R.color.holo_green_light,
  4. android.R.color.holo_orange_light, android.R.color.holo_red_light);
  5. // 设置下拉监听,当用户下拉的时候会去执行回调
  6. mSwipeRefreshLayout.setOnRefreshListener(this);
  7. // 调整进度条距离屏幕顶部的距离
  8. mSwipeRefreshLayout.setProgressViewOffset(false, 0,
  9. (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources().getDisplayMetrics()));
  10. }

以上是基本用法,现在来大体介绍一下定制支持上拉加载的部分,演示图示:

图1 上拉加载效果示意图

首先实现SwipeRefreshLayout的重写:

  1. public class mySwipeRefreshLayout extends SwipeRefreshLayout implements OnScrollListener {
  2.  
  3. private int mTouchSlop;
  4. private ListView mListView;
  5. private OnLoadListener mOnLoadListener;
  6. private View mListViewFooter;
  7. private int mYDown;
  8. private int mLastY;
  9. private boolean isLoading = false;
  10.  
  11. public mySwipeRefreshLayout(Context context) {
  12. this(context, null);
  13. }
  14.  
  15. public mySwipeRefreshLayout(Context context, AttributeSet attrs) {
  16. super(context, attrs);
  17.  
  18. mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
  19.  
  20. mListViewFooter = LayoutInflater.from(context).inflate(R.layout.listview_footer, null, false);
  21. }
  22.  
  23. @Override
  24. protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
  25. super.onLayout(changed, left, top, right, bottom);
  26.  
  27. // 初始化ListView对象
  28. if (mListView == null) {
  29. getListView();
  30. }
  31. }
  32.  
  33. private void getListView() {
  34. int childs = getChildCount();
  35. if (childs > 0) {
  36. View childView = getChildAt(0);
  37. if (childView instanceof ListView) {
  38. mListView = (ListView) childView;
  39. // 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载
  40. mListView.setOnScrollListener(this);
  41. }
  42. }
  43. }
  44.  
  45. public void setListView(ListView list) {
  46. this.mListView = list;
  47. setLoading(true);
  48. this.mListView.setOnScrollListener(this);
  49. }
  50.  
  51. @Override
  52. public boolean dispatchTouchEvent(MotionEvent event) {
  53. final int action = event.getAction();
  54.  
  55. switch (action) {
  56. case MotionEvent.ACTION_DOWN:
  57. mYDown = (int) event.getRawY();
  58. break;
  59. case MotionEvent.ACTION_MOVE:
  60. mLastY = (int) event.getRawY();
  61. break;
  62. case MotionEvent.ACTION_UP:
  63. if (canLoad()) {
  64. loadData();
  65. }
  66. break;
  67. default:
  68. break;
  69. }
  70.  
  71. return super.dispatchTouchEvent(event);
  72. }
  73.  
  74. /**
  75. * @方法说明:是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作.
  76. */
  77. private boolean canLoad() {
  78. return isBottom() && !isLoading && isPullUp();
  79. }
  80.  
  81. /**
  82. * @方法说明:判断是否到了最底部
  83. */
  84. private boolean isBottom() {
  85. if (mListView != null && mListView.getAdapter() != null) {
  86. return mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1);
  87. }
  88. return false;
  89. }
  90.  
  91. /**
  92. * @方法说明:是否是上拉操作
  93. */
  94. private boolean isPullUp() {
  95. return (mYDown - mLastY) >= mTouchSlop;
  96. }
  97.  
  98. /**
  99. * @方法说明: 如果到了最底部,而且是上拉操作.那么执行onLoad方法
  100. */
  101. private void loadData() {
  102. if (mOnLoadListener != null) {
  103. mOnLoadListener.onLoad();
  104. }
  105. // 设置状态
  106. setLoading(true);
  107. }
  108.  
  109. /**
  110. * @方法说明:设置刷新
  111. */
  112. public void setLoading(boolean loading) {
  113. isLoading = loading;
  114. if (mListView != null && mListView.getFooterViewsCount() > 0)
  115. mListView.removeFooterView(mListViewFooter);
  116. if (isLoading) {
  117. if (mListView != null && mListView.getFooterViewsCount() <= 0)
  118. mListView.addFooterView(mListViewFooter);
  119. } else {
  120. mYDown = 0;
  121. mLastY = 0;
  122. }
  123. }
  124.  
  125. public void setOnLoadListener(OnLoadListener loadListener) {
  126. mOnLoadListener = loadListener;
  127. }
  128.  
  129. @Override
  130. public void onScrollStateChanged(AbsListView view, int scrollState) {
  131. }
  132.  
  133. @Override
  134. public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
  135. if (isFastDoubleClick(100))
  136. return;
  137.  
  138. // 滚动时到了最底部也可以加载更多
  139. isLoading = false;
  140. if (canLoad()) {
  141. loadData();
  142. }
  143. }
  144.  
  145. public View getmListViewFooter() {
  146. return mListViewFooter;
  147. }
  148.  
  149. /**
  150. * @类描述:加载更多的监听器
  151. */
  152. public static interface OnLoadListener {
  153. public void onLoad();
  154. }
  155.  
  156. private static long lastClickTime;
  157.  
  158. public static boolean isFastDoubleClick(long times) {
  159. long time = System.currentTimeMillis();
  160. long timeD = time - lastClickTime;
  161. if (0 < timeD && timeD < times) {
  162. return true;
  163. }
  164. lastClickTime = time;
  165. return false;
  166. }
  167. }

MainActivity.java

  1. public class MainActivity extends Activity {
  2. private mydapter adapter;
  3.  
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7.  
  8. setContentView(R.layout.main);
  9. adapter = new mydapter();
  10.  
  11. // 获取RefreshLayout实例
  12. final mySwipeRefreshLayout myRefreshListView = (mySwipeRefreshLayout) findViewById(R.id.swipe_layout);
  13.  
  14. // 获取listview实例
  15. ListView listView = (ListView) findViewById(R.id.listview);
  16. myRefreshListView.setListView(listView);
  17. listView.setAdapter(adapter);
  18.  
  19. // 设置进度条的颜色变化,最多可以设置4种颜色
  20. myRefreshListView.setColorSchemeResources(android.R.color.holo_green_dark, android.R.color.holo_green_light,
  21. android.R.color.holo_orange_light, android.R.color.holo_red_light);
  22. // 设置下拉刷新监听器
  23. myRefreshListView.setOnRefreshListener(new OnRefreshListener() {
  24.  
  25. @Override
  26. public void onRefresh() {
  27. Toast.makeText(MainActivity.this, "refresh", Toast.LENGTH_SHORT).show();
  28. myRefreshListView.postDelayed(new Runnable() {
  29.  
  30. @Override
  31. public void run() {
  32. // 更新完后调用该方法结束刷新
  33. myRefreshListView.setRefreshing(false);
  34.  
  35. adapter.getData().clear();
  36. // 模拟一些数据
  37. for (int i = 0; i < 20; i++) {
  38. adapter.addData("liu hhh " + i);
  39. }
  40. }
  41. }, 1000);
  42. }
  43. });
  44.  
  45. // 加载监听器
  46. myRefreshListView.setOnLoadListener(new OnLoadListener() {
  47.  
  48. @Override
  49. public void onLoad() {
  50. myRefreshListView.postDelayed(new Runnable() {
  51. @Override
  52. public void run() {
  53. // 加载完后调用该方法
  54. adapter.addData(new Date().toGMTString());
  55. adapter.notifyDataSetChanged();
  56. myRefreshListView.setLoading(false);
  57. }
  58. }, 1500);
  59. }
  60. });
  61. }
  62.  
  63. class mydapter extends BaseAdapter {
  64. List<String> datas = new ArrayList<String>();
  65.  
  66. public mydapter() {
  67. // 模拟一些数据
  68. for (int i = 0; i < 20; i++) {
  69. datas.add("item - " + i);
  70. }
  71. }
  72.  
  73. public void setData(List<String> data) {
  74. this.datas = data;
  75. notifyDataSetChanged();
  76. }
  77.  
  78. public void addData(String str) {
  79. this.datas.add(str);
  80. notifyDataSetChanged();
  81. }
  82.  
  83. public List<String> getData() {
  84. return datas;
  85. }
  86.  
  87. @Override
  88. public int getCount() {
  89. return datas.size();
  90. }
  91.  
  92. @Override
  93. public Object getItem(int position) {
  94. return datas.get(position);
  95. }
  96.  
  97. @Override
  98. public long getItemId(int position) {
  99. return position;
  100. }
  101.  
  102. @Override
  103. public View getView(int position, View convertView, ViewGroup parent) {
  104. if (convertView == null) {
  105. convertView = MainActivity.this.getLayoutInflater().inflate(R.layout.item, null);
  106. }
  107.  
  108. TextView tv = (TextView) convertView.findViewById(R.id.text);
  109. tv.setText(datas.get(position));
  110.  
  111. return convertView;
  112. }
  113. }
  114. }

listView_footer:

  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/very_light_gray"
  6. android:gravity="center"
  7. android:layout_gravity="center_horizontal"
  8. android:paddingBottom="10dip"
  9. android:paddingTop="10dip" >
  10.  
  11. <ProgressBar
  12. android:id="@+id/pull_to_refresh_load_progress"
  13. style="@android:style/Widget.ProgressBar.Small.Inverse"
  14. android:layout_width="wrap_content"
  15. android:layout_height="wrap_content"
  16. android:layout_centerHorizontal="true"
  17. android:layout_centerVertical="true"
  18. android:indeterminate="true"
  19. android:paddingRight="10dp" />
  20.  
  21. <TextView
  22. android:id="@+id/pull_to_refresh_loadmore_text"
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:gravity="center_vertical"
  26. android:layout_toRightOf="@+id/pull_to_refresh_load_progress"
  27. android:paddingTop="5dip"
  28. android:text="@string/loading"
  29. android:textAppearance="?android:attr/textAppearanceMedium"
  30. android:textColor="@android:color/darker_gray"
  31. android:textSize="14sp"
  32. android:textStyle="bold" />
  33.  
  34. </RelativeLayout>

main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <com.example.demo.mySwipeRefreshLayout 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. </com.example.demo.mySwipeRefreshLayout>

item.xml:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6.  
  7. <TextView
  8. android:id="@+id/text"
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:gravity="left"
  12. android:padding="10dp"
  13. android:text="wo lai le"
  14. android:background="@color/very_light_gray"/>
  15.  
  16. <View
  17. android:layout_width="match_parent"
  18. android:layout_height="1dp"
  19. android:background="@android:color/white"/>
  20.  
  21. </LinearLayout>

参考链接

http://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html

版权所有,转载须注明作者(金田)及出处(原文

Android 5.0 之SwipeRefreshLayout的更多相关文章

  1. Android下拉刷新-SwipeRefreshLayout,RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout)

    SwipeRefrshLayout是Google官方更新的一个Widget,可以实现下拉刷新的效果.该控件集成自ViewGroup在support-v4兼容包下,不过我们需要升级supportlibr ...

  2. 【Android - V】之SwipeRefreshLayout的使用

    SwipeRefreshLayout是Android V4.V7包中的一个控件,是Google给我们提供的一个下拉刷新的布局控件,可以轻松完成下拉刷新. SwipeRefreshLayout的特点是其 ...

  3. Android下拉刷新-SwipeRefreshLayout

    现在市面上新闻类的App基本上都有下拉刷新,算是一个标配吧,网上关于下拉刷新的博客也有很多,实现方式可以使用开源的PullToRefresh,自定义ListView,或者可以直接使用LineLayOu ...

  4. android 5.0新特性学习总结之下拉刷新(一)

    android 5.0 后google最终在 support v4 包下 添加了下拉刷新的控件 项目地址: https://github.com/stormzhang/SwipeRefreshLayo ...

  5. Android下拉刷新SwipeRefreshLayout简单用法

    之前一直都想用下拉刷新,感觉上是庞大的工程,所以搁置了.现在学习了一下其实真的超级简单. 看了<第一行代码>以及 https://www.jianshu.com/p/3c402a9e4b7 ...

  6. Android数据存储之Android 6.0运行时权限下文件存储的思考

    前言: 在我们做App开发的过程中基本上都会用到文件存储,所以文件存储对于我们来说是相当熟悉了,不过自从Android 6.0发布之后,基于运行时权限机制访问外置sdcard是需要动态申请权限,所以以 ...

  7. Android权限管理之RxPermission解决Android 6.0 适配问题

    前言: 上篇重点学习了Android 6.0的运行时权限,今天还是围绕着Android 6.0权限适配来总结学习,这里主要介绍一下我们公司解决Android 6.0权限适配的方案:RxJava+RxP ...

  8. Android权限管理之Android 6.0运行时权限及解决办法

    前言: 今天还是围绕着最近面试的一个热门话题Android 6.0权限适配来总结学习,其实Android 6.0权限适配我们公司是在今年5月份才开始做,算是比较晚的吧,不过现在Android 6.0以 ...

  9. Android 5.0 到 Android 6.0 + 的深坑之一 之 .so 动态库的适配

    (原创:http://www.cnblogs.com/linguanh) 目录: 前序 一,问题描述 二,为何会如此"无情"? 三,目前存在该问题的知名SDK 四,解决方案,1 对 ...

随机推荐

  1. svn解决方案汇总

    http://blog.csdn.net/superch0054/article/details/38668017

  2. ngnix 一 入门指南

    翻译自:ngnix--Beginner Guide ##ngnix入门指南 本指南给出了nginx的基本介绍,并介绍了可以使用它的完成一些简单任务. 它假定nginx已经安装在读者的机器上. 如果不是 ...

  3. android performClick使用

    performClick 是使用代码主动去调用控件的点击事件(模拟人手去触摸控件) ----------------------------------------- boolean android. ...

  4. Managing linux Shell Jobs

    Managing Shell Jobs   When moving jobs between the foreground and background, it may be useful to ha ...

  5. Python第一课

    一.模块的常用方法 __name__     #主模块name值main __file__    #文件所在的路径+文件名 __doc__    #文件级别的注释 二.函数 参数 参数默认值 可变参数 ...

  6. divmod(a,b)函数

    python每日一函数 - divmod数字处理函数 divmod(a,b)函数 中文说明: divmod(a,b)方法返回的是a//b(除法取整)以及a对b的余数 返回结果类型为tuple 参数: ...

  7. 阿里巴巴iconfont使用方式

    IconFont的作用就是用字体的格式来取代图片.特殊字体的展示,用得比较多的就是一些纯色的图标,具体主要由当前css3属性里的自定义字体(@font-face)来实现. 1.首先在Iconfont- ...

  8. javascript判断浏览器

    function getExplorer() { //IE if (navigator.userAgent.indexOf("MSIE")>=0) { } //Firefox ...

  9. Leetcode 371: Sum of Two Integers(使用位运算实现)

    题目是:Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -. ...

  10. 【转】常用背景色RGB数值

    [转自]http://blog.sina.com.cn/s/blog_8fc890a201013z8h.html