【1】重写listViewimport java.text.SimpleDateFormat;

import java.util.Date;

import com.example.testdddleapk.R;

import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.Animation;

import android.view.animation.LinearInterpolator;

import android.view.animation.RotateAnimation;

import android.widget.AbsListView;

import android.widget.AbsListView.OnScrollListener;

import android.widget.BaseAdapter;

import android.widget.ImageView;

import android.widget.ListAdapter;

import android.widget.ListView;

import android.widget.ProgressBar;

import android.widget.TextView;

public class RefreshListView extends ListView implements OnScrollListener {

private static final int DONE = 0;

private static final int PULL_TO_REFRESH = 1;

private static final int RELEASE_TO_REFRESH = 2;

private static final int REFRESHING = 3;

private static final float RATIO = 3;// 用来设置实际间距和上边距之间的比例

private int state;// 当前下拉刷新的状态

private int firstVisibleIndex;// 在listview中第一个可以看见的item

private View headView;

private ImageView headArrow;

private ProgressBar progressBar;

private TextView headTitle;

private TextView headLastUpdate;

private int headContentWidth;

private int headContentHeight;

private Animation animation;

private Animation reverseAnimation;

private OnRefreshListner refreshListner;// 刷新监听器

private boolean isRefreshable;

private boolean isRecored = false;// 用来记录第一次按下坐标点,在整个滑动的过程中 只记录一次

private float startY;

private boolean isBack = false;// 是从 松开刷新状态 来到的 下拉刷新状态

public RefreshListView(Context context, AttributeSet attrs) {

super(context, attrs);

init(context);

}

private void init(Context context) {

// listview 设置滑动时缓冲背景色

setCacheColorHint(0xcc000000);

headView = View.inflate(context, R.layout.listview_header, null);

headArrow = (ImageView) headView.findViewById(R.id.iv_listview_header_arrow);

progressBar = (ProgressBar) headView.findViewById(R.id.pb_listview_header);

headTitle = (TextView) headView.findViewById(R.id.tv_listview_header_last_update_time);

headLastUpdate = (TextView) headView .findViewById(R.id.tv_listview_header_state);

headArrow.setMinimumWidth(50);

headArrow.setMinimumHeight(70);

MeasureView(headView);

headContentWidth = headView.getMeasuredWidth();

headContentHeight = headView.getMeasuredHeight();

headView.setPadding(0, -1*headContentHeight, 0, 0);

// 为listView加入顶部View

addHeaderView(headView);

setOnScrollListener(this);

animation = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF, 0.5f);

animation.setDuration(250);

animation.setFillAfter(true);// 设定动画结束时,停留在动画结束位置 (保留动画效果)

animation.setInterpolator(new LinearInterpolator());// 匀速变化

reverseAnimation = new RotateAnimation(0, -180,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);

reverseAnimation.setDuration(200);

reverseAnimation.setFillAfter(true);// 设定动画结束时,停留在动画结束位置 (保留动画效果)

reverseAnimation.setInterpolator(new LinearInterpolator());// 匀速变化

// 设置当前headView的状态

state = DONE;

// 设置当前下拉刷新是否可用

isRefreshable = false;

}

/**

* 测量headView的 宽高

*/

private void MeasureView(View child) {

ViewGroup.LayoutParams lp = child.getLayoutParams();

if (null == lp) {

lp = new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);

}

int measureChildWidth = ViewGroup.getChildMeasureSpec(0, 0, lp.width);

int measureChildHeight;

if (lp.height > 0) {

measureChildHeight = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);

} else {

measureChildHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

}

child.measure(measureChildWidth, measureChildHeight);

}

private float tempY=0;

private float downY=0;

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

downY=event.getY();

System.out.println("downY:"+downY);

if (firstVisibleIndex == 0 && !isRecored) {

startY = event.getY();

isRecored = true;

}

break;

case MotionEvent.ACTION_MOVE:

//float tempY = event.getY();

