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即可: 实现 ...
随机推荐
- ThinkPHP框架搭建及常见问题(Apache或MySQL无法启动)----简单的初体验
有一定基础的人勿进,这篇讲的只是零基础入门,都是我刚接触以及我所了解到的人刚开始有疑惑的地方,具体框架介绍会在后面的博客中介绍 这一篇只是为了一个简单的页面显示而介绍的方法,不涉及代码,开发环境,所以 ...
- TCP/IP详解之:SNMP
基于TCP/IP的网络管理包含3个组成部分: 一个管理信息库MIB:MIB包含所有代理进程的所有可被查询和修改的参数 关于MIB的一套公用的结构和表示符号,即SMI(管理信息结构) 管理进程和代理进程 ...
- final的深入理解 - final数据
先通过例子看一看: package com.sotaof.testfinal; public class Value { int i; public Value(int i){ this.i = i; ...
- 关于js中window.location.href,location.href,parent.location.href,top.location.href的用法与区别(跳出iframe方法)
"window.location.href"."location.href"是本页面跳转 "parent.location.href"是上一 ...
- ZRender源码分析2:Storage(Model层)
回顾 上一篇请移步:zrender源码分析1:总体结构 本篇进行ZRender的MVC结构中的M进行分析 总体理解 上篇说到,Storage负责MVC层中的Model,也就是模型,对于zrender来 ...
- html5属性placeholder的js 向下兼容支持(jquery版)
placeholder是html5表单特性中比较好用的一条,但是苦于其向下兼容性,所以一般要做向下兼容的站点都不敢用,如果有用到的地方,也是用js简单模拟而实现的,那么有没有一个一劳永逸的方法去解决这 ...
- BaseFragment的定义—所有Fragment的父类
public abstract class BaseActivity extends AppCompatActivity implements View.OnClickListener { prote ...
- Python爬虫实战(3):安居客房产经纪人信息采集
1, 引言 Python开源网络爬虫项目启动之初,我们就把网络爬虫分成两类:即时爬虫和收割式网络爬虫.为了使用各种应用场景,该项目的整个网络爬虫产品线包含了四类产品,如下图所示: 本实战是上图中的“独 ...
- $.each与$(data).each区别
在前端使用使用JQuery解析Json数据时,在遍历数组或者对象数据时,经常使用的函数为each.发现此函数有两种形式: $.each $(data).each 所达到的效果是一样的,使用方法的有一些 ...
- python操作 redis-list
#!/usr/bin/python #!coding: utf-8 import redis if __name__=="__main__": try: conn=redis.St ...