Android ListView自动加载 Android ListView pull up to refresh.

http://www.iteye.com/topic/1116292


在上一个一个博客中介绍了android的UI组件,其中就包括了一个android-pulltorefresh组件。 

https://github.com/johannilsson/android-pulltorefresh 

这个组件是用在twitter微博中的, 往下拉列表的话, 顶部会自动load, 而且有反弹的效果,非常cool。 但是它的自动load顶部的内部, 我现在需要拖拉listview到最后的时候load。这个组件不知道方向的选择, 所以自己就动手改了下,实现从底部load。 (今天发现新浪微博也实现了同样的功能。)  附件是源码。 

com.markupartist.android.widget.PullToRefreshListView 

Java代码   收藏代码
  1. package com.markupartist.android.widget;  
  2.   
  3.   
  4. import java.lang.reflect.InvocationTargetException;  
  5. import java.lang.reflect.Method;  
  6.   
  7. import android.content.Context;  
  8. import android.util.AttributeSet;  
  9. import android.util.Log;  
  10. import android.view.LayoutInflater;  
  11. import android.view.MotionEvent;  
  12. import android.view.View;  
  13. import android.view.ViewGroup;  
  14. import android.view.animation.LinearInterpolator;  
  15. import android.view.animation.RotateAnimation;  
  16. import android.widget.AbsListView;  
  17. import android.widget.ImageView;  
  18. import android.widget.RelativeLayout;  
  19. import android.widget.ListAdapter;  
  20. import android.widget.ListView;  
  21. import android.widget.ProgressBar;  
  22. import android.widget.TextView;  
  23. import android.widget.AbsListView.OnScrollListener;  
  24.   
  25. import com.markupartist.android.widget.pulltorefresh.R;  
  26.   
  27. public class PullToRefreshListView extends ListView implements OnScrollListener {  
  28.   
  29.     private static final int TAP_TO_REFRESH = 1;  
  30.     private static final int PULL_TO_REFRESH = 2;  
  31.     private static final int RELEASE_TO_REFRESH = 3;  
  32.     private static final int REFRESHING = 4;  
  33.   
  34.     private static final String TAG = "PullToRefreshListView";  
  35.   
  36.     private OnRefreshListener mOnRefreshListener;  
  37.   
  38.     /** 
  39.      * Listener that will receive notifications every time the list scrolls. 
  40.      */  
  41.     private OnScrollListener mOnScrollListener;  
  42.     private LayoutInflater mInflater;  
  43.   
  44.     private RelativeLayout mRefreshView;  
  45.     private TextView mRefreshViewText;  
  46.     private ImageView mRefreshViewImage;  
  47.     private ProgressBar mRefreshViewProgress;  
  48.     private TextView mRefreshViewLastUpdated;  
  49.   
  50.     private int mCurrentScrollState;  
  51.     private int mRefreshState;  
  52.   
  53.     private RotateAnimation mFlipAnimation;  
  54.     private RotateAnimation mReverseFlipAnimation;  
  55.   
  56.     private int mRefreshViewHeight;  
  57.     private int mRefreshOriginalTopPadding;  
  58.     private int mRefreshOriginalBottomPadding;  
  59.     private int mLastMotionY;  
  60.   
  61.     public PullToRefreshListView(Context context) {  
  62.         super(context);  
  63.         init(context);  
  64.     }  
  65.   
  66.     public PullToRefreshListView(Context context, AttributeSet attrs) {  
  67.         super(context, attrs);  
  68.         init(context);  
  69.     }  
  70.   
  71.     public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {  
  72.         super(context, attrs, defStyle);  
  73.         init(context);  
  74.     }  
  75.   
  76.     private void init(Context context) {  
  77.         // Load all of the animations we need in code rather than through XML  
  78.         mFlipAnimation = new RotateAnimation(0, -180,  
  79.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f,  
  80.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f);  
  81.         mFlipAnimation.setInterpolator(new LinearInterpolator());  
  82.         mFlipAnimation.setDuration(250);  
  83.         mFlipAnimation.setFillAfter(true);  
  84.         mReverseFlipAnimation = new RotateAnimation(-1800,  
  85.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f,  
  86.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f);  
  87.         mReverseFlipAnimation.setInterpolator(new LinearInterpolator());  
  88.         mReverseFlipAnimation.setDuration(250);  
  89.         mReverseFlipAnimation.setFillAfter(true);  
  90.   
  91.         mInflater = (LayoutInflater) context.getSystemService(  
  92.                 Context.LAYOUT_INFLATER_SERVICE);  
  93.   
  94.         mRefreshView = (RelativeLayout) mInflater.inflate(  
  95.                 R.layout.pull_to_refresh_header, thisfalse);  
  96.         mRefreshViewText =  
  97.             (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);  
  98.         mRefreshViewImage =  
  99.             (ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);  
  100.         mRefreshViewProgress =  
  101.             (ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);  
  102.         mRefreshViewLastUpdated =  
  103.             (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);  
  104.   
  105.         mRefreshViewImage.setMinimumHeight(50);  
  106.         mRefreshView.setOnClickListener(new OnClickRefreshListener());  
  107.         mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();  
  108.         mRefreshOriginalBottomPadding = mRefreshView.getPaddingBottom();  
  109.   
  110.         mRefreshState = TAP_TO_REFRESH;  
  111.   
  112. //        addHeaderView(mRefreshView);  
  113.         addFooterView(mRefreshView);  
  114.   
  115.         super.setOnScrollListener(this);  
  116.   
  117.         measureView(mRefreshView);  
  118.         mRefreshViewHeight = mRefreshView.getMeasuredHeight();  
  119.     }  
  120.   
  121.     @Override  
  122.     protected void onAttachedToWindow() {  
  123.         //setSelection(1);  
  124.     }  
  125.   
  126.     @Override  
  127.     public void setAdapter(ListAdapter adapter) {  
  128.         super.setAdapter(adapter);  
  129.   
  130.         //setSelection(1);  
  131.     }  
  132.   
  133.     /** 
  134.      * Set the listener that will receive notifications every time the list 
  135.      * scrolls. 
  136.      *  
  137.      * @param l The scroll listener.  
  138.      */  
  139.     @Override  
  140.     public void setOnScrollListener(AbsListView.OnScrollListener l) {  
  141.         mOnScrollListener = l;  
  142.     }  
  143.   
  144.     /** 
  145.      * Register a callback to be invoked when this list should be refreshed. 
  146.      *  
  147.      * @param onRefreshListener The callback to run. 
  148.      */  
  149.     public void setOnRefreshListener(OnRefreshListener onRefreshListener) {  
  150.         mOnRefreshListener = onRefreshListener;  
  151.     }  
  152.   
  153.     /** 
  154.      * Set a text to represent when the list was last updated.  
  155.      * @param lastUpdated Last updated at. 
  156.      */  
  157.     public void setLastUpdated(CharSequence lastUpdated) {  
  158.         if (lastUpdated != null) {  
  159.             mRefreshViewLastUpdated.setVisibility(View.VISIBLE);  
  160.             mRefreshViewLastUpdated.setText(lastUpdated);  
  161.         } else {  
  162.             mRefreshViewLastUpdated.setVisibility(View.GONE);  
  163.         }  
  164.     }  
  165.   
  166.     @Override  
  167.     public boolean onTouchEvent(MotionEvent event) {  
  168.         final int y = (int) event.getY();  
  169.         Log.i("PullToRefreshListView""Height:" + getMeasuredHeight());  
  170.         Log.i("PullToRefreshListView""MotionEvent:" + event.getAction());  
  171.         Log.i("PullToRefreshListView""mRefreshState:" + mRefreshState);  
  172.         Log.i("PullToRefreshListView""FirstVisiblePosition:" + getFirstVisiblePosition());  
  173.         Log.i("PullToRefreshListView""LastVisiblePosition:" + getLastVisiblePosition());  
  174.         Log.i("PullToRefreshListView""ChildCount:" + getAdapter().getCount());  
  175.         Log.i("PullToRefreshListView""RefreshViewBottom:" + mRefreshView.getBottom());  
  176.         Log.i("PullToRefreshListView""RefreshViewTop:" + mRefreshView.getTop());  
  177.         Log.i("PullToRefreshListView""mRefreshViewHeight:" + mRefreshViewHeight);  
  178.         Log.i("PullToRefreshListView""  ");  
  179.         Log.i("PullToRefreshListView""  ");  
  180.         Log.i("PullToRefreshListView""  ");  
  181.   
  182.   
  183.         switch (event.getAction()) {  
  184.             case MotionEvent.ACTION_UP:  
  185.   
  186.                 if (!isVerticalScrollBarEnabled()) {  
  187.                     setVerticalScrollBarEnabled(true);  
  188.                 }  
  189.                 if (getLastVisiblePosition() == getAdapter().getCount() - 1  
  190.                         && mRefreshState != REFRESHING) {  
  191.                     if ((  
  192.                             mRefreshView.getTop() <= getMeasuredHeight() - mRefreshViewHeight)  
  193.                             && mRefreshState == RELEASE_TO_REFRESH) {  
  194. //                        Log.i("PullToRefreshListView", "Fire...");  
  195. //                        Log.i("PullToRefreshListView", "  ");  
  196. //                        Log.i("PullToRefreshListView", "  ");  
  197. //                        Log.i("PullToRefreshListView", "  ");  
  198.                         // Initiate the refresh  
  199.                         mRefreshState = REFRESHING;  
  200.                         prepareForRefresh();  
  201.                         onRefresh();  
  202.                     } else if (  
  203.                             mRefreshView.getTop() > getMeasuredHeight() - mRefreshViewHeight) {  
  204.                         // Abort refresh and scroll down below the refresh view  
  205.                         resetHeader();  
  206.                         //setSelection(1);  
  207. //                        Log.v("PPMacbook", "pi:" + (getSelectedItemPosition() - 1));  
  208. //                        setSelectionAfterHeaderView();  
  209. //                        setSelection(getSelectedItemPosition() - 1);  
  210. //                        System.out.println("PPMacbook:" + (getFirstVisiblePosition() - 1));  
  211.                         setSelection((getFirstVisiblePosition() - 1));  
  212.                     }  
  213.                 }  
  214.                 break;  
  215.   
  216.   
  217.             case MotionEvent.ACTION_DOWN:  
  218.                 mLastMotionY = y;  
  219.                 break;  
  220.   
  221.             case MotionEvent.ACTION_MOVE:  
  222.                 applyHeaderPadding(event);  
  223.                 break;  
  224.         }  
  225.         return super.onTouchEvent(event);  
  226.     }  
  227.   
  228.     private void applyHeaderPadding(MotionEvent ev) {  
  229.         final int historySize = ev.getHistorySize();  
  230.   
  231.         // Workaround for getPointerCount() which is unavailable in 1.5  
  232.         // (it's always 1 in 1.5)  
  233.         int pointerCount = 1;  
  234.         try {  
  235.             Method method = MotionEvent.class.getMethod("getPointerCount");  
  236.             pointerCount = (Integer)method.invoke(ev);  
  237.         } catch (NoSuchMethodException e) {  
  238.             pointerCount = 1;  
  239.         } catch (IllegalArgumentException e) {  
  240.             throw e;  
  241.         } catch (IllegalAccessException e) {  
  242.             System.err.println("unexpected " + e);  
  243.         } catch (InvocationTargetException e) {  
  244.             System.err.println("unexpected " + e);  
  245.         }  
  246.   
  247. //        Log.i("PullToRefreshListView", "historySize:" + historySize);  
  248. //        Log.i("PullToRefreshListView", "pointerCount:" + pointerCount);  
  249. //        Log.i("PullToRefreshListView", "  ");  
  250. //        Log.i("PullToRefreshListView", "  ");  
  251. //        Log.i("PullToRefreshListView", "  ");  
  252.   
  253.         for (int h = 0; h < historySize; h++) {  
  254.             for (int p = 0; p < pointerCount; p++) {  
  255.                 if (mRefreshState == RELEASE_TO_REFRESH) {  
  256.                     if (isVerticalFadingEdgeEnabled()) {  
  257.                         setVerticalScrollBarEnabled(false);  
  258.                     }  
  259.   
  260.                     int historicalY = 0;  
  261.                     try {  
  262.                         // For Android > 2.0  
  263.                         Method method = MotionEvent.class.getMethod(  
  264.                                 "getHistoricalY", Integer.TYPE, Integer.TYPE);  
  265.                         historicalY = ((Float) method.invoke(ev, p, h)).intValue();  
  266.                     } catch (NoSuchMethodException e) {  
  267.                         // For Android < 2.0  
  268.                         historicalY = (int) (ev.getHistoricalY(h));  
  269.                     } catch (IllegalArgumentException e) {  
  270.                         throw e;  
  271.                     } catch (IllegalAccessException e) {  
  272.                         System.err.println("unexpected " + e);  
  273.                     } catch (InvocationTargetException e) {  
  274.                         System.err.println("unexpected " + e);  
  275.                     }  
  276.   
  277.                     // Calculate the padding to apply, we divide by 1.7 to  
  278.                     // simulate a more resistant effect during pull.  
  279.                     int topPadding = (int) (((historicalY + mLastMotionY)  
  280.                             + mRefreshViewHeight) / 1.7);  
  281.   
  282.                     mRefreshView.setPadding(  
  283.                             mRefreshView.getPaddingLeft(),  
  284.                             mRefreshView.getPaddingTop(),  
  285.                             mRefreshView.getPaddingRight(),  
  286.                             topPadding);  
  287.                 }  
  288.             }  
  289.         }  
  290.     }  
  291.   
  292.     /** 
  293.      * Sets the header padding back to original size. 
  294.      */  
  295.     private void resetHeaderPadding() {  
  296.         mRefreshView.setPadding(  
  297.                 mRefreshView.getPaddingLeft(),  
  298.                 mRefreshView.getPaddingTop(),  
  299.                 mRefreshView.getPaddingRight(),  
  300.                 mRefreshOriginalBottomPadding);  
  301.     }  
  302.   
  303.     /** 
  304.      * Resets the header to the original state. 
  305.      */  
  306.     private void resetHeader() {  
  307.         if (mRefreshState != TAP_TO_REFRESH) {  
  308.             mRefreshState = TAP_TO_REFRESH;  
  309.   
  310.             resetHeaderPadding();  
  311.   
  312.             // Set refresh view text to the pull label  
  313.             mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);  
  314.             // Replace refresh drawable with arrow drawable  
  315.             mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);  
  316.             // Clear the full rotation animation  
  317.             mRefreshViewImage.clearAnimation();  
  318.             // Hide progress bar and arrow.  
  319.             mRefreshViewImage.setVisibility(View.GONE);  
  320.             mRefreshViewProgress.setVisibility(View.GONE);  
  321.         }  
  322.     }  
  323.   
  324.     private void measureView(View child) {  
  325.         ViewGroup.LayoutParams p = child.getLayoutParams();  
  326.         if (p == null) {  
  327.             p = new ViewGroup.LayoutParams(  
  328.                     ViewGroup.LayoutParams.FILL_PARENT,  
  329.                     ViewGroup.LayoutParams.WRAP_CONTENT);  
  330.         }  
  331.   
  332.         int childWidthSpec = ViewGroup.getChildMeasureSpec(0,  
  333.                 0 + 0, p.width);  
  334.         int lpHeight = p.height;  
  335.         int childHeightSpec;  
  336.         if (lpHeight > 0) {  
  337.             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);  
  338.         } else {  
  339.             childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);  
  340.         }  
  341.         child.measure(childWidthSpec, childHeightSpec);  
  342.     }  
  343.   
  344.     @Override  
  345.     public void onScroll(AbsListView view, int firstVisibleItem,  
  346.             int visibleItemCount, int totalItemCount) {  
  347. //        Log.i("PullToRefreshListView", "firstVisibleItem:" + firstVisibleItem);  
  348. //        Log.i("PullToRefreshListView", "visibleItemCount:" + visibleItemCount);  
  349. //        Log.i("PullToRefreshListView", "totalItemCount:" + totalItemCount);  
  350. //        Log.i("PullToRefreshListView", "");  
  351. //        Log.i("PullToRefreshListView", "");  
  352. //        Log.i("PullToRefreshListView", "");  
  353.         // When the refresh view is completely visible, change the text to say  
  354.         // "Release to refresh..." and flip the arrow drawable.  
  355.         if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL  
  356.                 && mRefreshState != REFRESHING) {  
  357.             if (firstVisibleItem + visibleItemCount == totalItemCount) {  
  358.                 mRefreshViewImage.setVisibility(View.VISIBLE);  
  359.                 if ((  
  360.                         mRefreshView.getTop() <= getMeasuredHeight() - mRefreshViewHeight)  
  361.                         && mRefreshState != RELEASE_TO_REFRESH) {  
  362.                     mRefreshViewText.setText(R.string.pull_to_refresh_release_label);  
  363.                     mRefreshViewImage.clearAnimation();  
  364.                     mRefreshViewImage.startAnimation(mFlipAnimation);  
  365.                     mRefreshState = RELEASE_TO_REFRESH;  
  366.                 } else if (  
  367.                         mRefreshView.getTop() >getMeasuredHeight() - 20 - mRefreshViewHeight  
  368.                         && mRefreshState != PULL_TO_REFRESH) {  
  369.                     mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);  
  370.                     if (mRefreshState != TAP_TO_REFRESH) {  
  371.                         mRefreshViewImage.clearAnimation();  
  372.                         mRefreshViewImage.startAnimation(mReverseFlipAnimation);  
  373.                     }  
  374.                     mRefreshState = PULL_TO_REFRESH;  
  375.                 }  
  376.             } else {  
  377.                 mRefreshViewImage.setVisibility(View.GONE);  
  378.                 resetHeader();  
  379.             }  
  380.         } else if (mCurrentScrollState == SCROLL_STATE_FLING  
  381.                 && firstVisibleItem + visibleItemCount == totalItemCount  
  382.                 && mRefreshState != REFRESHING) {  
  383.             //setSelection(1);  
  384. //            Log.i("PullToRefreshListView", "Selection:" + (totalItemCount - visibleItemCount));  
  385.             setSelection(getSelectedItemPosition() - 2);  
  386. //  
  387.             setSelection((getFirstVisiblePosition() - 1));  
  388.         }  
  389.   
  390.         if (mOnScrollListener != null) {  
  391.             mOnScrollListener.onScroll(view, firstVisibleItem,  
  392.                     visibleItemCount, totalItemCount);  
  393.         }  
  394.     }  
  395.   
  396.     @Override  
  397.     public void onScrollStateChanged(AbsListView view, int scrollState) {  
  398.         mCurrentScrollState = scrollState;  
  399.   
  400.         if (mOnScrollListener != null) {  
  401.             mOnScrollListener.onScrollStateChanged(view, scrollState);  
  402.         }  
  403.     }  
  404.   
  405.     public void prepareForRefresh() {  
  406.         resetHeaderPadding();  
  407.   
  408.         mRefreshViewImage.setVisibility(View.GONE);  
  409.         // We need this hack, otherwise it will keep the previous drawable.  
  410.         mRefreshViewImage.setImageDrawable(null);  
  411.         mRefreshViewProgress.setVisibility(View.VISIBLE);  
  412.   
  413.         // Set refresh view text to the refreshing label  
  414.         mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);  
  415.   
  416.         mRefreshState = REFRESHING;  
  417.     }  
  418.   
  419.     public void onRefresh() {  
  420.         Log.d(TAG, "onRefresh");  
  421.   
  422.         if (mOnRefreshListener != null) {  
  423.             mOnRefreshListener.onRefresh();  
  424.         }  
  425.     }  
  426.   
  427.     /** 
  428.      * Resets the list to a normal state after a refresh. 
  429.      * @param lastUpdated Last updated at. 
  430.      */  
  431.     public void onRefreshComplete(CharSequence lastUpdated) {  
  432.         setLastUpdated(lastUpdated);  
  433.         onRefreshComplete();  
  434.     }  
  435.   
  436.     /** 
  437.      * Resets the list to a normal state after a refresh. 
  438.      */  
  439.     public void onRefreshComplete() {          
  440.         Log.d(TAG, "onRefreshComplete");  
  441.   
  442.         resetHeader();  
  443.   
  444.         // If refresh view is visible when loading completes, scroll down to  
  445.         // the next item.  
  446.         if (mRefreshView.getBottom() > 0) {  
  447.             invalidateViews();  
  448.             //setSelection(1);  
  449.         }  
  450.     }  
  451.   
  452.     /** 
  453.      * Invoked when the refresh view is clicked on. This is mainly used when 
  454.      * there's only a few items in the list and it's not possible to drag the 
  455.      * list. 
  456.      */  
  457.     private class OnClickRefreshListener implements OnClickListener {  
  458.   
  459.         @Override  
  460.         public void onClick(View v) {  
  461.             if (mRefreshState != REFRESHING) {  
  462.                 prepareForRefresh();  
  463.                 onRefresh();  
  464.             }  
  465.         }  
  466.   
  467.     }  
  468.   
  469.     /** 
  470.      * Interface definition for a callback to be invoked when list should be 
  471.      * refreshed. 
  472.      */  
  473.     public interface OnRefreshListener {  
  474.         /** 
  475.          * Called when the list should be refreshed. 
  476.          * <p> 
  477.          * A call to {@link PullToRefreshListView #onRefreshComplete()} is 
  478.          * expected to indicate that the refresh has completed. 
  479.          */  
  480.         public void onRefresh();  
  481.     }  
  482. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值