ListView实现下拉刷新(三)实现下拉刷新
该准备的东西都已经准备好了。在这篇文章里,我们就开始实现下拉刷新功能吧。
一、大体的逻辑分析
我们来简单分析一下需要做的逻辑吧。首先分析头布局有几种状态。不下拉时,为正常状态,此时头布局隐藏。下拉到一定高度,提示信息变为“下拉刷新”,箭头朝下,此为下拉状态。再往下拉,提示信息变为“松开刷新”,箭头朝上,此为提示刷新状态。而此时松开手指,则执行刷新操作,头布局变为进度条显示,箭头消失,此为正在刷新状态。相反的,其他状态下松开手指,都不执行刷新操作,应该将头布局恢复到正常状态。因为可确定头布局的状态有四种。
我们根据这四种状态,确定我们要做的事情。要监听ListView的滚动,故要实现OnScrollListener接口。还要监听手指触摸事件,根据手指的下拉移动来改变头布局的显示效果,根据手指的抬起来判断是否进行刷新操作,因为要实现onTouchEvent方法。也就是说,头布局状态的改变应该随着手指的移动而改变,因此在onTouchEvent里面我们要实现上面分析的四种状态的改变。当然,状态改变就意味着头布局显示效果的改变,这里可以嵌套在onTouchEvent方法里面。但考虑到避免方法臃肿,以及其他地方可能也需要改变头布局界面,比如数据加载完成后等情况,因此专门将头布局界面的改变抽取出来,凝聚为一个方法。
然后就是数据刷新,刷新操作要在MyListView里执行,但是数据要在MainActivity中获取。老规矩,用接口回调即可。
好了,基本上大体的逻辑就这么多了。下面我们将上面的分析转化为代码。
二、代码编写
废话我就不多说了,上面的分析很清楚了。继续完善MyListView即可。代码如下:
package com.fuly.load; import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView; public class MyListView extends ListView implements OnScrollListener{ private View header;//头布局 private int headerHeight;//头布局自身的高度 private int scrollState;//当前滚动状态
private int firstVisibleItem;//当前可见的第一个item
private int startY;//刚开始触摸屏幕时的Y值 private int curState = 0;//当前header状态,默认为0
private final int NORMAL = 0;//正常状态
private final int PULL = 1;//状态下拉
private final int RELEASE = 2;//提示刷新状态
private final int RELEASING = 3;//状态正在刷新 private boolean canPull = false;//是否可以执行下拉操作 private refresfListener mListener;//回调接口 //三个构造方法都要重写
public MyListView(Context context) {
super(context);
initView( context); }
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView( context); }
public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView( context); } //定义回调接口
public interface refresfListener{
void refresh();
}
public void setOnRefreshListener(refresfListener listener){
this.mListener = listener;
} public void initView(Context context){ header = LayoutInflater.from(context).inflate(R.layout.header, null);
notifyView(header);
headerHeight = header.getMeasuredHeight();//获取header的高度 // headerHeight = header.getHeight();
paddingTop(-headerHeight);
//将头布局加进去
this.addHeaderView(header); this.setOnScrollListener(this);
} /**
* 该方法为通知父布局,子布局view的宽度和高度
* @param view:子布局
*/
private void notifyView(View view){ ViewGroup.LayoutParams p = view.getLayoutParams(); if(p == null){
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } //spec表示当前子view左右边距,padding表示子view的左右内边距
//childDimension:子view的宽度
int width = ViewGroup.getChildMeasureSpec(0, 0, p.width); int height;
int tempHeight = p.height;
if(tempHeight>0){
//子布局高度不为空,需要填充这个布局
height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
}else{
//高度为0,则不需要填充
height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
} //然后告诉父布局,子布局的高度和宽度
view.measure(width, height);
} //该方法设定header的paddingTop
private void paddingTop(int pt){
header.setPadding(header.getPaddingLeft(), pt, header.getPaddingRight(), header.getPaddingBottom());
header.invalidate();
} /***
* 监听当前滚动状态
* scrollState:当前滚动状态
*/
public void onScrollStateChanged(AbsListView view, int scrollState) {
//记录当前的滚动状态
this.scrollState = scrollState; } /***
* 监听当前滚动的item
* firstVisibleItem:当前可见的第一个item
* visibleItemCount:当前共有多少个item可见
* totalItemCount:总共有多少个item
*
*/
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) { this.firstVisibleItem = firstVisibleItem; } //触屏事件
public boolean onTouchEvent(MotionEvent ev) { switch(ev.getAction()){
//手指落到屏幕上时
case MotionEvent.ACTION_DOWN:
//如果当前可见的第一个item为第0号,说明ListView位于顶端,可以执行下拉刷新
if(firstVisibleItem == 0){
canPull = true;
startY = (int) ev.getY();
} break;
//手指在屏幕上拖动时
case MotionEvent.ACTION_MOVE:
if(canPull){
touchMove(ev);
}
break;
//手指离开屏幕时
case MotionEvent.ACTION_UP:
canPull = false;
if(curState == RELEASE){
curState = RELEASING;
refreshHeaderByState();
//这里添加刷新数据的逻辑
mListener.refresh();
}else{
curState = NORMAL;
refreshHeaderByState();
paddingTop(-headerHeight);
} break;
} return super.onTouchEvent(ev);
} /**
* 该方法根据触摸屏幕滑动来改变STATE,即改变当前状态
* @param ev
*/
private void touchMove(MotionEvent ev) { int tempY = (int) ev.getY();
int space = tempY -startY;//移动的距离
int topdding = space-headerHeight;
paddingTop(topdding);//即时设定头布局的隐藏高度
if(space>headerHeight&&space<headerHeight+50&&scrollState == SCROLL_STATE_TOUCH_SCROLL){
curState = PULL;//设定为下拉状态
refreshHeaderByState();
}
if(space>headerHeight+50){
curState = RELEASE;//设定为提示刷新状态
refreshHeaderByState();
} if(space<headerHeight){
curState = NORMAL;//设定为正常状态
refreshHeaderByState();
} } /**
* 根据当前状态更改header的显示界面
*
*/
private void refreshHeaderByState( ){
ProgressBar pb = (ProgressBar) header.findViewById(R.id.progress_bar);
ImageView img = (ImageView) header.findViewById(R.id.img_arrow);
TextView tv = (TextView) header.findViewById(R.id.textinfo); switch(curState){ case NORMAL:
pb.setVisibility(View.GONE);
img.setVisibility(View.VISIBLE);
img.setImageResource(R.drawable.down_arrow);
tv.setText("下拉刷新");
break;
case PULL:
pb.setVisibility(View.GONE);
img.setVisibility(View.VISIBLE);
img.setImageResource(R.drawable.down_arrow);
tv.setText("下拉刷新");
break;
case RELEASE:
pb.setVisibility(View.GONE);
img.setVisibility(View.VISIBLE);
img.setImageResource(R.drawable.up_arrow);
tv.setText("松开刷新");
break;
case RELEASING:
pb.setVisibility(View.VISIBLE);
img.setVisibility(View.GONE);
tv.setText("正在刷新");
break; } } //数据刷新完成后的操作
public void refreshFinish(){ curState = NORMAL;
paddingTop(-headerHeight);
refreshHeaderByState();
} }
接下来就是MainActivity中的代码了。如下:
package com.fuly.load; import java.util.ArrayList;
import java.util.List; import com.fuly.load.MyListView.refresfListener; import android.os.Bundle;
import android.os.Handler;
import android.app.Activity; public class MainActivity extends Activity implements refresfListener{ private MyListView lv;
private List<MyData> mDatas = new ArrayList<MyData>();
private MyAdapter mAdapter; protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); initData();//该方法初始化数据
lv = (MyListView) findViewById(R.id.list_view);
lv.setOnRefreshListener(this);//设定回调接口
mAdapter = new MyAdapter(this, mDatas);
lv.setAdapter(mAdapter); } /**
* 该方法初始化数据,即提供初始的素材
*/
private void initData() {
for(int i = 0;i<12;i++){
MyData md = new MyData("你好,我是提前设定的");
mDatas.add(md);
} }
/**
* 提供刷新数据
*/
private void getRefreshData() {
for(int i = 0;i<3;i++){
MyData md = new MyData("你好,我是刷新进来的");
mDatas.add(i, md);
} } //重写回调方法
public void refresh() { //在这里之所以使用Handler,是想让操作延迟,这样子效果看起来更
//清晰,实际项目中,是 不需要的
Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable(){ @Override
public void run() {
//获得刷新数据
getRefreshData();
//刷新ListView
mAdapter.notifyDataSetChanged();
//lv.setSelection(mDatas.size()-1); //刷新后
lv.refreshFinish(); } }, 5000 ); }
}
好了,快快运行下程序,体验下拉刷新的效果吧。至此,ListView实现下拉刷新,我们讲解完毕了。
ListView实现下拉刷新(三)实现下拉刷新的更多相关文章
- Android 自定义ListView实现底部分页刷新与顶部下拉刷新,androidlistview
在项目开发中,由于数据过大时,需要进行分页加载或下拉刷新,来缓解一次性加载的过长等待.本篇博文实例讲解通过自定义的ListView实现底部分页加载和顶部下拉刷新的效果. 其效果图: 一.ListVie ...
- 你必须了解的RecyclerView的五大开源项目-解决上拉加载、下拉刷新和添加Header、Footer等问题
前段时间做项目由于采用的MD设计,所以必须要使用RecyclerView全面代替ListView.但是开发中遇到了需要实现RecyclerView上拉加载.下拉刷新和添加Header以及Footer等 ...
- 定位和xml解析和gson解析加上拉加载,下拉刷新
这里的上拉加载,下拉刷新用到是依赖包 Mainactivity,xml解析和定位 package com.exmple.autolayout; import java.util.List; impor ...
- PullToRefreshScrollView的上拉加载、下拉刷新
eclipse中的项目: //注意:此刷新功能是使用的第三方的PullToRefreshScrollView,因此需要导入第三方library作为依赖 步骤:导入第三方library,依赖:点击你的应 ...
- PullToRefreshListView上拉加载、下拉刷新
说明:此项目使用studio完成的.需要导入library作为依赖,使用了xuitls获得网络请求.使用Pull解析了XML eclipse中的项目: //注意:此刷新功能是使用的第三方的PullTo ...
- Vue-上拉加载与下拉刷新(mint-ui:loadmore)一个页面使用多个上拉加载后冲突问题
所遇问题: 该页面为双选项卡联动,四个部分都需要上拉加载和下拉刷新功能,使用的mint-ui的loadmore插件,分别加上上拉加载后,只有最后一个的this.$refs.loadmore.onTop ...
- C#构造方法(函数) C#方法重载 C#字段和属性 MUI实现上拉加载和下拉刷新 SVN常用功能介绍(二) SVN常用功能介绍(一) ASP.NET常用内置对象之——Server sql server——子查询 C#接口 字符串的本质 AJAX原生JavaScript写法
C#构造方法(函数) 一.概括 1.通常创建一个对象的方法如图: 通过 Student tom = new Student(); 创建tom对象,这种创建实例的形式被称为构造方法. 简述:用来初 ...
- vue使用vant-ui实现上拉加载、下拉刷新和返回顶部
vue使用vant-ui实现上拉加载.下拉刷新和返回顶部 vue现在在移动端常用的ui库有vant-ui和mint-ui,上拉加载.下拉刷新和返回顶部也是移动端最基础最常见的功能.下面就用vant-u ...
- 使用jquery结合ajax做下拉刷新页面,上拉加载页面,俗称分页
jquery结合iscroll.js做下拉刷新页面,上拉加载页面 先上代码,里面都有注释这就不一一说明了 <!DOCTYPE html> <html lang="en&qu ...
- android 支持上拉加载,下拉刷新的列表控件SwipeRefreshLayout的二次封装
上拉加载,下拉刷新的列表控件,大家一定都封装过,或者使用过 源代码,我会在最后贴出来 这篇代码主要是为了解决两个问题 1.滑动冲突得问题 2.listview无数据时,无数据布局的展示问题 下方列出的 ...
随机推荐
- PostgreSQL On Windows Process Connection Performance
本文主要对PostgreSql在Windows下的连接测试. 测试环境: Win7 x64, PostgreSql 10.1 x64 测试语言: VS2015 C# 因为Pg的数据库连接是开启进程来处 ...
- react-native学习之入门app
1.项目初始化: react-native init MyProject 2.启动项目: cd MyProject react-native start 新开cmd窗口: react-native r ...
- 三个缓存数据库Redis、Memcache、MongoDB
>>Memcached Memcached的优点:Memcached可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key.value的字节大小以及服务器硬件性能,日常环境 ...
- SPDY和HTTP
SPDY 是什么 ? SPDY 是 Google 开发的基于传输控制协议 (TCP) 的应用层协议.SPDY 协议旨在通过压缩.多路复用和优先级来缩短网页的加载时间和提高安全性.(SPDY 是 Spe ...
- HDU 4283 (第k个出场 区间DP)
http://blog.csdn.net/acm_cxlove/article/details/7964594 http://www.tuicool.com/articles/jyaQ7n http: ...
- Jvm运行时内存解析
一.jvm的概念 在了解jvm的概念之前,我们先来了解java平台的逻辑结构,图片来自<深入java虚拟机> 从图中我们可以看到jdk包含了jre,java语言和java开发工具和Api, ...
- svg基础知识体系建立
一.简介:SVG 是使用 XML 来描述二维图形和绘图程序的语言. SVG 指可伸缩矢量图形 (Scalable Vector Graphics) SVG 用来定义用于网络的基于矢量的图形 SVG 使 ...
- centos yum安装常用命令
安装killall命令 yum install -y psmisc 安装sz(下载)和rz(上传)命令 yum install -y lrzsz 安装 ifconfig 命令 yum install ...
- 【Machine Learning】分类与回归 区别
一.分类与回归的区别 两类监督学习 Classification Regression 分类和回归的区别在于输出变量的类型(而非输入变量). 定性输出称为分类,或者说是离散变量预测(discrete) ...
- [poj 2479] Maximum sum -- 转载
转自 CSND 想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410 ...