Android 自定义下拉刷新ListView
package com.dwtedx.qq.view; 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.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar; import com.dwtedx.tst.R; public class DropdownListView extends ListView implements OnScrollListener { private static final String TAG = "listview"; private final static int RELEASE_To_REFRESH = ;
private final static int PULL_To_REFRESH = ;
private final static int REFRESHING = ;
private final static int DONE = ;
private final static int LOADING = ; // 实际的padding的距离与界面上偏移距离的比例
private final static int RATIO = ; private LayoutInflater inflater;
private FrameLayout fl;
private LinearLayout headView; // private View line;
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 OnRefreshListenerHeader refreshListenerHeader; private boolean isRefreshableHeader; public DropdownListView(Context context) {
super(context);
init(context);
} public DropdownListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
} private void init(Context context) {
setCacheColorHint(context.getResources().getColor(R.color.transparent));
inflater = LayoutInflater.from(context); fl = (FrameLayout)inflater.inflate(R.layout.dropdown_lv_head, null);
headView = (LinearLayout) fl.findViewById(R.id.drop_down_head); progressBar = (ProgressBar) fl.findViewById(R.id.loading);
measureView(headView); headContentHeight = headView.getMeasuredHeight();
headContentWidth = headView.getMeasuredWidth(); headView.setPadding(, - * headContentHeight, , );
headView.invalidate(); Log.v("size", "width:" + headContentWidth + " height:"
+ headContentHeight); addHeaderView(fl, null, false);
// addHeaderView(headView, null, false);
setOnScrollListener(this); state = DONE;
isRefreshableHeader = false;
} public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,
int arg3) {
firstItemIndex = firstVisiableItem;
} public void onScrollStateChanged(AbsListView arg0, int scrollState) {
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
// 判断滚动到底部 }
} public boolean onTouchEvent(MotionEvent event) { if (isRefreshableHeader) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (firstItemIndex == && !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();
// recoverLine();
onRefresh(); Log.v(TAG, "由松开刷新状态,到done状态");
}
} isRecored = false;
isBack = false; break; case MotionEvent.ACTION_MOVE:
int tempY = (int) event.getY();
if (!isRecored && firstItemIndex == ) {
Log.v(TAG, "在move时候记录下位置");
isRecored = true;
startY = tempY;
} if (state != REFRESHING && isRecored && state != LOADING) { // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动 // 可以松手去刷新了
if (state == RELEASE_To_REFRESH) { setSelection(); // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
if (((tempY - startY) / RATIO < headContentHeight)
&& (tempY - startY) > ) {
state = PULL_To_REFRESH;
changeHeaderViewByState(); Log.v(TAG, "由松开刷新状态转变到下拉刷新状态");
}
// 一下子推到顶了
else if (tempY - startY <= ) {
state = DONE;
changeHeaderViewByState(); Log.v(TAG, "由松开刷新状态转变到done状态");
}
// 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
else {
// 不用进行特别的操作,只用更新paddingTop的值就行了
}
}
// 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
if (state == PULL_To_REFRESH) { setSelection(); // 下拉到可以进入RELEASE_TO_REFRESH的状态
if ((tempY - startY) / RATIO >= headContentHeight) {
state = RELEASE_To_REFRESH;
isBack = true;
changeHeaderViewByState(); Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");
}
// 上推到顶了
else if (tempY - startY <= ) {
state = DONE;
changeHeaderViewByState(); Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");
}
} // done状态下
if (state == DONE) {
if (tempY - startY > ) {
state = PULL_To_REFRESH;
changeHeaderViewByState();
}
} // 更新headView的size
if (state == PULL_To_REFRESH) {
headView.setPadding(, - * headContentHeight
+ (tempY - startY) / RATIO, , );
} // 更新headView的paddingTop
if (state == RELEASE_To_REFRESH) {
headView.setPadding(, (tempY - startY) / RATIO
- headContentHeight, , );
}
} break;
}
} return super.onTouchEvent(event);
} // 当状态改变时候,调用该方法,以更新界面
private void changeHeaderViewByState() {
switch (state) {
case RELEASE_To_REFRESH:
progressBar.setVisibility(View.VISIBLE); Log.v(TAG, "当前状态,松开刷新");
break;
case PULL_To_REFRESH:
progressBar.setVisibility(View.VISIBLE);
// 是由RELEASE_To_REFRESH状态转变来的
if (isBack) {
isBack = false; } else {
}
Log.v(TAG, "当前状态,下拉刷新");
break; case REFRESHING: headView.setPadding(, , , ); progressBar.setVisibility(View.VISIBLE); Log.v(TAG, "当前状态,正在刷新...");
break;
case DONE:
headView.setPadding(, - * headContentHeight, , ); progressBar.setVisibility(View.GONE);
Log.v(TAG, "当前状态,done");
break;
}
} public void setOnRefreshListenerHead(
OnRefreshListenerHeader refreshListenerHeader) {
this.refreshListenerHeader = refreshListenerHeader;
isRefreshableHeader = true;
} public interface OnRefreshListenerHeader {
public void onRefresh();
} public interface OnRefreshListenerFooter {
public void onRefresh();
} public void onRefreshCompleteHeader() {
state = DONE;
changeHeaderViewByState();
} private void onRefresh() {
if (refreshListenerHeader != null) {
refreshListenerHeader.onRefresh();
}
} // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(, + , p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > ) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
} public void setAdapter(BaseAdapter adapter) {
super.setAdapter(adapter);
}
}
对应头部布局:
<?xml version="1.0" encoding="utf-8"?> <!-- ListView的头部 -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" > <View
android:id="@+id/line"
android:layout_width="0.2dip"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:background="@color/gray" /> <LinearLayout
android:id="@+id/drop_down_head"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:gravity="center_horizontal"
android:orientation="vertical" > <View
android:layout_width="0.2dip"
android:layout_height="20dip"
android:layout_gravity="center_horizontal"
android:background="@color/gray" /> <ProgressBar
android:id="@+id/loading"
android:layout_width="20dip"
android:layout_height="20dip"
android:background="@drawable/circle_shape"
android:indeterminateDrawable="@drawable/loading" />
</LinearLayout> </FrameLayout>
Android 自定义下拉刷新ListView的更多相关文章
- Android自定义下拉刷新
网上的下拉刷新功能很多,不过基本上都是隐藏header的,而项目里面需要只隐藏部分的header,类似QQ好友动态的效果,修改了一些现有的,最后有很多问题,所以就自己自定义了一个,逻辑也很简单,首先就 ...
- Android PullToRrefresh 自定义下拉刷新动画 (listview、scrollview等)
PullToRefreshScrollView 自定义下拉刷新动画,只需改一处. 以下部分转载自http://blog.csdn.net/superjunjin/article/details/450 ...
- Xamarin. Android实现下拉刷新功能
PS:发现文章被其他网站或者博客抓取后发表为原创了,给图片加了个水印 下拉刷新功能在安卓和iOS中非常常见,一般实现这样的功能都是直接使用第三方的库,网上能找到很多这样的开源库.然而在Xamarin. ...
- 滚动到底部加载更多及下拉刷新listview的使用
最新内容建议直接访问原文:滚动到底部加载更多及下拉刷新listview的使用 本文主要介绍可同时实现下拉刷新及滑动到底部加载更多的ListView的使用. 该ListView优点包括:a. 可自定义下 ...
- Android智能下拉刷新加载框架—看这些就够了
一些值得学习的几个下拉刷新上拉加载开源库 Android智能下拉刷新框架-SmartRefreshLayout 支持所有的 View(AbsListView.RecyclerView.WebView. ...
- 自定义控件学习——下拉刷新ListView
效果 开始用Android Studio写了,还有挺多不明白这IDE用法的地方....蛋疼 主要思路 1. 添加了自定义的头布局 2. 默认让头布局隐藏setPadding.设置 -自身的高度 ...
- Android 定制下拉刷新头部 Ultra Pull To Refresh
我们看到手机中的各种APP的花样繁多的下拉刷新是不是有点心动呢,想着自己定制自己的专门的下拉刷新,市场上比如,58同城,京东,天猫,美团等下拉刷新都是在下拉头部执行帧动画,我最近看到一个APP,就是慕 ...
- 自定义下拉刷新上拉加载View
MainActivity.java package com.heima52.pullrefresh; import java.util.ArrayList; import com.heima52.pu ...
- 使用MJRefresh自定义下拉刷新,上拉加载动画
有时候我们需要自己设置下拉刷新,上拉加载动画的实现,这里主要是记录下使用MJRefresh自定义下拉刷新,上拉加载动画..... 下拉刷新我们只需要继承MJRefreshGifHeader即可: 实现 ...
随机推荐
- iOS数组、字典与json字符串的转换
/*! * 将字典或者数组转化为JSON串 * * @param theData <#theData description#> * * @return <#return value ...
- VirtualBox添加共享文件夹
直接上图 添加了一个名为"Ubuntu10.04-en"的共享文件夹 但是按照它说的命令 mount -t vboxsf share mount_point 打入,然后悲剧了 错误 ...
- oracle中的rowid和数据行的结构
在oracle数据库系统中每一行都有一个rowid,oracle数据库系统就是利用rowid来定位数据行的.rowid也是oracle中内置的一个标量数据类型 rowid有一下特点; 是数据库中每一行 ...
- jq插件又来了,模拟select下拉框,支持上下方向键哦
好久没来了,更新下插件, 这个原理就是利用的 input[type='hidden']和自定义属性data-value捆绑传值操作的,可是设置默认选项,回调等参数,代码不多,比较简单,吼吼 (func ...
- MYSQL delete 从多人表中删除
语法 1. delete table_list_A from table_list_B where bool_expression; 从delete_table_list_A 删除 bool expr ...
- 定制化Azure站点Java运行环境(3)
定制化Azure Website提供的默认的Tomcat和JDK环境 在我们之前的测试中,如果你访问你的WEB站点URL时不加任何上下文,实际上你看到的web界面是系统自带的测试页面index.jsp ...
- javascript链式调用实现方式总结
方法链一般适合对一个对象进行连续操作(集中在一句代码).一定程度上可以减少代码量,缺点是它占用了函数的返回值. 一.方法体内返回对象实例自身(this) function ClassA(){ this ...
- JDBC批量操作
/** * 批量执行预定义模式的SQL */ public static void exeBatchParparedSQL() { ...
- Ubuntu12.04 Jdk1.7 Tomct7.0部署配置
jdk1.7 下载 http://download.oracle.com/otn-pub/java/jdk/7u67-b01/jdk-7u67-linux-x64.tar.gz?AuthParam=1 ...
- 网易云课堂_C++程序设计入门(上)_第6单元:丹枫虽老犹多态–继承与多态_第6单元作业【2】- 在线编程(难度:中)
第6单元作业[2]- 在线编程(难度:中) 查看帮助 返回 温馨提示: 1.本次作业属于Online Judge题目,提交后由系统即时判分. 2.学生可以在作业截止时间之前不限次数提交答案,系统 ...