tempY = event.getY();

System.out.println("tempy:"+tempY);

if (firstVisibleIndex == 0 && !isRecored) {

startY = tempY;

isRecored = true;

}

if (state != REFRESHING) {

if (state == PULL_TO_REFRESH) {

// 向下拉了 从下拉刷新的状态 来到 松开刷新的状态

if ((tempY - startY) / RATIO >= headContentHeight

&& (tempY - startY) > 0) {

state = RELEASE_TO_REFRESH;

changeHeadViewOfState();

}

// 向上推了 从下拉刷新的状态 来到 刷新完成的状态

else if ((tempY - startY) <= 0) {

state = DONE;

changeHeadViewOfState();

}

} else if (state == RELEASE_TO_REFRESH) {

// 向上推了 还没有完全将HEADVIEW 隐藏掉(可以看到一部分)

// 从松开刷新的状态 来到 下拉刷新的状态

if ((tempY - startY) / RATIO

&& (tempY - startY) > 0) {

state = PULL_TO_REFRESH;

changeHeadViewOfState();

isBack = true;

}

// 向上推了 一下子推到了最上面 从松开刷新的状态 来到 刷新完成的状态 (数据不刷新的)

else if ((tempY - startY) <= 0) {

state = DONE;

changeHeadViewOfState();

}

} else if (state == DONE) {

// 刷新完成的状态 来到 下拉刷新的状态

if ((tempY - startY) > 0) {

state = PULL_TO_REFRESH;

changeHeadViewOfState();

}

}

if (state == PULL_TO_REFRESH) {

headView.setPadding(0,(int) ((tempY - startY) / RATIO - headContentHeight),0, 0);

}

if (state == RELEASE_TO_REFRESH) {

headView.setPadding(0, (int) ((tempY - startY) / RATIO - headContentHeight),0, 0);

}

}

break;

case MotionEvent.ACTION_UP:

if (state != REFRESHING) {

if (state == PULL_TO_REFRESH) {

// 松手

state = DONE;

changeHeadViewOfState();

}

else if (state == RELEASE_TO_REFRESH) {

// 松手

state = REFRESHING;

changeHeadViewOfState();

// 执行数据刷新方法

onRefresh();

}

}

isRecored = false;

isBack = false;

break;

}

return super.onTouchEvent(event);

}

/**

* 执行下拉刷新

*/

private void onRefresh() {

if (refreshListner != null) {

refreshListner.onRefresh();

}

}

/**

* HeadView的状态变化效果

*/

private void changeHeadViewOfState() {

switch (state) {

case PULL_TO_REFRESH:

headArrow.setVisibility(View.VISIBLE);

progressBar.setVisibility(View.GONE);

headTitle.setVisibility(View.VISIBLE);

headLastUpdate.setVisibility(View.VISIBLE);

headArrow.clearAnimation();

headTitle.setText("下拉可以刷新");

//由 松开刷新  到  下拉刷新

if(isBack){

headArrow.startAnimation(animation);

isBack = false;

}

break;

case RELEASE_TO_REFRESH:

headArrow.setVisibility(View.VISIBLE);

progressBar.setVisibility(View.GONE);

headTitle.setVisibility(View.VISIBLE);

headLastUpdate.setVisibility(View.VISIBLE);

headArrow.clearAnimation();

headArrow.startAnimation(reverseAnimation);

headTitle.setText("松开可以刷新");

break;

case REFRESHING:

headArrow.setVisibility(View.GONE);

progressBar.setVisibility(View.VISIBLE);

headTitle.setVisibility(View.VISIBLE);

headLastUpdate.setVisibility(View.VISIBLE);

headArrow.clearAnimation();

headTitle.setText("正在刷新...");

headView.setPadding(0, 0, 0, 0);

break;

case DONE:

headArrow.setVisibility(View.VISIBLE);

progressBar.setVisibility(View.GONE);

headTitle.setVisibility(View.VISIBLE);

headLastUpdate.setVisibility(View.VISIBLE);

headArrow.clearAnimation();

headTitle.setText("下拉可以刷新");

headView.setPadding(0, -1 * headContentHeight, 0, 0);

break;

}

}

