打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Android下拉刷新功能实现过程详解

  1. package net.oschina.app.widget;  
  2.   
  3. import net.oschina.app.R;  
  4. import android.content.Context;  
  5. import android.util.AttributeSet;  
  6. import android.view.LayoutInflater;  
  7. import android.view.MotionEvent;  
  8. import android.view.View;  
  9. import android.view.ViewGroup;  
  10. import android.view.animation.LinearInterpolator;  
  11. import android.view.animation.RotateAnimation;  
  12. import android.widget.AbsListView;  
  13. import android.widget.AbsListView.OnScrollListener;  
  14. import android.widget.ImageView;  
  15. import android.widget.LinearLayout;  
  16. import android.widget.ListView;  
  17. import android.widget.ProgressBar;  
  18. import android.widget.TextView;  
  19.   
  20. /**  
  21.  * 下拉刷新控件  
  22.  * @author liux (http://my.oschina.net/liux)  
  23.  * @version 1.0  
  24.  * @created 2012-3-21  
  25.  */  
  26. public class PullToRefreshListView extends ListView implements OnScrollListener {    
  27.          
  28.     private final static String TAG = "PullToRefreshListView";    
  29.       
  30.     // 下拉刷新标志     
  31.     private final static int PULL_To_REFRESH = 0;   
  32.     // 松开刷新标志     
  33.     private final static int RELEASE_To_REFRESH = 1;   
  34.     // 正在刷新标志     
  35.     private final static int REFRESHING = 2;    
  36.     // 刷新完成标志     
  37.     private final static int DONE = 3;    
  38.     
  39.     private LayoutInflater inflater;    
  40.     
  41.     private LinearLayout headView;    
  42.     private TextView tipsTextview;    
  43.     private TextView lastUpdatedTextView;    
  44.     private ImageView arrowImageView;    
  45.     private ProgressBar progressBar;    
  46.     // 用来设置箭头图标动画效果     
  47.     private RotateAnimation animation;    
  48.     private RotateAnimation reverseAnimation;    
  49.     
  50.     // 用于保证startY的值在一个完整的touch事件中只被记录一次     
  51.     private boolean isRecored;    
  52.     
  53.     private int headContentWidth;    
  54.     private int headContentHeight;    
  55.     private int headContentOriginalTopPadding;  
  56.     
  57.     private int startY;    
  58.     private int firstItemIndex;    
  59.     private int currentScrollState;  
  60.     
  61.     private int state;    
  62.     
  63.     private boolean isBack;    
  64.     
  65.     public OnRefreshListener refreshListener;    
  66.       
  67.     public PullToRefreshListView(Context context, AttributeSet attrs) {    
  68.         super(context, attrs);    
  69.         init(context);    
  70.     }    
  71.       
  72.     public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {    
  73.         super(context, attrs, defStyle);    
  74.         init(context);    
  75.     }    
  76.     
  77.     private void init(Context context) {     
  78.         //设置滑动效果  
  79.         animation = new RotateAnimation(0, -180,    
  80.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f,    
  81.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f);    
  82.         animation.setInterpolator(new LinearInterpolator());    
  83.         animation.setDuration(100);    
  84.         animation.setFillAfter(true);    
  85.     
  86.         reverseAnimation = new RotateAnimation(-180, 0,    
  87.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f,    
  88.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f);    
  89.         reverseAnimation.setInterpolator(new LinearInterpolator());    
  90.         reverseAnimation.setDuration(100);    
  91.         reverseAnimation.setFillAfter(true);    
  92.           
  93.         inflater = LayoutInflater.from(context);    
  94.         headView = (LinearLayout) inflater.inflate(R.layout.pull_to_refresh_head, null);    
  95.     
  96.         arrowImageView = (ImageView) headView.findViewById(R.id.head_arrowImageView);    
  97.         arrowImageView.setMinimumWidth(50);    
  98.         arrowImageView.setMinimumHeight(50);    
  99.         progressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar);    
  100.         tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);    
  101.         lastUpdatedTextView = (TextView) headView.findViewById(R.id.head_lastUpdatedTextView);    
  102.           
  103.         headContentOriginalTopPadding = headView.getPaddingTop();    
  104.           
  105.           
  106.         measureView(headView);    
  107.         headContentHeight = headView.getMeasuredHeight();    
  108.         headContentWidth = headView.getMeasuredWidth();   
  109.           
  110.         headView.setPadding(headView.getPaddingLeft(), -1 * headContentHeight, headView.getPaddingRight(), headView.getPaddingBottom());    
  111.         headView.invalidate();    
  112.   
  113. //        System.out.println("初始高度:"+headContentHeight);   
  114. //        System.out.println("初始width:"+headContentWidth);  
  115. //        System.out.println("初始TopPad:"+headContentOriginalTopPadding);  
  116. //        System.out.println("headContentOriginalTopPadding:"+headContentOriginalTopPadding);  
  117. //        System.out.println("PaddingLeft:"+headView.getPaddingLeft());  
  118. //        System.out.println("PaddingRight:"+headView.getPaddingRight());  
  119. //        System.out.println("PaddingBottom:"+headView.getPaddingBottom());  
  120. //        System.out.println("headContentHeight:"+headContentHeight);  
  121.           
  122.         addHeaderView(headView);          
  123.         setOnScrollListener(this);   
  124.     }    
  125.     
  126.     public void onScroll(AbsListView view, int firstVisiableItem, int visibleItemCount,  int totalItemCount) {    
  127.         firstItemIndex = firstVisiableItem;    
  128.     }    
  129.     
  130.     public void onScrollStateChanged(AbsListView view, int scrollState) {    
  131.         currentScrollState = scrollState;  
  132.     }    
  133.     
  134.     public boolean onTouchEvent(MotionEvent event) {    
  135.         switch (event.getAction()) {    
  136.         case MotionEvent.ACTION_DOWN:    
  137.             if (firstItemIndex == 0 && !isRecored) {    
  138.                 startY = (int) event.getY();    
  139.                 isRecored = true;    
  140.                 //System.out.println("当前-按下高度-ACTION_DOWN-Y:"+startY);  
  141.             }    
  142.             break;    
  143.           
  144.         case MotionEvent.ACTION_CANCEL://失去焦点&取消动作  
  145.         case MotionEvent.ACTION_UP:    
  146.     
  147.             if (state != REFRESHING) {    
  148.                 if (state == DONE) {    
  149.                     //System.out.println("当前-抬起-ACTION_UP:DONE什么都不做");  
  150.                 }    
  151.                 else if (state == PULL_To_REFRESH) {    
  152.                     state = DONE;    
  153.                     changeHeaderViewByState();                        
  154.                     //System.out.println("当前-抬起-ACTION_UP:PULL_To_REFRESH-->DONE-由下拉刷新状态到刷新完成状态");  
  155.                 }    
  156.                 else if (state == RELEASE_To_REFRESH) {    
  157.                     state = REFRESHING;    
  158.                     changeHeaderViewByState();    
  159.                     onRefresh();                        
  160.                     //System.out.println("当前-抬起-ACTION_UP:RELEASE_To_REFRESH-->REFRESHING-由松开刷新状态,到刷新完成状态");  
  161.                 }    
  162.             }    
  163.     
  164.             isRecored = false;    
  165.             isBack = false;    
  166.     
  167.             break;    
  168.     
  169.         case MotionEvent.ACTION_MOVE:    
  170.             int tempY = (int) event.getY();   
  171.             //System.out.println("当前-滑动-ACTION_MOVE Y:"+tempY);  
  172.             if (!isRecored && firstItemIndex == 0) {    
  173.                 //System.out.println("当前-滑动-记录拖拽时的位置 Y:"+tempY);  
  174.                 isRecored = true;    
  175.                 startY = tempY;    
  176.             }    
  177.             if (state != REFRESHING && isRecored) {    
  178.                 // 可以松开刷新了     
  179.                 if (state == RELEASE_To_REFRESH) {    
  180.                     // 往上推,推到屏幕足够掩盖head的程度,但还没有全部掩盖     
  181.                     if ((tempY - startY < headContentHeight+20)    
  182.                             && (tempY - startY) > 0) {    
  183.                         state = PULL_To_REFRESH;    
  184.                         changeHeaderViewByState();                            
  185.                         //System.out.println("当前-滑动-ACTION_MOVE:RELEASE_To_REFRESH--》PULL_To_REFRESH-由松开刷新状态转变到下拉刷新状态");  
  186.                     }    
  187.                     // 一下子推到顶     
  188.                     else if (tempY - startY <= 0) {    
  189.                         state = DONE;    
  190.                         changeHeaderViewByState();                           
  191.                         //System.out.println("当前-滑动-ACTION_MOVE:RELEASE_To_REFRESH--》DONE-由松开刷新状态转变到done状态");  
  192.                     }    
  193.                     // 往下拉,或者还没有上推到屏幕顶部掩盖head     
  194.                     else {    
  195.                         // 不用进行特别的操作,只用更新paddingTop的值就行了     
  196.                     }    
  197.                 }    
  198.                 // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态     
  199.                 else if (state == PULL_To_REFRESH) {    
  200.                     // 下拉到可以进入RELEASE_TO_REFRESH的状态     
  201.                     if (tempY - startY >= headContentHeight+20 && currentScrollState == SCROLL_STATE_TOUCH_SCROLL) {    
  202.                         state = RELEASE_To_REFRESH;    
  203.                         isBack = true;    
  204.                         changeHeaderViewByState();    
  205.                         //System.out.println("当前-滑动-PULL_To_REFRESH--》RELEASE_To_REFRESH-由done或者下拉刷新状态转变到松开刷新");  
  206.                     }    
  207.                     // 上推到顶了     
  208.                     else if (tempY - startY <= 0) {    
  209.                         state = DONE;    
  210.                         changeHeaderViewByState();     
  211.                         //System.out.println("当前-滑动-PULL_To_REFRESH--》DONE-由Done或者下拉刷新状态转变到done状态");  
  212.                     }    
  213.                 }    
  214.                 // done状态下     
  215.                 else if (state == DONE) {    
  216.                     if (tempY - startY > 0) {    
  217.                         state = PULL_To_REFRESH;    
  218.                         changeHeaderViewByState();   
  219.                         //System.out.println("当前-滑动-DONE--》PULL_To_REFRESH-由done状态转变到下拉刷新状态");  
  220.                     }    
  221.                 }    
  222.                   
  223.                 // 更新headView的size     
  224.                 if (state == PULL_To_REFRESH) {   
  225.                     int topPadding = (int)((-1 * headContentHeight + (tempY - startY)));  
  226.                     headView.setPadding(headView.getPaddingLeft(), topPadding, headView.getPaddingRight(), headView.getPaddingBottom());     
  227.                     headView.invalidate();    
  228.                     //System.out.println("当前-下拉刷新PULL_To_REFRESH-TopPad:"+topPadding);  
  229.                 }    
  230.     
  231.                 // 更新headView的paddingTop     
  232.                 if (state == RELEASE_To_REFRESH) {    
  233.                     int topPadding = (int)((tempY - startY - headContentHeight));  
  234.                     headView.setPadding(headView.getPaddingLeft(), topPadding, headView.getPaddingRight(), headView.getPaddingBottom());      
  235.                     headView.invalidate();    
  236.                     //System.out.println("当前-释放刷新RELEASE_To_REFRESH-TopPad:"+topPadding);  
  237.                 }    
  238.             }    
  239.             break;    
  240.         }    
  241.         return super.onTouchEvent(event);    
  242.     }    
  243.     
  244.     // 当状态改变时候,调用该方法,以更新界面     
  245.     private void changeHeaderViewByState() {    
  246.         switch (state) {    
  247.         case RELEASE_To_REFRESH:    
  248.               
  249.             arrowImageView.setVisibility(View.VISIBLE);    
  250.             progressBar.setVisibility(View.GONE);    
  251.             tipsTextview.setVisibility(View.VISIBLE);    
  252.             lastUpdatedTextView.setVisibility(View.VISIBLE);    
  253.     
  254.             arrowImageView.clearAnimation();    
  255.             arrowImageView.startAnimation(animation);    
  256.     
  257.             tipsTextview.setText(R.string.pull_to_refresh_release_label);    
  258.     
  259.             //Log.v(TAG, "当前状态,松开刷新");    
  260.             break;    
  261.         case PULL_To_REFRESH:  
  262.               
  263.             progressBar.setVisibility(View.GONE);    
  264.             tipsTextview.setVisibility(View.VISIBLE);    
  265.             lastUpdatedTextView.setVisibility(View.VISIBLE);    
  266.             arrowImageView.clearAnimation();    
  267.             arrowImageView.setVisibility(View.VISIBLE);    
  268.             if (isBack) {    
  269.                 isBack = false;    
  270.                 arrowImageView.clearAnimation();    
  271.                 arrowImageView.startAnimation(reverseAnimation);    
  272.             }   
  273.             tipsTextview.setText(R.string.pull_to_refresh_pull_label);    
  274.   
  275.             //Log.v(TAG, "当前状态,下拉刷新");    
  276.             break;    
  277.     
  278.         case REFRESHING:     
  279.             //System.out.println("刷新REFRESHING-TopPad:"+headContentOriginalTopPadding);  
  280.             headView.setPadding(headView.getPaddingLeft(), headContentOriginalTopPadding, headView.getPaddingRight(), headView.getPaddingBottom());     
  281.             headView.invalidate();    
  282.     
  283.             progressBar.setVisibility(View.VISIBLE);    
  284.             arrowImageView.clearAnimation();    
  285.             arrowImageView.setVisibility(View.GONE);    
  286.             tipsTextview.setText(R.string.pull_to_refresh_refreshing_label);    
  287.             lastUpdatedTextView.setVisibility(View.GONE);    
  288.     
  289.             //Log.v(TAG, "当前状态,正在刷新...");    
  290.             break;    
  291.         case DONE:    
  292.             //System.out.println("完成DONE-TopPad:"+(-1 * headContentHeight));  
  293.             headView.setPadding(headView.getPaddingLeft(), -1 * headContentHeight, headView.getPaddingRight(), headView.getPaddingBottom());    
  294.             headView.invalidate();    
  295.     
  296.             progressBar.setVisibility(View.GONE);    
  297.             arrowImageView.clearAnimation();    
  298.             // 此处更换图标     
  299.             arrowImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow);    
  300.     
  301.             tipsTextview.setText(R.string.pull_to_refresh_pull_label);    
  302.             lastUpdatedTextView.setVisibility(View.VISIBLE);    
  303.     
  304.             //Log.v(TAG, "当前状态,done");    
  305.             break;    
  306.         }    
  307.     }    
  308.     
  309.     //点击刷新  
  310.     public void clickRefresh() {  
  311.         setSelection(0);  
  312.         state = REFRESHING;    
  313.         changeHeaderViewByState();    
  314.         onRefresh();   
  315.     }  
  316.       
  317.     public void setOnRefreshListener(OnRefreshListener refreshListener) {    
  318.         this.refreshListener = refreshListener;    
  319.     }    
  320.     
  321.     public interface OnRefreshListener {    
  322.         public void onRefresh();    
  323.     }    
  324.     
  325.     public void onRefreshComplete(String update) {    
  326.         lastUpdatedTextView.setText(update);    
  327.         onRefreshComplete();  
  328.     }   
  329.       
  330.     public void onRefreshComplete() {    
  331.         state = DONE;    
  332.         changeHeaderViewByState();    
  333.     }    
  334.     
  335.     private void onRefresh() {    
  336.         if (refreshListener != null) {    
  337.             refreshListener.onRefresh();    
  338.         }    
  339.     }    
  340.     
  341.     // 计算headView的width及height值    
  342.     private void measureView(View child) {    
  343.         ViewGroup.LayoutParams p = child.getLayoutParams();    
  344.         if (p == null) {    
  345.             p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,    
  346.                     ViewGroup.LayoutParams.WRAP_CONTENT);    
  347.         }    
  348.         int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);    
  349.         int lpHeight = p.height;    
  350.         int childHeightSpec;    
  351.         if (lpHeight > 0) {    
  352.             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,    
  353.                     MeasureSpec.EXACTLY);    
  354.         } else {    
  355.             childHeightSpec = MeasureSpec.makeMeasureSpec(0,    
  356.                     MeasureSpec.UNSPECIFIED);    
  357.         }    
  358.         child.measure(childWidthSpec, childHeightSpec);    
  359.     }    
  360.         
  361. }  


另外一种实现方式:

http://blog.csdn.net/sinyu890807/article/details/9255575

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Android 实现 dialog 的 3D 翻转
ListView下拉刷新,上拉自动加载更多
利用RotateAnimation旋转图片的问题 - 移动平台 / Android
ViewPager + HorizontalScrollView 实现可滚动的标签栏
Android自定义View仿百度加载效果
android 美化zxing二维码扫描框
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服