ListView下拉刷新
本内容为复制代码:
一、自定义ListView控件:
package com.xczl.smart.view; import java.util.Date; import com.suliang.R; import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.MeasureSpec;
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.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView; /**
* 自定义ListView,继承ListView实现OnScrollListener接口
*
* @author Administrator
*
*/
public class MyListView extends ListView implements OnScrollListener { private static final String TAG = "listview"; private final static int RELEASE_To_REFRESH = 0;
private final static int PULL_To_REFRESH = 1;
private final static int REFRESHING = 2;
private final static int DONE = 3;
private final static int LOADING = 4; // 实际的padding的距离与界面上偏移距离的比例
private final static int RATIO = 3; private LayoutInflater inflater; private LinearLayout headView; private TextView tipsTextview;
private TextView lastUpdatedTextView;
private ImageView arrowImageView;
private ProgressBar progressBar; private RotateAnimation animation;
private RotateAnimation reverseAnimation; // 用于保证startY的值在一个完整的touch事件中只被记录一次
private boolean isRecored; private int headContentWidth;
private int headContentHeight; private int startY;
private int firstItemIndex; private int state; private boolean isBack; private OnRefreshListener refreshListener; private boolean isRefreshable; public MyListView(Context context) {
super(context);
init(context);
} public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
} private void init(Context context) {
inflater = LayoutInflater.from(context); headView = (LinearLayout) inflater.inflate(R.layout.head, null); arrowImageView = (ImageView) headView
.findViewById(R.id.head_arrowImageView); arrowImageView.setMinimumWidth(70);
arrowImageView.setMinimumHeight(50); progressBar = (ProgressBar) headView
.findViewById(R.id.head_progressBar);
tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);
lastUpdatedTextView = (TextView) headView
.findViewById(R.id.head_lastUpdateTextView); measureView(headView); headContentHeight = headView.getMeasuredHeight();
headContentWidth = headView.getMeasuredWidth(); headView.setPadding(0, -1 * headContentHeight, 0, 0);
headView.invalidate(); Log.v("size", "width:" + headContentWidth + " height:"
+ headContentHeight); addHeaderView(headView, null, false);
setOnScrollListener(this); animation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(250);
animation.setFillAfter(true); reverseAnimation = new RotateAnimation(-180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
reverseAnimation.setInterpolator(new LinearInterpolator());
reverseAnimation.setDuration(200);
reverseAnimation.setFillAfter(true); state = DONE;
isRefreshable = false;
} public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,
int arg3) {
firstItemIndex = firstVisiableItem;
} public void onScrollStateChanged(AbsListView arg0, int arg1) {
} public boolean onTouchEvent(MotionEvent event) { if (isRefreshable) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (firstItemIndex == 0 && !isRecored) {
isRecored = true;
startY = (int) event.getY();
Log.v(TAG, "在down时候记录当前位置‘");
}
break; case MotionEvent.ACTION_UP: if (state != REFRESHING && state != LOADING) {
if (state == DONE) {
// 什么都不做
}
if (state == PULL_To_REFRESH) {
state = DONE;
changeHeaderViewByState(); Log.v(TAG, "由下拉刷新状态,到done状态");
}
if (state == RELEASE_To_REFRESH) {
state = REFRESHING;
changeHeaderViewByState();
onRefresh(); Log.v(TAG, "由松开刷新状态,到done状态");
}
} isRecored = false;
isBack = false; break; case MotionEvent.ACTION_MOVE:
int tempY = (int) event.getY(); if (!isRecored && firstItemIndex == 0) {
Log.v(TAG, "在move时候记录下位置");
isRecored = true;
startY = tempY;
} if (state != REFRESHING && isRecored && state != LOADING) { // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动 // 可以松手去刷新了
if (state == RELEASE_To_REFRESH) { setSelection(0); // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
if (((tempY - startY) / RATIO < headContentHeight)
&& (tempY - startY) > 0) {
state = PULL_To_REFRESH;
changeHeaderViewByState(); Log.v(TAG, "由松开刷新状态转变到下拉刷新状态");
}
// 一下子推到顶了
else if (tempY - startY <= 0) {
state = DONE;
changeHeaderViewByState(); Log.v(TAG, "由松开刷新状态转变到done状态");
}
// 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
else {
// 不用进行特别的操作,只用更新paddingTop的值就行了
}
}
// 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
if (state == PULL_To_REFRESH) { setSelection(0); // 下拉到可以进入RELEASE_TO_REFRESH的状态
if ((tempY - startY) / RATIO >= headContentHeight) {
state = RELEASE_To_REFRESH;
isBack = true;
changeHeaderViewByState(); Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");
}
// 上推到顶了
else if (tempY - startY <= 0) {
state = DONE;
changeHeaderViewByState(); Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");
}
} // done状态下
if (state == DONE) {
if (tempY - startY > 0) {
state = PULL_To_REFRESH;
changeHeaderViewByState();
}
} // 更新headView的size
if (state == PULL_To_REFRESH) {
headView.setPadding(0, -1 * headContentHeight
+ (tempY - startY) / RATIO, 0, 0); } // 更新headView的paddingTop
if (state == RELEASE_To_REFRESH) {
headView.setPadding(0, (tempY - startY) / RATIO
- headContentHeight, 0, 0);
} } break;
}
} return super.onTouchEvent(event);
} // 当状态改变时候,调用该方法,以更新界面
private void changeHeaderViewByState() {
switch (state) {
case RELEASE_To_REFRESH:
arrowImageView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
tipsTextview.setVisibility(View.VISIBLE);
lastUpdatedTextView.setVisibility(View.VISIBLE); arrowImageView.clearAnimation();
arrowImageView.startAnimation(animation); tipsTextview.setText("松开刷新"); Log.v(TAG, "当前状态,松开刷新");
break;
case PULL_To_REFRESH:
progressBar.setVisibility(View.GONE);
tipsTextview.setVisibility(View.VISIBLE);
lastUpdatedTextView.setVisibility(View.VISIBLE);
arrowImageView.clearAnimation();
arrowImageView.setVisibility(View.VISIBLE);
// 是由RELEASE_To_REFRESH状态转变来的
if (isBack) {
isBack = false;
arrowImageView.clearAnimation();
arrowImageView.startAnimation(reverseAnimation); tipsTextview.setText("下拉刷新");
} else {
tipsTextview.setText("下拉刷新");
}
Log.v(TAG, "当前状态,下拉刷新");
break; case REFRESHING: headView.setPadding(0, 0, 0, 0); progressBar.setVisibility(View.VISIBLE);
arrowImageView.clearAnimation();
arrowImageView.setVisibility(View.GONE);
tipsTextview.setText("正在刷新...");
lastUpdatedTextView.setVisibility(View.VISIBLE); Log.v(TAG, "当前状态,正在刷新...");
break;
case DONE:
headView.setPadding(0, -1 * headContentHeight, 0, 0); progressBar.setVisibility(View.GONE);
arrowImageView.clearAnimation();
arrowImageView.setImageResource(R.drawable.arrow);
tipsTextview.setText("下拉刷新");
lastUpdatedTextView.setVisibility(View.VISIBLE); Log.v(TAG, "当前状态,done");
break;
}
} public void setonRefreshListener(OnRefreshListener refreshListener) {
this.refreshListener = refreshListener;
isRefreshable = true;
} public interface OnRefreshListener {
public void onRefresh();
} public void onRefreshComplete() {
state = DONE;
lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());
changeHeaderViewByState();
} private void onRefresh() {
if (refreshListener != null) {
refreshListener.onRefresh();
}
} // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
} public void setAdapter(BaseAdapter adapter) {
lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());
super.setAdapter(adapter);
} }
二、下拉布局:
<?xml version="1.0" encoding="utf-8"?>
<!-- ListView的头部 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@color/title_green" > <!-- 内容 --> <RelativeLayout
android:id="@+id/head_contentlayout"
android:layout_width="fill_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/head_arrowImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/arrow" /> <ProgressBar
android:id="@+id/head_progressBar"
style="@android:style/Widget.ProgressBar.Inverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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_horizontal"
android:orientation="vertical" > <TextView
android:id="@+id/head_tipsTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="下拉刷新"
android:textSize="20sp" />
<TextView
android:id="@+id/head_lastUpdateTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="最后更新"
android:textColor="#FF0000"
android:textSize="10sp" />
</LinearLayout>
</RelativeLayout> </LinearLayout>
三、代码中使用:
MyListView mListView = (MyListView)view.findViewById(R.id.mlist);
/** 下拉刷新 */
mListView.setonRefreshListener(new com.xczl.smart.view.MyListView.OnRefreshListener() {
public void onRefresh() {
new AsyncTask<Void, Void, Void>() {
protected Void doInBackground(Void... params) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) { mListView.onRefreshComplete();
} }.execute();
}
});
ListView下拉刷新的更多相关文章
- Android—自定义控件实现ListView下拉刷新
这篇博客为大家介绍一个android常见的功能——ListView下拉刷新(参考自他人博客,网址忘记了,阅读他的代码自己理解注释的,希望能帮助到大家): 首先下拉未松手时候手机显示这样的界面: 下面的 ...
- ListView下拉刷新、上拉载入更多之封装改进
在Android中ListView下拉刷新.上拉载入更多示例一文中,Maxwin兄给出的控件比较强大,前面有详细介绍,但是有个不足就是,里面使用了一些资源文件,包括图片,String,layout,这 ...
- ListView下拉刷新上拉加载更多实现
这篇文章将带大家了解listview下拉刷新和上拉加载更多的实现过程,先看效果(注:图片中listview中的阴影可以加上属性android:fadingEdge="none"去掉 ...
- listview下拉刷新上拉加载扩展(三)-仿最新版美团外卖
本篇是基于上篇listview下拉刷新上拉加载扩展(二)-仿美团外卖改造而来,主要调整了headview的布局,并加了两个背景动画,看似高大上,其实很简单: as源码地址:http://downloa ...
- listview下拉刷新上拉加载扩展(二)-仿美团外卖
经过前几篇的listview下拉刷新上拉加载讲解,相信你对其实现机制有了一个深刻的认识了吧,那么这篇文章我们来实现一个高级的listview下拉刷新上拉加载-仿新版美团外卖的袋鼠动画: 项目结构: 是 ...
- listview下拉刷新上拉加载扩展(一)
前两篇实现了listview简单的下拉刷新和上拉加载,功能已经达到,单体验效果稍简陋,那么在这篇文章里我们来加一点效果,已达到我们常见的listview下拉刷新时的效果: 首先,在headview的x ...
- 手把手教你轻松实现listview下拉刷新
很多人觉得自定义一个listview下拉刷新上拉加载更多是一件很牛x的事情,不是大神写不出来,我想大多数童鞋都是做项目用到时就百度,什么pulltorefresh,xlistview...也不看原理, ...
- Android ListView下拉刷新时卡的问题解决小技巧
问题:ListView下拉刷新时看上去非常的卡 解决方案: 在BaseAdapter的getView方法中,有三个参数 public View getView(int position, View c ...
- listView下拉刷新加载数据
这个下拉效果在网上最早的例子恐怕就是Johan Nilsson的实现,http://johannilsson.com/2011/03/13/android-pull-to-refresh-update ...
- 自定义ListView下拉刷新上拉加载更多
自定义ListView下拉刷新上拉加载更多 自定义RecyclerView下拉刷新上拉加载更多 Listview现在用的很少了,基本都是使用Recycleview,但是不得不说Listview具有划时 ...
随机推荐
- sklearn学习笔记1
Image recognition with Support Vector Machines #our dataset is provided within scikit-learn #let's s ...
- linux mint 崩溃
换完linux mint 今天突然崩溃了.出现如下错误 因为是双屏.一个屏幕显示一般,这么不重要.搜了一下,找到解决方案 解决办法 ctrl+atl+f1 login sudo apt-get ins ...
- 检测文件是否有BOM 头,并删除BOM头(php)
将下面文件放在网站根目录访问即可,它会遍历当前目录下所有子目录,检测文件是否含有BOM头,并删除BOM头 <?php //remove the utf-8 boms //by magicbug ...
- [ActionScript 3.0] 分页排版
竖排版: 横排版: /*** 分页排版 ***/ var _column:int = 5;//列数 var _row:int = 3;//行数 var _vGap:Number = 20;//行间距 ...
- 【java】分页查询实体类
package com.dmsd.itoo.tool.pageModel; import java.io.Serializable; import java.util.HashMap; import ...
- ubuntu12.04 安装mac主题
1.下载主题包我把主题上传到了csdn的资源栏目,下载地址:http://download.csdn.net/detail/chenjiebin/4531537 2.将/mac/sharc/theme ...
- Django中提示TemplateDoesNotExist?
用的是1.9版本.需要在settings.py文件中设置TEMPLATES下的DIRS如下: TEMPLATES = [ { 'BACKEND': 'django.template.backends. ...
- Asprise-OCR的使用
Asprise-OCR下载地址: http://asprise.com/product/ocr/download.php?lang=csharp 其中需要使用的3个dll是AspriseOCR.dll ...
- 删除Json中的不需要的键值
var json = {'A': 1, ,'B': 2, 'ccc': 333} delete json['ccc'];
- 图片转base64
function convertImgToBase64(url, callback, outputFormat){ var canvas = document.createElement('CANVA ...