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即可: 实现 ...
随机推荐
- 大数值基础、for与while循环的简单对比
- js循环遍历
//获取多个用户id 一般用在复选框 cust_id = 1,2,3,4; var str = cust_id.split(","); for (var key ...
- printf--动态指定输出格式长度
char a1[] = {'A', 'B', 'C'}; char a2[] = "world"; printf(, a1, , a2); printf("[%.*s][ ...
- 理解Window和WindowManger
一.Window简介 作用:桌面上显示一个类似悬浮的东西. 介绍:Window是一个抽象类,实现是由PhoneWindow.WindowManager是外界访问Window的入口.但是最终实现是在Wi ...
- 运算符 - PHP手册笔记
运算符优先级 每种编程语言都有运算符,运算符要学会灵活使用. 运算符拥有不同的优先级和结合方向. <?php var_dump(1 <= 1 == 1); // true var_dump ...
- delphi idhttp 实战用法(TIdhttpEx)
以delphi XE8 自带indy(10.5.8.0)组件为例,分享实战中遇到的问题及解决方法. TIdHttpEx 用法实例01[多线程获取网页](包含完整源码) 实例02(如何Post参数,如何 ...
- js 中的switch
前言 switch 这种表达式在很多语言中都有,比如java, C等待, 使用switch比使用if else 来得方便,来得清晰. 使用语法很简单: switch(n) { case 1: 执行代码 ...
- perl binlog dml操作报告
<pre name="code" class="html">if ( $#ARGV < 2 ){ print "please inp ...
- JIRA官方:JIRA项目跟踪
问题无处不在 使用JIRA来捕捉任何类型的问题——从软件缺陷到新特性到需求和故事到任务和活动项.你可以很方便地定义自己的问题类型以匹配团队工作需要. 自定义工作流 一个项目跟踪工具不应该决定你的工作方 ...
- C errors recods
error: unterminated #ifndef 1,权限问题 2,少了#endif