private int lastPos;//最后一个可见的item的位置

private int count;//item总数,注意不是当前可见的item总数

private boolean hasFoot = false;//是否有了Foot

public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {

firstVisibleIndex = firstVisibleItem;

lastPos = getLastVisiblePosition();

count = totalItemCount;

//因为刚进入的时候,lastPos=-1,count=0,这个时候不能让它执行onAddFoot方法

if(lastPos==count-1 && !hasFoot && lastPos != -1&&((tempY-startY)<0)){

hasFoot = true;

onAddFoot();

}

}

public void onScrollStateChanged(AbsListView view, int scrollState) {

if(isFootLoading) return;

if(lastPos==count-1 && lastPos != -1&&hasFoot&&footer!=null&&((tempY-downY)>0)){

this.removeFooterView(footer);

}

if(hasFoot && scrollState==SCROLL_STATE_IDLE&&((tempY-downY)<0)){

isFootLoading = true;

onFootLoading();

}

}

/**

* 设置下拉刷新监听

*/

public void setOnRefreshListner(OnRefreshListner listener) {

// 设置下拉刷新可用

isRefreshable = true;

refreshListner = listener;

}

//执行底部加载

public void onFootLoading(){

if(footLoadingListener!=null && isFootLoading &&hasFoot&&(tempY-downY)<0)  {

footLoadingListener.onFootLoading();  }

}

public void setOnAddFootListener(OnAddFootListener addFootListener){

onAddFootListener = addFootListener;

}

//执行添加foot

public void onAddFoot(){

if(onAddFootListener!=null && hasFoot)

onAddFootListener.addFoot();

}

//是否添加Foot的监听器,如果写在OnFootLoadingListener中会有延迟,效果不好

//应该是先进入添加Foot的状态,再进入FootLoading的状态

public OnAddFootListener onAddFootListener;

//是否进入从底部加载数据的状态的监听器

public OnFootLoadingListener footLoadingListener;

//正在加载底部数据

private boolean isFootLoading = false;

public void setOnFootLoadingListener(OnFootLoadingListener footLoading){

footLoadingListener = footLoading;

}

/**

* 下拉刷新监听器

*/

public interface OnRefreshListner {

// 下拉刷新的时候,在这里执行获取数据的过程

void onRefresh();

}

private View footer=null;

public void setFooter(View footer){

this.footer=footer;

}

/**

* 上拉刷新监听器

*/

public interface OnFootLoadingListener{

// 这里是执行后台获取数据的过程

void onFootLoading();

}

/**

* 添加Foot的监听器

*/

public interface OnAddFootListener{

// 这里是用户addFootView的操作

void addFoot();

}

/**

* 底部数据加载完成,用户需要加入一个removeFootView的操作

*/

public void onFootLoadingComplete(){

hasFoot = false;

isFootLoading = false;

}

/**

* 上拉刷新完成时 所执行的操作,更改状态,隐藏head

*/

public void onRefreshComplete() {

state = DONE;

changeHeadViewOfState();

headLastUpdate.setText("最后刷新时间: " + new Date().toLocaleString());

}

@Override

public void setAdapter(ListAdapter adapter) {

headLastUpdate.setText("最后刷新时间: " + new Date().toLocaleString());

super.setAdapter(adapter);

}

}

【2】下拉刷新头部布局文件listview_header.xml<?xml  version="1.0" encoding="utf-8"?>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="10dip" >

android:id="@+id/iv_listview_header_arrow"

android:layout_width="40dp"

android:layout_height="40dp"

android:layout_gravity="center"

android:minWidth="30dip"

android:src="@drawable/arrow" />

