Android开发技术学习之下拉刷新功能的实现

  • 好久没有写博客了,最近都在忙。有时候即使是有时间也会很懒,就会想玩一玩,放松放松!一直都没有什么时间更新我这个菜鸟的博客了。不过今天不一样,我要给大家讲讲怎么实现许多app中下拉刷新的功能。比如腾讯的QQ、新浪微博等等。为什么我会写这篇技术博客,是因为我热爱技术,平时喜欢学习一些比较好玩的demo。故而有了这篇技术博客的诞生。好了,废话不多说了,下面开始进入正题吧!
  • 下拉刷新的功能,相信大家一定都接触过。比如一个界面上显示了一些内容,你只要按住手机的屏幕下拉一定的距离就可以实现刷新的功能,当然你也可以下拉一段距离后抬起你的手,此时就不会刷新了,继续回到界面上。
  • 首先需要你新建一个项目,默认有MainActivity和activity_main.xml布局。且activity_main.xml布局如下所示:
  • 该布局的代码很简单,就引用到自定义的一个view,在项目中的名字叫做MyListView,该类继承了ListView,需要重写构造方法。MyListView类的代码如下所示:
  • -
package com.example.zq.pullfresh;import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;import java.text.SimpleDateFormat;
import java.util.Date;/*** Created by zq on 2016/4/26.*/
public class MyListView extends ListView {private final View viewHeader;private static final byte DONE = 1;private static final byte PULL = 2;private static final byte RELEASE = 3;private static final byte RELEASE_NOT_FRESHING = 4;private byte currentState;private final int height;private TextView tvState, tvTime;private ImageView ivArrow;private ProgressBar pBar;private int downY, moveY, showY;private onRefreshingListener onRefreshingListener;// TODO: 2016/4/26 构造方法public MyListView(Context context, AttributeSet attrs) {super(context, attrs);// TODO: 2016/4/26 构建下拉刷新的布局viewHeader = View.inflate(context, R.layout.layout_header, null);setViews(viewHeader);// TODO: 2016/4/26 控件初始化this.addHeaderView(viewHeader);// TODO: 2016/4/26 添加头部刷新布局viewHeader.measure(0, 0);// TODO: 2016/4/26 精确测量height = viewHeader.getMeasuredHeight();// TODO: 2016/4/26 获取布局的高度viewHeader.setPadding(0, -height, 0, 0);// TODO: 2016/4/26 隐藏刷新布局String strCurrentDate = GetCurrentDate();tvTime.setText(strCurrentDate);// TODO: 2016/4/26 设置系统当前时间currentState = DONE;}private void setViews(View viewHeader) {tvState = (TextView) viewHeader.findViewById(R.id.tv_state);// TODO: 2016/4/26 下拉状态tvTime = (TextView) viewHeader.findViewById(R.id.tv_updateTime);// TODO: 2016/4/26 刷新时间ivArrow = (ImageView) viewHeader.findViewById(R.id.iv_arrow);// TODO: 2016/4/26 下拉时箭头pBar = (ProgressBar) viewHeader.findViewById(R.id.progressBar);// TODO: 2016/4/26 进度条}@Overridepublic boolean onTouchEvent(MotionEvent ev) {int action = ev.getAction();switch (action) {case MotionEvent.ACTION_DOWN:// TODO: 2016/4/26 手势按下if (currentState == DONE) {currentState = PULL;downY = (int) ev.getY();// TODO: 2016/4/26 获取按下时的Y坐标}break;case MotionEvent.ACTION_MOVE:// TODO: 2016/4/27 手势移动if (currentState == PULL) {moveY = (int) ev.getY();// TODO: 2016/4/26 移动时的Y坐标showY = moveY - downY + (-height);// TODO: 2016/4/26 获取下拉显示的长度viewHeader.setPadding(0, showY, 0, 0); TODO: 2016/4/26 下拉的时候慢慢的将布局显示出来// TODO: 2016/4/26 判断向下拉了很久if (showY > height) {ivArrow.setImageResource(R.mipmap.ic_launcher);// TODO: 2016/4/26 将下拉箭头设置为上拉箭头tvState.setText("松开刷新");currentState = RELEASE;}}break;case MotionEvent.ACTION_UP:// TODO: 2016/4/27 手势抬起// TODO: 2016/4/26 下拉了一段距离但是没有刷新的情况if (showY < height) {ivArrow.setImageResource(R.drawable.arrow);// TODO: 2016/4/26 设置下拉箭头ivArrow.setVisibility(View.VISIBLE);// TODO: 2016/4/26 设置下拉箭头可见pBar.setVisibility(View.GONE);tvState.setText("下拉刷新");viewHeader.setPadding(0, -height, 0, 0);// TODO: 2016/4/26 隐藏下拉刷新布局currentState = DONE;}if (currentState == RELEASE) {tvState.setText("正在刷新");pBar.setVisibility(View.VISIBLE);ivArrow.setVisibility(View.GONE);String strCurrentDate = GetCurrentDate();tvTime.setText(strCurrentDate);// TODO: 2016/4/26 设置刷新时间,为系统当前时间// TODO: 2016/4/26 比如联网获取数据,可以让别人调接口if (onRefreshingListener != null) {// TODO: 2016/4/27 主界面回调该方法,但在主界面对该方法做具体的实现this.onRefreshingListener.onRefreshing(this);}}break;}return super.onTouchEvent(ev);}// TODO: 2016/4/26 获取系统当前的日期 格式为:yyyy-MM-dd HH:mm:ssprivate String GetCurrentDate() {SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");Date currentData = new Date(System.currentTimeMillis()); TODO: 2016/4/26 获取系统当前时间String strDate = format.format(currentData);// TODO: 2016/4/26 格式化系统当前时间return strDate;// TODO: 2016/4/26 返回格式化后的日期}// TODO: 2016/4/26 接收接口实现类public void setOnRefreshingListener(onRefreshingListener onRefreshingListener) {this.onRefreshingListener = onRefreshingListener;}public void completeRefresh() {ivArrow.setImageResource(R.drawable.arrow);ivArrow.setVisibility(VISIBLE);pBar.setVisibility(View.GONE);tvState.setText("下拉刷新");viewHeader.setPadding(0, -height, 0, 0);// TODO: 2016/4/26 隐藏下拉刷新布局 currentState = DONE;// TODO: 2016/4/26 用于重复刷新}
}
  • 代码很简单,就是自定义了一个view,MyListView继承ListView,重写构造方法。在构造方法中,构建下拉刷新的布局,在代码中构建的布局为viewHeader,即下拉刷新的布局;下拉刷新的xml布局如下所示:
  • xml的代码为:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout   xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="match_parent"   android:layout_height="wrap_content"   android:background="#00000000"    android:orientation="horizontal"><!-- 内容 --><RelativeLayout
          android:id="@+id/head_contentLayout"android:layout_width="match_parent"android:layout_height="wrap_content"android:paddingLeft="30dp"><!-- 箭头图像、进度条 --><FrameLayout
              android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"><!-- 箭头 --><ImageView
                  android:id="@+id/iv_arrow"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:src="@drawable/arrow" /><!-- 进度条 --><ProgressBar
                  android:id="@+id/progressBar"style="?android:attr/progressBarStyleSmall"android:layout_width="50dp"android:layout_height="50dp"android:layout_gravity="center"android:visibility="gone" /></FrameLayout><!-- 提示、最近更新 --><LinearLayout
              android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:gravity="center"android:orientation="vertical"><!-- 提示 --><TextView
                  android:id="@+id/tv_state"android:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingTop="8dp"android:text="下拉刷新"android:textColor="#FF000000"android:textSize="20sp" /><!-- 最近更新 --><TextView
                  android:id="@+id/tv_updateTime"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="上次更新"android:textColor="#FFFF0000"android:textSize="15sp" /></LinearLayout>    </RelativeLayout></LinearLayout>
  • 代码很简单,就是一个线性布局里面放置两个布局,两个布局再分别放置一些控件。其中第一个布局用的是帧布局,里面有一个下拉箭头的图片和一个进度条,此时需要将进度条隐藏,设置android:visibility=”gone”就可以了。第二个布局用的是一个线性布局,里面有两个TextView控件,一个是用于当前状态提示显示,另一个是用于最近更新提示显示。在MyListView类的构造方法中将下拉刷新布局构建好了之后,进行控件的一些初始化操作,就可以将该布局添加到头部了,this.addHeaderView(viewHeader);添加到头部的时候需要精确的测量布局的高度。高度测量完成后,设置padding,可以隐藏下拉刷新的布局,viewHeader.setPadding(0,-height, 0, 0);这里为什么要将top参数设置为-height,因为设置在头部需要将其隐藏。一些当前状态提示和时间提示的赋值我就不多说了,大家都看的懂,只要给对应的控件设置你需要让其显示的内容就可以了。下面开始关键的代码讲解:在MyListView类中重写了屏幕的触摸事件,为什么要重写该方法,因为下拉刷新这个功能是对手势做判断,执行相应操作实现的。如图方法:

  • 即重写public boolean onTouchEvent(MotionEvent ev) { ......
    return super.onTouchEvent(ev); }
    方法。

  • 在该方法中,首先获取手势动作action,手势动作有三个:手势按下,手势移动,手势抬起。

  • 当手势按下的时候,currentState赋值为PULL,获取按下时的Y坐标。currentState是用于在不同的手势之间切换的一个参数标记。此时按下就执行以上操作就可以。
  • 接下来需要下拉移动了,手势动作也相应的变成了手势移动。在手势移动的时候,判断currentState是否为PULL,为PULL的话,就获取移动时的Y坐标,根据手势按下时的Y坐标和移动时的Y坐标获取下拉显示的长度showY。获取的代码是:showY = moveY - downY + (-height);将下拉的布局慢慢显示出来就设置padding的top为当前获取的下拉显示的长度。这样你移动的时候就可以慢慢的显示出来了。这时再判断是否向下下拉了很久,如果是的话,就将下拉箭头ivArrow设置为上拉箭头,由于没有上拉箭头的图片资源,我就用ic_launcher代替了。当前状态显示提示tvState就设置为“松开刷新”,最后将currentState赋值为RELEASE。
  • 手势移动就结束了,此时手势抬起的动作就来了,手势抬起的时候分两种情况。第一种下拉一段距离但是没有刷新的情况;另一种就是释放刷新的情况。下拉一段距离但没有刷新的情况用条件”showY < heght”来判断,如果该条件成立,就说明你此时你下还在下拉,下拉没有结束,此时松开,即手势抬起的时候,下拉刷新布局就会再一次的隐藏。有人会问这里为什么用showY < 0来做判断?当布局刚好全部显示出来的时候就提示你可以刷新了不是更好吗?如果你这样提问,恭喜你,我为什么这样写你应该懂了,我只是让其下拉的距离再长一点再执行刷新操作。只要是大于0以上的数值就可以,看你个人的喜好了。
  • 而释放刷新的情况用条件currentState == RELEASE来判断,当此条件成立,即手势移动结束后(手势移动时下拉了足够长的距离),给当前状态显示提示tvState设置为“正在刷新”,进度条设置为显示,下拉箭头设置为不可见。当前刷新时间tvTime设置为系统当前时间,这个很简单,代码有注释,大家应该都能懂。接下来就是获取数据的时候了,刷新是为了干什么,是为了获取一些网络上的数据。关键的地方来了,这里你可以写个接口,让别人回调你接口的方法,在别人那里对该方法做具体的实现。给大家说具体点吧!可能有的人不是很懂。
  • 第一步:创建一个接口,如下图所示:
  • 第二步:在MyListView类写一个方法用于接收接口实现类,方法名称为:setOnRefreshingListener(onRefreshingListener onRefreshingListener)该方法用于接收一个接口参数,也就是刚刚定义的接口。如下图所示: *
  • 第三步:在释放刷新,比如联网获取数据,可以让别人调你的接口,如下图所示: *
  • 第四步:在MainActivity中用MyListView对象调用接收接口实现类方法,当调用该方法后需要执行接口中的onRefreshingListener.onRefreshing()方法,也就相当于在MainActivity中回调了第三步当中提到的方法this.RefreshingListener.onRefreshing(this)。但是具体的操作还是在MainActivity中实现。这其实也就是android中接口的回调机制,如果还不是很懂的就自己去百度“接口回调机制 ”,弄清楚它。
  • 在MainActivity中具体的实现方式如下图所示:
  • 以上图片中我标记了4处重要的地方,第一处是让线程休眠1s,模拟获取数据的操作;第二处是往集合中添加获取的数据,我这里也只用了简单的添加方式;第三处是adapter更新数据源的变化,因为往集合中添加了数据,所以执行该方法可以更新adapter中内容。但是更新UI的操作需要执行在主线程,故runOnUiThread(…);第四处是执行方法myListView.completeRefresh();用于完成数据的刷新操作。此时又回到了MyListView这个类中,在该类中去实现该方法。主要是联网完成了,隐藏下拉布局。如下图所示:
  • 代码很简单,就是一些图片的显示与进度条的隐藏,布局的设置padding等,这里就不多说了。代码里都有给出。
  • MainActivity中的代码如下所示:
