背景知识

ListView使用非常广泛,对于使用ListView的应用来说,下拉刷新是必不可少要实现的功能。

我们常用的微博、网易新闻,搜狐新闻都使用了这一功能,如下图所示。

    微博

搜狐新闻


具体学习:

首先分析下拉刷新的具体操作过程:

用户手指在ListView上按下往下拉----->出现一个提示的View在ListView顶部----->ListView内容更新,顶部的提示View消失

   具体实现步骤:

   1.创建继承自ListView的RefreshListView,并添加顶部提示View

   

public class RefreshListView extends ListView {View header;// 顶部提示Viewpublic RefreshListView(Context context) {super(context);initView(context);}public RefreshListView(Context context, AttributeSet attrs) {super(context, attrs);initView(context);}public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView(context);}private void initView(Context context) {// LayoutInflater作用是加载布局LayoutInflater inflater = LayoutInflater.from(context);header = inflater.inflate(R.layout.header_layout, null);this.addHeaderView(header);}
}

顶部提示View布局文件 header_layout.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    <RelativeLayout
 8        android:layout_width="match_parent"
 9        android:layout_height="wrap_content"
10        android:paddingTop="10dip"
11        android:paddingBottom="10dip"
12        >
13        <LinearLayout
14            android:layout_width="wrap_content"
15            android:layout_height="wrap_content"
16            android:orientation="vertical"
17            android:id="@+id/layout"
18            android:layout_centerInParent="true"
19            android:gravity="center"
20            >
21            <!-- 提示文字 -->
22            <TextView
23                android:id="@+id/tips"
24                android:layout_width="wrap_content"
25                android:layout_height="wrap_content"
26                android:text="下拉可以刷新"
27                />
28            <!-- 距上次更新至今的时间 -->
29            <TextView
30                android:id="@+id/time"
31                android:layout_width="wrap_content"
32                android:layout_height="wrap_content"
33                />
34
35        </LinearLayout>
36        <!-- 箭头 -->
37        <ImageView
38            android:id="@+id/arrow"
39            android:layout_width="wrap_content"
40            android:layout_height="wrap_content"
41            android:layout_toLeftOf="@id/layout"
42            android:src="@drawable/pull_to_refresh_arrow"
43            />
44        <!-- 更新进度条 -->
45        <ProgressBar
46            android:id="@+id/progress"
47            android:layout_width="wrap_content"
48            android:layout_height="wrap_content"
49            style="?android:attr/progressBarStyleSmall"
50            android:layout_toLeftOf="@id/layout"
51            android:visibility="gone"
52            />
53    </RelativeLayout>
54 </LinearLayout>

运行效果图:

2.由上图可以知道,默认加载header是显示出来的。默认我们应该隐藏顶部提示布局header。

 1 private void initView(Context context){
 2         //LayoutInflater作用是加载布局
 3         LayoutInflater inflater = LayoutInflater.from(context);
 4         header = inflater.inflate(R.layout.header_layout, null);
 5         measureView(header);
 6         headerHeight = header.getMeasuredHeight();
 7         topPadding(-headerHeight);
 8         this.addHeaderView(header);
 9     }
10     /**
11      * 设置顶部布局的上边距
12      * @param topPadding
13      */
14     private void topPadding(int topPadding){
15         //设置顶部提示的边距
16         //除了顶部用参数值topPadding外,其他三个用header默认的值
17         header.setPadding(header.getPaddingLeft(), topPadding,
18                 header.getPaddingRight(), header.getPaddingBottom());
19         //使header无效,将来调用onDraw()重绘View
20         header.invalidate();
21     }
22     /**
23      * 通知父布局,占用的宽和高
24      */
25     private void measureView(View view){
26         //LayoutParams are used by views to tell their parents
27         //how they want to be laid out.
28         //LayoutParams被view用来告诉它们的父布局它们应该被怎样安排
29         ViewGroup.LayoutParams p = view.getLayoutParams();
30         if(p==null){
31             //两个参数:width,height
32             p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
33                     ViewGroup.LayoutParams.WRAP_CONTENT);
34         }
35         //getChildMeasureSpec:获取子View的widthMeasureSpec、heightMeasureSpec值
36         int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
37         int height;
38         int tempHeight = p.height;
39         if(tempHeight>0){
40             height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
41         }else{
42             height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
43         }
44         view.measure(width, height);
45     }

运行效果图:

3.监听用户滑动屏幕操作

1.实现OnScrollListener接口