android:id="@+id/pb_listview_header"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:indeterminateDrawable="@drawable/common_progressbar"

android:visibility="gone" />

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_gravity="center_vertical"

android:gravity="center_horizontal"

android:orientation="vertical" >

android:id="@+id/tv_listview_header_state"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="下拉刷新"

android:textColor="#FF0000"

android:textSize="18sp" />

android:id="@+id/tv_listview_header_last_update_time"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="5dip"

android:text="最后刷新时间: 2014-10-10 12:56:12"

android:textColor="@android:color/white"

android:textSize="14sp" />

【3】上拉加载更多布局文件listview_footer.xml<?xml  version="1.0" encoding="utf-8"?>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:layout_margin="10dip"

android:gravity="center_vertical"

android:orientation="horizontal" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:indeterminateDrawable="@drawable/common_progressbar" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="10dip"

android:text="加载更多..."

android:textColor="#FF0000"

android:textSize="18sp" />

【4】progressBar--common_progressbar.xml<?xml  version="1.0" encoding="utf-8"?>

android:fromDegrees="0"

android:pivotX="50%"

android:pivotY="50%"

android:toDegrees="360" >

android:innerRadiusRatio="3"

android:shape="ring"

android:useLevel="false" >

android:centerColor="#FF6666"

android:endColor="#FF0000"

android:startColor="#FFFFFF"

android:type="sweep" />

【5】使用方法adapter=new myListAdapter(items,xxx.this);

listView.setAdapter(adapter);

/**

* 下拉刷新回调

*/

listView.setOnRefreshListner(new OnRefreshListner() {

public void onRefresh() {

new AsyncTask>(){

@Override

protected ArrayList doInBackground(Void... params) {

try {

//模拟从服务器获取数据的过程

Thread.sleep(1500);

} catch (InterruptedException e) {

e.printStackTrace();

}

return null;

}

//更新UI的方法,系统自动实现

@Override

protected void onPostExecute(ArrayList result) {

data.addAll(0,result);//注意是往前添加数据

adapter.notifyDataSetChanged();

listView.onRefreshComplete();//完成下拉刷新,这个方法要调用

super.onPostExecute(result);

}

}.execute();

}

});

//上拉加载更多功能

final View footer = View.inflate(getActivity(), R.layout.listview_footer, null);

listView.setOnAddFootListener(new OnAddFootListener() {

public void addFoot() {

listView.setFooter(footer);

listView.addFooterView(footer);

}

});

