1. package com.dwtedx.qq.view;
  2.  
  3. import android.content.Context;
  4. import android.util.AttributeSet;
  5. import android.util.Log;
  6. import android.view.LayoutInflater;
  7. import android.view.MotionEvent;
  8. import android.view.View;
  9. import android.view.ViewGroup;
  10. import android.widget.AbsListView;
  11. import android.widget.AbsListView.OnScrollListener;
  12. import android.widget.BaseAdapter;
  13. import android.widget.FrameLayout;
  14. import android.widget.LinearLayout;
  15. import android.widget.ListView;
  16. import android.widget.ProgressBar;
  17.  
  18. import com.dwtedx.tst.R;
  19.  
  20. public class DropdownListView extends ListView implements OnScrollListener {
  21.  
  22. private static final String TAG = "listview";
  23.  
  24. private final static int RELEASE_To_REFRESH = ;
  25. private final static int PULL_To_REFRESH = ;
  26. private final static int REFRESHING = ;
  27. private final static int DONE = ;
  28. private final static int LOADING = ;
  29.  
  30. // 实际的padding的距离与界面上偏移距离的比例
  31. private final static int RATIO = ;
  32.  
  33. private LayoutInflater inflater;
  34. private FrameLayout fl;
  35. private LinearLayout headView;
  36.  
  37. // private View line;
  38. private ProgressBar progressBar;
  39.  
  40. // private RotateAnimation animation;
  41. // private RotateAnimation reverseAnimation;
  42.  
  43. // 用于保证startY的值在一个完整的touch事件中只被记录一次
  44. private boolean isRecored;
  45.  
  46. private int headContentWidth;
  47. private int headContentHeight;
  48.  
  49. private int startY;
  50. private int firstItemIndex;
  51.  
  52. private int state;
  53.  
  54. private boolean isBack;
  55.  
  56. private OnRefreshListenerHeader refreshListenerHeader;
  57.  
  58. private boolean isRefreshableHeader;
  59.  
  60. public DropdownListView(Context context) {
  61. super(context);
  62. init(context);
  63. }
  64.  
  65. public DropdownListView(Context context, AttributeSet attrs) {
  66. super(context, attrs);
  67. init(context);
  68. }
  69.  
  70. private void init(Context context) {
  71. setCacheColorHint(context.getResources().getColor(R.color.transparent));
  72. inflater = LayoutInflater.from(context);
  73.  
  74. fl = (FrameLayout)inflater.inflate(R.layout.dropdown_lv_head, null);
  75. headView = (LinearLayout) fl.findViewById(R.id.drop_down_head);
  76.  
  77. progressBar = (ProgressBar) fl.findViewById(R.id.loading);
  78. measureView(headView);
  79.  
  80. headContentHeight = headView.getMeasuredHeight();
  81. headContentWidth = headView.getMeasuredWidth();
  82.  
  83. headView.setPadding(, - * headContentHeight, , );
  84. headView.invalidate();
  85.  
  86. Log.v("size", "width:" + headContentWidth + " height:"
  87. + headContentHeight);
  88.  
  89. addHeaderView(fl, null, false);
  90. // addHeaderView(headView, null, false);
  91. setOnScrollListener(this);
  92.  
  93. state = DONE;
  94. isRefreshableHeader = false;
  95. }
  96.  
  97. public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,
  98. int arg3) {
  99. firstItemIndex = firstVisiableItem;
  100. }
  101.  
  102. public void onScrollStateChanged(AbsListView arg0, int scrollState) {
  103. if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
  104. // 判断滚动到底部
  105.  
  106. }
  107. }
  108.  
  109. public boolean onTouchEvent(MotionEvent event) {
  110.  
  111. if (isRefreshableHeader) {
  112. switch (event.getAction()) {
  113. case MotionEvent.ACTION_DOWN:
  114. if (firstItemIndex == && !isRecored) {
  115. isRecored = true;
  116. startY = (int) event.getY();
  117. Log.v(TAG, "在down时候记录当前位置‘");
  118. }
  119. break;
  120.  
  121. case MotionEvent.ACTION_UP:
  122.  
  123. if (state != REFRESHING && state != LOADING) {
  124. if (state == DONE) {
  125. // 什么都不做
  126. }
  127. if (state == PULL_To_REFRESH) {
  128. state = DONE;
  129. changeHeaderViewByState();
  130.  
  131. Log.v(TAG, "由下拉刷新状态,到done状态");
  132. }
  133. if (state == RELEASE_To_REFRESH) {
  134. state = REFRESHING;
  135.  
  136. changeHeaderViewByState();
  137. // recoverLine();
  138. onRefresh();
  139.  
  140. Log.v(TAG, "由松开刷新状态,到done状态");
  141. }
  142. }
  143.  
  144. isRecored = false;
  145. isBack = false;
  146.  
  147. break;
  148.  
  149. case MotionEvent.ACTION_MOVE:
  150. int tempY = (int) event.getY();
  151. if (!isRecored && firstItemIndex == ) {
  152. Log.v(TAG, "在move时候记录下位置");
  153. isRecored = true;
  154. startY = tempY;
  155. }
  156.  
  157. if (state != REFRESHING && isRecored && state != LOADING) {
  158.  
  159. // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
  160.  
  161. // 可以松手去刷新了
  162. if (state == RELEASE_To_REFRESH) {
  163.  
  164. setSelection();
  165.  
  166. // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
  167. if (((tempY - startY) / RATIO < headContentHeight)
  168. && (tempY - startY) > ) {
  169. state = PULL_To_REFRESH;
  170. changeHeaderViewByState();
  171.  
  172. Log.v(TAG, "由松开刷新状态转变到下拉刷新状态");
  173. }
  174. // 一下子推到顶了
  175. else if (tempY - startY <= ) {
  176. state = DONE;
  177. changeHeaderViewByState();
  178.  
  179. Log.v(TAG, "由松开刷新状态转变到done状态");
  180. }
  181. // 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
  182. else {
  183. // 不用进行特别的操作,只用更新paddingTop的值就行了
  184. }
  185. }
  186. // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
  187. if (state == PULL_To_REFRESH) {
  188.  
  189. setSelection();
  190.  
  191. // 下拉到可以进入RELEASE_TO_REFRESH的状态
  192. if ((tempY - startY) / RATIO >= headContentHeight) {
  193. state = RELEASE_To_REFRESH;
  194. isBack = true;
  195. changeHeaderViewByState();
  196.  
  197. Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");
  198. }
  199. // 上推到顶了
  200. else if (tempY - startY <= ) {
  201. state = DONE;
  202. changeHeaderViewByState();
  203.  
  204. Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");
  205. }
  206. }
  207.  
  208. // done状态下
  209. if (state == DONE) {
  210. if (tempY - startY > ) {
  211. state = PULL_To_REFRESH;
  212. changeHeaderViewByState();
  213. }
  214. }
  215.  
  216. // 更新headView的size
  217. if (state == PULL_To_REFRESH) {
  218. headView.setPadding(, - * headContentHeight
  219. + (tempY - startY) / RATIO, , );
  220. }
  221.  
  222. // 更新headView的paddingTop
  223. if (state == RELEASE_To_REFRESH) {
  224. headView.setPadding(, (tempY - startY) / RATIO
  225. - headContentHeight, , );
  226. }
  227. }
  228.  
  229. break;
  230. }
  231. }
  232.  
  233. return super.onTouchEvent(event);
  234. }
  235.  
  236. // 当状态改变时候,调用该方法,以更新界面
  237. private void changeHeaderViewByState() {
  238. switch (state) {
  239. case RELEASE_To_REFRESH:
  240. progressBar.setVisibility(View.VISIBLE);
  241.  
  242. Log.v(TAG, "当前状态,松开刷新");
  243. break;
  244. case PULL_To_REFRESH:
  245. progressBar.setVisibility(View.VISIBLE);
  246. // 是由RELEASE_To_REFRESH状态转变来的
  247. if (isBack) {
  248. isBack = false;
  249.  
  250. } else {
  251. }
  252. Log.v(TAG, "当前状态,下拉刷新");
  253. break;
  254.  
  255. case REFRESHING:
  256.  
  257. headView.setPadding(, , , );
  258.  
  259. progressBar.setVisibility(View.VISIBLE);
  260.  
  261. Log.v(TAG, "当前状态,正在刷新...");
  262. break;
  263. case DONE:
  264. headView.setPadding(, - * headContentHeight, , );
  265.  
  266. progressBar.setVisibility(View.GONE);
  267. Log.v(TAG, "当前状态,done");
  268. break;
  269. }
  270. }
  271.  
  272. public void setOnRefreshListenerHead(
  273. OnRefreshListenerHeader refreshListenerHeader) {
  274. this.refreshListenerHeader = refreshListenerHeader;
  275. isRefreshableHeader = true;
  276. }
  277.  
  278. public interface OnRefreshListenerHeader {
  279. public void onRefresh();
  280. }
  281.  
  282. public interface OnRefreshListenerFooter {
  283. public void onRefresh();
  284. }
  285.  
  286. public void onRefreshCompleteHeader() {
  287. state = DONE;
  288. changeHeaderViewByState();
  289. }
  290.  
  291. private void onRefresh() {
  292. if (refreshListenerHeader != null) {
  293. refreshListenerHeader.onRefresh();
  294. }
  295. }
  296.  
  297. // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
  298. private void measureView(View child) {
  299. ViewGroup.LayoutParams p = child.getLayoutParams();
  300. if (p == null) {
  301. p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
  302. ViewGroup.LayoutParams.WRAP_CONTENT);
  303. }
  304. int childWidthSpec = ViewGroup.getChildMeasureSpec(, + , p.width);
  305. int lpHeight = p.height;
  306. int childHeightSpec;
  307. if (lpHeight > ) {
  308. childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
  309. MeasureSpec.EXACTLY);
  310. } else {
  311. childHeightSpec = MeasureSpec.makeMeasureSpec(,
  312. MeasureSpec.UNSPECIFIED);
  313. }
  314. child.measure(childWidthSpec, childHeightSpec);
  315. }
  316.  
  317. public void setAdapter(BaseAdapter adapter) {
  318. super.setAdapter(adapter);
  319. }
  320. }