package com.example.zq.pullfresh;import android.support.v7.app.AppCompatActivity; import android.os.Bundle;import java.util.ArrayList; import java.util.List; import java.util.Random;public class MainActivity extends AppCompatActivity {private List<String> lists = new ArrayList<>();// TODO: 2016/4/26 声明一个集合保存数据 private MyListView myListView;@Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// TODO: 2016/4/26 设置该Activity的使用布局setContentView(R.layout.activity_main);lists.add("a");// TODO: 2016/4/26 象征性的添加几个数据 lists.add("b");lists.add("c");// TODO: 2016/4/26 创建adapterfinal MyAdapter adapter = new MyAdapter(MainActivity.this, lists);// TODO: 2016/4/26 获取自定义的listViewmyListView = (MyListView)findViewById(R.id.myListView);// TODO: 2016/4/26 设置adaptermyListView.setAdapter(adapter);myListView.setOnRefreshingListener(new onRefreshingListener() {@Overridepublic void onRefreshing(final MyListView myListView) {new Thread(){@Overridepublic void run() {super.run();try {Thread.sleep(1000);lists.add(new Random().nextInt(100)+"联网获取的数据");// TODO: 2016/4/26 主线程执行更新UI操作必须在主线程runOnUiThread(new Runnable() {@Overridepublic void run() {adapter.notifyDataSetChanged();// TODO: 2016/4/26 联网完成了,隐藏下拉刷新布局myListView.completeRefresh();}});} catch (InterruptedException e) {e.printStackTrace();}}}.start();}}); } }
  • 代码很简单,获取MyListVIew对象,给对象设置adapter。这样就可以了。获取adapter只需要创建MyAdapter类的对象可以获取。MyAdapter类代码如下:
package com.example.zq.pullfresh;import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;import java.util.ArrayList;
import java.util.List;/*** Created by zq on 2016/4/26.*/
public class MyAdapter extends BaseAdapter {private List<String> lists = new ArrayList<>();private Context context;public MyAdapter(Context context, List<String> lists) {this.lists = lists;this.context = context;}@Overridepublic int getCount() {return lists.size();}@Overridepublic Object getItem(int position) {return lists.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {TextView tvData = new TextView(context);// TODO: 2016/4/26 新建一个TextViewtvData.setText(lists.get(position));// TODO: 2016/4/26 设置数据tvData.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);// TODO: 2016/4/26 设置textView在listView中的字体显示位置return tvData;// TODO: 2016/4/26 返回tvData}
}
  • 代码简单,继承BaseAdapter,重写相关方法,getView()方法中新建一个TextView,设置数据,返回TextView对象即可。
  • 好了,到这里就结束了。
  • 最后给大家显示一些演示的demo图片:
  • -

每天进步一点点!加油!

源码下载地址:安卓开发技术之下拉刷新的实现

Android开发技术学习之下拉刷新功能的实现相关推荐

  1. android ListView实现下拉上拉刷新功能

    android ListView实现下拉上拉刷新功能 主ListView类: package com.carcare.refresh;/*** @file XListView.java* @packa ...

  2. Android开发技术学习笔记

    目标:全面学习知识点,能理解原理,多实战练习并做笔记与总结学习心得 Android开发技术学习笔记记录如下: Android开发Google的官网https://developer.android.g ...

  3. android官方自带下拉刷新功能

    最近想写下拉刷新功能,网上找的第三方框架最著名的pullToRefresh也早在2013年停止维护了,偶然间发现谷歌公司早已推出了自家的下拉刷新功能,位于v4包中,效果请看下图: 使用的就是andro ...

  4. 【FastDev4Android框架开发】RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout(三十一)...

    转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/49992269 本文出自:[江清清的博客] (一).前言: [好消息] ...

  5. Android开发技术周报176学习记录

    Android开发技术周报176学习记录 教程 当 OkHttp 遇上 Http 2.0 http://fucknmb.com/2018/04/16/%E5%BD%93OkHttp%E9%81%87% ...

  6. IOS开发之下拉刷新和上拉加载更多

    IOS开发之下拉刷新和上拉加载更多 1.简介 常用的下拉刷新和上拉加载更多的实现方式 (1)UIRefreshControl (2)EGOTableViewRefresh (3)AH3DPullRef ...

  7. Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能 (转)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9255575 最 近项目中需要用到ListView下拉刷新的功能,一开始想图省事,在 ...

  8. Android ListView 疯狂之旅 之 《自定义下拉刷新功能的ListView》

    效果图: 一 首先创建一个类,继承ListView,编写其构造方法 public class RefreshListView extends ListView {public RefreshListV ...

  9. Android仿苹果版QQ下拉刷新实现(二) ——贝塞尔曲线开发鼻涕下拉粘连效果

    前言 接着上一期 Android仿苹果版QQ下拉刷新实现(一) --打造简单平滑的通用下拉刷新控件 的博客开始,同样,在开始前我们先来看一下目标效果: 下面上一下本章需要实现的效果图: 大家看到这个效 ...

  10. Xamarin. Android实现下拉刷新功能

    PS:发现文章被其他网站或者博客抓取后发表为原创了,给图片加了个水印 下拉刷新功能在安卓和iOS中非常常见,一般实现这样的功能都是直接使用第三方的库,网上能找到很多这样的开源库.然而在Xamarin. ...

最新文章

  1. 19.1 Linux监控平台介绍;19.2 zabbix监控介绍;19.3,19.4 安装zabbi
  2. Zabbix discoverer processes more than 75% busy
  3. mac好用大java_好用,小个头大本事!Mac下轻量级清理软件。
  4. Python之pandas:对pandas中dataframe数据中的索引输出、修改、重命名等详细攻略
  5. mysql pt_mysql之pt工具之pt-fifo-split用法介绍
  6. 【百家稷学】卷积神经网络的前世、今生与未来(武汉工程大学技术分享)
  7. HTML的<span>标签【杂记】
  8. neon浮点运算_Linux下VFP NEON浮点编译
  9. 用AI写出的第一本书面世:先进算法能对机器生成的内容负责吗?
  10. aix下oracle 12.1.0.2 asmca不能打开的故障
  11. 内置对象session与httpSession对象是同一个东西么?
  12. 在Linux下安装rarlinux
  13. Flink Web UI不能访问
  14. matlab中门函数怎么化,Matlab中函数tf2zp的解析
  15. wsbm服务器错误怎么修复,如何使用ab测试上传文件
  16. macOS 下菜单栏图标管理操作教程
  17. STC12C5A60S2系列单片机PCA时钟源设置
  18. JavaScript学习攻略
  19. 关于comsol“LU因式分解时内存不足“的一些解决建议
  20. 讲台计算机的英语怎么读,讲台英语怎么读

热门文章

  1. 英文词性标注PTB标准
  2. ALS模拟环境光传感芯片的工作原理
  3. word电子签名在线制作
  4. (rear + maxSize - front) % maxSize 公式的理解(文图详解,手把手)
  5. 西瓜书读书笔记(一)-绪论
  6. 自己整理的资料 视频格式以及参数含义
  7. 7.6批量下载网易云歌曲
  8. 爬虫之模拟强智系统登录
  9. 下面程序的功能是调用fun函数以删除字符串中指定的字符
  10. 蔬菜大棚成本_在农村,建一个温室大棚要多少钱?看完一目了然!