listView.setOnFootLoadingListener(new OnFootLoadingListener() {

public void onFootLoading() {

new AsyncTask>(){

@Override

protected ArrayList doInBackground(Void... params) {

try {

//模拟从服务器获取数据的过程

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

return null;

}

//在doInBackground后面执行

protected void onPostExecute(ArrayList result) {

data.addAll(result);//这个是往后添加数据

adapter.notifyDataSetChanged();

listView.onFootLoadingComplete();//完成上拉刷新,就是底部加载完毕,这个方法要调用

//移除footer,这个动作不能少

listView.removeFooterView(footer);

super.onPostExecute(result);

}

}.execute();

}

});

【6】注意事项

listview设置项目点击事件

listView.setOnItemClickListener(new OnItemClickListener() {

public void onItemClick(AdapterView> parent, View view,int position, long id) {

if(position==0||position==items.length()+1) return;

//获取每项的数据,position需减1,第0项为listview_head

}

android listview下拉刷新动画,android 安卓 listview 支持下拉刷新 上拉加载更多相关推荐

  1. jquery手机端页面下拉刷新,上划加载更多

    手机页面下拉刷新,上划加载更多,IOS不能下拉的问题解决 -转圈的是需要引用样式,代码删除了 上划加载时的样子 <script type="text/javascript"& ...

  2. 使用Vant框架的组件van-pull-refresh搭配van-list和van-card完成上滑加载更多列表数据,下拉刷新当前列表数据(等同于翻页功能)

    <template><div class="sg-page-body"><div class="sg-list"><v ...

  3. 微信小程序实战篇-下拉刷新与加载更多

    下拉刷新 实现下拉刷新目前能想到的有两种方式 调用系统的API,系统有提供下拉刷新的API接口 下拉刷新API.png 监听scroll-view,自定义下拉刷新,还记得scroll-view里面有一 ...

  4. H5——移动端JQ实现下拉刷新、上拉加载更多

    前言 这里用的JQ库里免费插件__dropload,效果图在文末 引入 去上面链接里面下载内容,可以本地引入 <link rel="stylesheet" href=&quo ...

  5. Android之Socket通信、List加载更多、Spinner下拉列表

    Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是"请求-响应方式",即在请求时建立连接通道,当客户端向服 ...

  6. Android项目:使用pulltorefresh开源项目扩展为下拉刷新上拉加载更多的处理方法,监听listview滚动方向...

    很多android应用的下拉刷新都是使用的pulltorefresh这个开源项目,但是它的扩展性在下拉刷新同时又上拉加载更多时会有一定的局限性.查了很多地方,发现这个开源项目并不能很好的同时支持下拉刷 ...

  7. android自带下拉阻尼动画,android 有阻尼下拉刷新列表的实现方法

    本文将会介绍有阻尼下拉刷新列表的实现,先来看看效果预览: 这是下拉状态: 这是下拉松开手指后listView回滚到刷新状态时的样子: 1. 如何调用 虽然效果图看起来样子不太好看,主要是因为那个蓝色的 ...

  8. android 加载更多动画效果,Android实践之带加载效果的下拉刷新上拉加载更多

    前言 之前写的一个LoadingBar,这次把LoadingBar加到下拉刷新的头部.从头写一个下拉刷新,附赠上拉加载更多.下面话不多说了,来一起看看详细的介绍吧. 效果图: 实现过程 首先是自定义属 ...

  9. Android ListView下拉与上拉刷新加载更多数据 二

    效果图:                 java代码中: public class MainActivity extends Activity implements OnRefreshListene ...

最新文章

  1. jdbc封装与多并发的共鸣
  2. MySQL数据库右连接查询right join ... on
  3. LayIM.AspNetCore Middleware 开发日记(一)闲言碎语
  4. 设计立方体类(求出立方体的面积和体积 分别用全局函数和成员函数判断两个立方体是否相等)
  5. 信息系统项目管理知识--项目整合管理
  6. 龙书啃不动?老司机带你从零入门编译原理,开发编译器
  7. python如何生成随机数_python如何生成随机数
  8. 父母该不该把自己的收入告诉孩子?
  9. AcWing1087.修剪草坪(单调队列DP)
  10. Activity常用设置
  11. 软件是怎么控制硬件的?
  12. 基于php046学校固定资产管理系统
  13. oracle数据库例题答案下载,Oracle数据库试题及答案[教学知识]
  14. 联想笔记本怎么开启无线网络?
  15. 数学分析(9): 不定积分
  16. C语言实现字符串转数字(包括负数)
  17. TeraTerm下载方法
  18. PR如何调整输出视频的分辨率?
  19. LibPcap丢包怎么办
  20. vue+elementui上传视频并回显

热门文章

  1. 【干货】数据挖掘比赛大数据处理和建模经验
  2. 如何快速搭建自己的独立站?
  3. 遍历界面控件 android,Android 判断所有字段是否已经输入的实例
  4. 怎么把文件导入云服务器,怎么把文件放到云服务器里
  5. linux脚本调用job,linux shell - 脚本中调用fg调取后台任务报错
  6. java工厂模式定义宠物_Java设计模式之抽象工厂模式
  7. 新版本NexT 调动态背景、调canvas_nest的解决方案
  8. Leetcode每日一题:29.divide-two-integers(两数相除)
  9. TensorFlow2.0:tensorboard使用
  10. 梯度下降法and实战