对应头部布局:

  1. <?xml version="1.0" encoding="utf-8"?>
  2.  
  3. <!-- ListView的头部 -->
  4. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  5. android:layout_width="match_parent"
  6. android:layout_height="wrap_content" >
  7.  
  8. <View
  9. android:id="@+id/line"
  10. android:layout_width="0.2dip"
  11. android:layout_height="match_parent"
  12. android:layout_gravity="center_horizontal"
  13. android:background="@color/gray" />
  14.  
  15. <LinearLayout
  16. android:id="@+id/drop_down_head"
  17. android:layout_width="match_parent"
  18. android:layout_height="wrap_content"
  19. android:layout_gravity="bottom"
  20. android:gravity="center_horizontal"
  21. android:orientation="vertical" >
  22.  
  23. <View
  24. android:layout_width="0.2dip"
  25. android:layout_height="20dip"
  26. android:layout_gravity="center_horizontal"
  27. android:background="@color/gray" />
  28.  
  29. <ProgressBar
  30. android:id="@+id/loading"
  31. android:layout_width="20dip"
  32. android:layout_height="20dip"
  33. android:background="@drawable/circle_shape"
  34. android:indeterminateDrawable="@drawable/loading" />
  35. </LinearLayout>
  36.  
  37. </FrameLayout>

