Android开发技术学习之下拉刷新功能的实现
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开发技术学习之下拉刷新功能的实现相关推荐
- android ListView实现下拉上拉刷新功能
android ListView实现下拉上拉刷新功能 主ListView类: package com.carcare.refresh;/*** @file XListView.java* @packa ...
- Android开发技术学习笔记
目标:全面学习知识点,能理解原理,多实战练习并做笔记与总结学习心得 Android开发技术学习笔记记录如下: Android开发Google的官网https://developer.android.g ...
- android官方自带下拉刷新功能
最近想写下拉刷新功能,网上找的第三方框架最著名的pullToRefresh也早在2013年停止维护了,偶然间发现谷歌公司早已推出了自家的下拉刷新功能,位于v4包中,效果请看下图: 使用的就是andro ...
- 【FastDev4Android框架开发】RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout(三十一)...
转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/49992269 本文出自:[江清清的博客] (一).前言: [好消息] ...
- Android开发技术周报176学习记录
Android开发技术周报176学习记录 教程 当 OkHttp 遇上 Http 2.0 http://fucknmb.com/2018/04/16/%E5%BD%93OkHttp%E9%81%87% ...
- IOS开发之下拉刷新和上拉加载更多
IOS开发之下拉刷新和上拉加载更多 1.简介 常用的下拉刷新和上拉加载更多的实现方式 (1)UIRefreshControl (2)EGOTableViewRefresh (3)AH3DPullRef ...
- Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能 (转)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9255575 最 近项目中需要用到ListView下拉刷新的功能,一开始想图省事,在 ...
- Android ListView 疯狂之旅 之 《自定义下拉刷新功能的ListView》
效果图: 一 首先创建一个类,继承ListView,编写其构造方法 public class RefreshListView extends ListView {public RefreshListV ...
- Android仿苹果版QQ下拉刷新实现(二) ——贝塞尔曲线开发鼻涕下拉粘连效果
前言 接着上一期 Android仿苹果版QQ下拉刷新实现(一) --打造简单平滑的通用下拉刷新控件 的博客开始,同样,在开始前我们先来看一下目标效果: 下面上一下本章需要实现的效果图: 大家看到这个效 ...
- Xamarin. Android实现下拉刷新功能
PS:发现文章被其他网站或者博客抓取后发表为原创了,给图片加了个水印 下拉刷新功能在安卓和iOS中非常常见,一般实现这样的功能都是直接使用第三方的库,网上能找到很多这样的开源库.然而在Xamarin. ...
最新文章
- 19.1 Linux监控平台介绍;19.2 zabbix监控介绍;19.3,19.4 安装zabbi
- Zabbix discoverer processes more than 75% busy
- mac好用大java_好用,小个头大本事!Mac下轻量级清理软件。
- Python之pandas:对pandas中dataframe数据中的索引输出、修改、重命名等详细攻略
- mysql pt_mysql之pt工具之pt-fifo-split用法介绍
- 【百家稷学】卷积神经网络的前世、今生与未来(武汉工程大学技术分享)
- HTML的<span>标签【杂记】
- neon浮点运算_Linux下VFP NEON浮点编译
- 用AI写出的第一本书面世:先进算法能对机器生成的内容负责吗?
- aix下oracle 12.1.0.2 asmca不能打开的故障
- 内置对象session与httpSession对象是同一个东西么?
- 在Linux下安装rarlinux
- Flink Web UI不能访问
- matlab中门函数怎么化,Matlab中函数tf2zp的解析
- wsbm服务器错误怎么修复,如何使用ab测试上传文件
- macOS 下菜单栏图标管理操作教程
- STC12C5A60S2系列单片机PCA时钟源设置
- JavaScript学习攻略
- 关于comsol“LU因式分解时内存不足“的一些解决建议
- 讲台计算机的英语怎么读,讲台英语怎么读