2.根据用户按下、移动、抬起手势来设置不同的响应事件

3.顶部提示View--header有四种状态:

1. 正常状态(NONE)

2.提示用户下拉可以刷新(PULL)

3.提示用户释放可以刷新(RELEASE)

4.提示用户正在刷新状态(REFREASH)

 1 public class RefreshListView extends ListView implements OnScrollListener{
 2         View header;//下拉刷新时出现的顶部布局View
 3     int headerHeight;//header的高度
 4     int firstVisibleItem;//当前界面第一个可见的item的位置
 5
 6     boolean isFlag;//标志,是在当前显示的listView是在listView最顶端时按下额
 7     int startY;//用户按下的Y值
 8
 9
10     int state;//当前状态
11     final int NONE = 0;//正常状态
12     final int PULL = 1;//提示下拉状态
13     final int RELEASE = 2;//提示释放状态
14     final int REFRESH = 3;//提示正在刷新状态
15
16
17         @Override
18     public void onScrollStateChanged(AbsListView view, int scrollState) {
19         // TODO Auto-generated method stub
20         this.scrollState = scrollState;
21     }
22     @Override
23     public void onScroll(AbsListView view, int firstVisibleItem,
24             int visibleItemCount, int totalItemCount) {
25         // TODO Auto-generated method stub
26         this.firstVisibleItem = firstVisibleItem;
27     }
28     @Override
29     public boolean onTouchEvent(MotionEvent ev) {
30         // TODO Auto-generated method stub
31         switch (ev.getAction()) {
32         case MotionEvent.ACTION_DOWN:
33             if(firstVisibleItem == 0){
34                 isFlag = true;//ListView最顶端按下,标志值设为真
35                 startY = (int)ev.getY();
36             }
37             break;
38         case MotionEvent.ACTION_MOVE:
39             onMove(ev);
40             break;
41         case MotionEvent.ACTION_UP:
42             if(state == RELEASE){
43                 state = REFRESH;
44                 //加载数据
45                 refreshViewByState();
46                 iRefreshlistener.onRefresh();
47             }else if(state == PULL){
48                 state = NONE;
49                 isFlag = false;
50                 refreshViewByState();
51             }
52             break;
53         }
54         return super.onTouchEvent(ev);
55     

onMove()方法----->根据用户下拉距离的不同设置不同的响应方法

 1 private void onMove(MotionEvent ev){
 2         //如果不是最顶端按下,则直接返回
 3         if(!isFlag){
 4             return;
 5         }
 6         int currentY = (int)ev.getY();//当前的Y值
 7         int space = currentY - startY;//用户向下拉的距离
 8         int topPadding = space - headerHeight;//顶部提示View距顶部的距离值
 9         switch (state) {
10         //正常状态
11         case NONE:
12             if(space>0){
13                 state = PULL;//下拉的距离大于0,则将状态改为PULL(提示下拉更新)
14                 refreshViewByState();//根据状态的不同更新View
15             }
16             break;
17         case PULL:
18             topPadding(topPadding);
19             if(space>headerHeight+30//下拉的距离大于header的高度加30且用户滚动屏幕,手指仍在屏幕上
20                     &&scrollState == SCROLL_STATE_TOUCH_SCROLL ){
21                 state = RELEASE;//将状态改为RELEASE(提示松开更新)
22                 refreshViewByState();
23             }
24             break;
25         case RELEASE:
26             topPadding(topPadding);
27             if(space<headerHeight+30){//用户下拉的距离不够
28                 state = PULL;         //将状态改为PULL
29                 refreshViewByState();
30             }else if(space<=0){  //用户下拉的距离为非正值
31                 state = NONE;    //将状态改为NONE
32                 isFlag = false;  //标志改为false
33                 refreshViewByState();
34             }
35             break;
36         }
37     }

根据不同状态,改变用户界面的显示

 1     /**
 2      * 根据当前状态state,改变界面显示
 3      * state:
 4      *      NONE:无操作
 5      *      PULL:下拉可以刷新
 6      *      RELEASE:松开可以刷新
 7      *      REFREASH:正在刷新
 8      */
 9     private void refreshViewByState(){
10         //提示
11         TextView tips = (TextView)header.findViewById(R.id.tips);
12         //箭头
13         ImageView arrow = (ImageView)header.findViewById(R.id.arrow);
14         //进度条
15         ProgressBar progress = (ProgressBar)header.findViewById(R.id.progress);
16         //箭头的动画效果1,由0度转向180度,即箭头由朝下转为朝上
17         RotateAnimation animation1 = new RotateAnimation(0, 180,
18                 RotateAnimation.RELATIVE_TO_SELF,0.5f,
19                 RotateAnimation.RELATIVE_TO_SELF,0.5f);
20         animation1.setDuration(500);
21         animation1.setFillAfter(true);
22         //箭头的动画效果2,由180度转向0度,即箭头由朝上转为朝下
23         RotateAnimation animation2 = new RotateAnimation(180, 0,
24                 RotateAnimation.RELATIVE_TO_SELF,0.5f,
25                 RotateAnimation.RELATIVE_TO_SELF,0.5f);
26         animation2.setDuration(500);
27         animation2.setFillAfter(true);
28
29         switch (state) {
30         case NONE:                     //正常状态
31             arrow.clearAnimation();    //清除箭头动画效果
32             topPadding(-headerHeight); //设置header距离顶部的距离
33             break;
34
35         case PULL:                                //下拉状态
36             arrow.setVisibility(View.VISIBLE);    //箭头设为可见
37             progress.setVisibility(View.GONE);    //进度条设为不可见
38             tips.setText("下拉可以刷新");           //提示文字设为"下拉可以刷新"
39             arrow.clearAnimation();               //清除之前的动画效果,并将其设置为动画效果2
40             arrow.setAnimation(animation2);
41             break;
42
43         case RELEASE:                            //下拉状态
44             arrow.setVisibility(View.VISIBLE);   //箭头设为可见
45             progress.setVisibility(View.GONE);   //进度条设为不可见
46             tips.setText("松开可以刷新");          //提示文字设为"松开可以刷新"
47             arrow.clearAnimation();              //清除之前的动画效果,并将其设置为动画效果2
48             arrow.setAnimation(animation1);
49             break;
50
51         case REFRESH:                             //更新状态
52             topPadding(50);                       //距离顶部的距离设置为50
53             arrow.setVisibility(View.GONE);       //箭头设为不可见
54             progress.setVisibility(View.VISIBLE); //进度条设为可见
55             tips.setText("正在刷新...");            //提示文字设为""正在刷新..."
56             arrow.clearAnimation();                //清除动画效果
57             break;
58
59         }
60     }

4.更新数据      由于在RefreshListView中不能直接更新数据,必须设置回调接口来实现更新数据这一功能。

     IRefreshListener iRefreshlistener;//刷新数据的接口
      ...public void setInterface(IRefreshListener listener){this.iRefreshlistener = listener;}/*** 刷新数据接口* @author lenovo**/public interface IRefreshListener{public void onRefresh();}

在MainActivity中实现IRefreshListener接口并实现onRefresh()方法

public class MainActivity extends Activity implements IRefreshListener{......@Overridepublic void onRefresh() {// TODO Auto-generated method stub//handler设置刷新延时效果Handler handler = new Handler();handler.postDelayed(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stub//获取最新数据
                getRefreshData();//通知界面显示
                adapter.notifyDataSetChanged();//通知listView刷新数据完毕
                listView.refreshComplete();}}, 2000);
}