Android 自定义下拉刷新ListView的更多相关文章

  1. Android自定义下拉刷新

    网上的下拉刷新功能很多,不过基本上都是隐藏header的,而项目里面需要只隐藏部分的header,类似QQ好友动态的效果,修改了一些现有的,最后有很多问题,所以就自己自定义了一个,逻辑也很简单,首先就 ...

  2. Android PullToRrefresh 自定义下拉刷新动画 (listview、scrollview等)

    PullToRefreshScrollView 自定义下拉刷新动画,只需改一处. 以下部分转载自http://blog.csdn.net/superjunjin/article/details/450 ...

  3. Xamarin. Android实现下拉刷新功能

    PS:发现文章被其他网站或者博客抓取后发表为原创了,给图片加了个水印 下拉刷新功能在安卓和iOS中非常常见,一般实现这样的功能都是直接使用第三方的库,网上能找到很多这样的开源库.然而在Xamarin. ...

  4. 滚动到底部加载更多及下拉刷新listview的使用

    最新内容建议直接访问原文:滚动到底部加载更多及下拉刷新listview的使用 本文主要介绍可同时实现下拉刷新及滑动到底部加载更多的ListView的使用. 该ListView优点包括:a. 可自定义下 ...

  5. Android智能下拉刷新加载框架—看这些就够了

    一些值得学习的几个下拉刷新上拉加载开源库 Android智能下拉刷新框架-SmartRefreshLayout 支持所有的 View(AbsListView.RecyclerView.WebView. ...

  6. 自定义控件学习——下拉刷新ListView

    效果 开始用Android Studio写了,还有挺多不明白这IDE用法的地方....蛋疼 主要思路 1. 添加了自定义的头布局    2. 默认让头布局隐藏setPadding.设置 -自身的高度  ...

  7. Android 定制下拉刷新头部 Ultra Pull To Refresh

    我们看到手机中的各种APP的花样繁多的下拉刷新是不是有点心动呢,想着自己定制自己的专门的下拉刷新,市场上比如,58同城,京东,天猫,美团等下拉刷新都是在下拉头部执行帧动画,我最近看到一个APP,就是慕 ...

  8. 自定义下拉刷新上拉加载View

    MainActivity.java package com.heima52.pullrefresh; import java.util.ArrayList; import com.heima52.pu ...

  9. 使用MJRefresh自定义下拉刷新,上拉加载动画

    有时候我们需要自己设置下拉刷新,上拉加载动画的实现,这里主要是记录下使用MJRefresh自定义下拉刷新,上拉加载动画..... 下拉刷新我们只需要继承MJRefreshGifHeader即可: 实现 ...

随机推荐

  1. JQ 操作样式,单选按钮跟复选框

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. 在C#中使用CastleDynamicProxy 实现AOP

      原文链接:Aspect Oriented Programming (AOP) in C# using CastleDynamicProxy 本文主要展示在C#中如何使用Castle Dynamic ...

  3. SQL Performance Improvement Techniques(转)

    原文地址:http://www.codeproject.com/Tips/1023621/SQL-Performance-Improvement-Techniques This article pro ...

  4. hdu2304Electrical Outlets

    Problem Description Roy has just moved into a new apartment. Well, actually the apartment itself is ...

  5. Eclipse导入jre方法

    处理步骤:引入本机安装的jre1.8的步骤如下:

  6. linux学习笔记之线程

    线程同步机制:http://www.cnblogs.com/zheng39562/p/4270019.html 一.基础知识 1:基础知识. 1,线程需要的信息有:线程ID,寄存器,栈,调度优先级和策 ...

  7. EF 数据迁移问题总结

    在项目中使用Entity Framework的Code First模式,进行数据迁移时,Migration文件夹中存放的是每一次Entity的修改如何同步到数据的操作方法,每个文件中都只有Up和Dow ...

  8. Node.js HTTP 使用详解

    对于初学者有没有发觉在查看Node.js官方API的时候非常简单,只有几个洋文描述两下子,没了,我第一次一口气看完所以API后,对于第一个示例都有些懵,特别是参数里的request和response, ...

  9. 添加解压缩版Tomcat到系统服务

    一.安装服务 在命令行中进入/Tomcat路径/bin/,执行“service.bat install”: 说明:1.服务名和显示名称:service.bat中设置了默认的服务名称,不同版本分别命名为 ...

  10. 几种MEMS陀螺仪(gyroscope)的设计和性能比较

    现在市场上的MEMS陀螺仪主要有SYSTRON.BOSCH和INVENSENSE设计和生产.前两者设计的陀螺仪属高端产品,主要用于汽车.后者的属低端产品,主要用于消费类电子,象任天堂的Wii.ADI2 ...