刷新完成的操作:

 1 public void refreshComplete(){
 2         state = NONE;   //状态设为正常状态
 3         isFlag = false; //标志设为false
 4         refreshViewByState();
 5         //设置提示更新时间间隔
 6         Time t = new Time();
 7         t.setToNow();
 8         time = t.hour*60+t.minute-updateTime;
 9         updateTime = t.hour*60+t.minute;
10         TextView lastUpdateTime = (TextView)findViewById(R.id.time);
11         lastUpdateTime.setText(time+"分钟前更新");
12     }

Demo运行效果图

想及时获取最新最有用的Android开发干货,请关注我

转载请注明网址:http://www.cnblogs.com/JohnTsai

如果觉得本文对你的学习工作有所帮助,不妨在右下方点推荐一下,谢谢。

联系我:JohnTsai.Work@gmail.com

转载于:https://www.cnblogs.com/JohnTsai/p/4150475.html

Android学习之——ListView下拉刷新相关推荐

  1. android-ultra-pull-to-refresh list,[Android]Ultra-Pull-To-Refresh之listview下拉刷新、上拉加载的用例...

    前言 app中最常见的场景莫过于下拉刷新和自动加载的功能了,最经典的开源组件就是 本次demo的编辑环境为android studio,java1.8 截图 使用 1.本示例依赖jar如下: depe ...

  2. android中上拉下滑布局,3年以上勿进!最简单的Android自定义ListView下拉刷新与上拉加载,代码直接拿去用~...

    本文主要针对开发新手,手写实现一个最简单Android自定义listview下拉刷新和上拉加载demo. 不喜可喷,欢迎大佬留言指点. 效果图 一:编写需要在ListView中增加头加载的布局文件,与 ...

  3. 基于Android的计步器(Pedometer)的讲解(六)——ListView下拉刷新页面

    计步器(Pedometer)整个项目的源代码,最近做了比较大的修改,可能以前下载的不能运行,感兴趣的朋友可以下载来看看(记得帮小弟在github打个星~) https://github.com/296 ...

  4. 浅谈Android列表ListView下拉刷新控件的实现(一)

    ListView下拉刷新的功能到处可见,很多app客户端都存在,比如QQ空间好友动态下拉刷新,网易新闻内容下拉刷新等.相信很多人已经把这个功能运用的很溜,妥妥的吧,接下就来实现一下功能,有个不爽的一点 ...

  5. Android ListView下拉刷新时卡的问题解决小技巧

    问题:ListView下拉刷新时看上去非常的卡 解决方案: 在BaseAdapter的getView方法中,有三个参数 public View getView(int position, View c ...

  6. 开启Fluter基础之旅五-------ListView 3D滚动、Flipper效果、ListView下拉刷新上拉加载、ListView重排序...

    继续来来操练Flutter的基础,对于Flutter的学习也有一段时间了,实操项目还木有做过,所以待这次基础学完之后就打算用一个项目对之前所学的进行一下巩固,不然光学这些零散的知识点最终还是不会Flu ...

  7. ListView下拉刷新、上拉载入更多之封装改进

    在Android中ListView下拉刷新.上拉载入更多示例一文中,Maxwin兄给出的控件比较强大,前面有详细介绍,但是有个不足就是,里面使用了一些资源文件,包括图片,String,layout,这 ...

  8. Flutter ListView 下拉刷新与上拉加载更多

    ListView 下拉刷新与上拉加载更多 import 'dart:async'; import 'package:flutter/material.dart';/*** 有状态StatefulWid ...

  9. Android仿苹果版QQ下拉刷新实现(三)

    前言 第三篇下拉刷新的博客来的稍微有点晚,因为前两篇的博客访问量一直不是很高,所以博主花了点时间修改了整体的Demo效果,处理了很多极端下拉情况下的显示问题,给大家呈现一个完美的下拉刷新控件.因为本文 ...

最新文章

  1. javascript js异步加载
  2. python运行慢-提高python运行速度的几个技巧
  3. Echarts的简单使用
  4. Spring Boot中如何干掉if else
  5. hdu 3501 欧拉函数
  6. 苹果公司的新的编程语言 Swift 高级语言()两--基本数据类型
  7. iOS点击获取短信验证码按钮
  8. sql服务器时间不正确,使用更改 CPU 频率的实用工具或技术时,SQL Server 计时值可能不正确...
  9. 客户端渲染(CSR)
  10. win7系统控制面板在哪打开,win7电脑打开控制面板方法
  11. 用python绘制心形_如何利用Python绘制一个爱心
  12. CS231n李飞飞计算机视觉 神经网络训练细节part1上
  13. 标准ASCII编码表
  14. 非视距(非视域)成像(Non-Line-of-Sight,NLOS Imaging) Github开源代码合集
  15. 加速度传感器的计步算法Pedometer
  16. 桌面窗口管理器(dwn.exe)内存占用大怎么解决
  17. 曾国藩:统领30万湘军,只靠这4句话
  18. python鞋子_Micropython 鞋码匹配仪(标题图与内容无关)
  19. stata学习笔记|异方差问题
  20. STC全系列头文件及用户手册(官方资源的获取方法)

热门文章

  1. IntelliJ IDEA中怎么创建xml文件?
  2. 平凡函数依赖是什么?
  3. php 生成器 封装,php生成器
  4. matlab 箱图不显示异常值_无功功率显示值与计算值不匹配?
  5. c if标签怎么用android,android – 使用NDK将YUV解码为C/C++中的RGB
  6. linux arm交叉编译ko,Ubuntu嵌入式交叉编译环境arm-linux-gcc
  7. PHP判断客户端协议类型是否为https
  8. STM32F103单片机读取芯片自身ID
  9. STM8学习笔记---PWM变频输出
  10. Pytorch:神经网络工具箱nn