您当前的位置: 首页 >  android

xiangzhihong8

暂无认证

  • 1浏览

    0关注

    1324博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

android上拉下拉加载更多数据

xiangzhihong8 发布时间:2014-02-16 23:38:15 ,浏览量:1

最近项目中用到了ListView的下拉刷新的功能,总结了一下前辈们的代码,单独抽取出来写了一个demo作为示例。

效果图

下拉刷新:

加载更多:

CustomListView.java

[java] view plain copy
  1. package com.example.uitest.view;  
  2.   
  3. import java.util.Date;  
  4. import com.example.uitest.R;  
  5. import android.content.Context;  
  6. import android.util.AttributeSet;  
  7. import android.util.Log;  
  8. import android.view.LayoutInflater;  
  9. import android.view.MotionEvent;  
  10. import android.view.View;  
  11. import android.view.ViewGroup;  
  12. import android.view.animation.LinearInterpolator;  
  13. import android.view.animation.RotateAnimation;  
  14. import android.widget.AbsListView;  
  15. import android.widget.AbsListView.OnScrollListener;  
  16. import android.widget.BaseAdapter;  
  17. import android.widget.ImageView;  
  18. import android.widget.LinearLayout;  
  19. import android.widget.ListView;  
  20. import android.widget.ProgressBar;  
  21. import android.widget.TextView;  
  22.   
  23. /** 
  24.  * ListView下拉刷新 
  25.  * 
  26.  */  
  27. public class CustomListView extends ListView implements OnScrollListener {  
  28.   
  29.     private final static int RELEASE_To_REFRESH = 0;  
  30.     private final static int PULL_To_REFRESH = 1;  
  31.     private final static int REFRESHING = 2;  
  32.     private final static int DONE = 3;  
  33.     private final static int LOADING = 4;  
  34.   
  35.     // 实际的padding的距离与界面上偏移距离的比例  
  36.     private final static int RATIO = 3;  
  37.   
  38.     private LayoutInflater inflater;  
  39.   
  40.     private LinearLayout headView;  
  41.   
  42.     private TextView tipsTextview;  
  43.     private TextView lastUpdatedTextView;  
  44.     private ImageView arrowImageView;  
  45.     private ProgressBar progressBar;  
  46.   
  47.   
  48.     private RotateAnimation animation;  
  49.     private RotateAnimation reverseAnimation;  
  50.   
  51.     // 用于保证startY的值在一个完整的touch事件中只被记录一次  
  52.     private boolean isRecored;  
  53.   
  54.     private int headContentWidth;  
  55.     private int headContentHeight;  
  56.   
  57.     private int startY;  
  58.     private int firstItemIndex;  
  59.   
  60.     private int state;  
  61.   
  62.     private boolean isBack;  
  63.   
  64.     private OnRefreshListener refreshListener;  
  65.     private OnLoadListener loadListener;  
  66.   
  67.     private boolean isRefreshable;  
  68.       
  69.     private ProgressBar moreProgressBar;  
  70.     private TextView loadMoreView;  
  71.     private View moreView;  
  72.   
  73.     public CustomListView(Context context) {  
  74.         super(context);  
  75.         init(context);  
  76.     }  
  77.   
  78.     public CustomListView(Context context, AttributeSet attrs) {  
  79.         super(context, attrs);  
  80.         init(context);  
  81.     }  
  82.   
  83.     private void init(Context context) {  
  84.         setCacheColorHint(context.getResources().getColor(R.color.transparent));  
  85.         inflater = LayoutInflater.from(context);  
  86.   
  87.         headView = (LinearLayout) inflater.inflate(R.layout.head, null);  
  88.   
  89.         arrowImageView = (ImageView) headView.findViewById(R.id.head_arrowImageView);  
  90.         arrowImageView.setMinimumWidth(70);  
  91.         arrowImageView.setMinimumHeight(50);  
  92.         progressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar);  
  93.         tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);  
  94.         lastUpdatedTextView = (TextView) headView.findViewById(R.id.head_lastUpdatedTextView);  
  95.   
  96.         measureView(headView);  
  97.         headContentHeight = headView.getMeasuredHeight();  
  98.         headContentWidth = headView.getMeasuredWidth();  
  99.   
  100.         headView.setPadding(0, -1 * headContentHeight, 0, 0);  
  101.         headView.invalidate();  
  102.   
  103.         Log.v("size", "width:" + headContentWidth + " height:" + headContentHeight);  
  104.   
  105.         addHeaderView(headView, null, false);  
  106.         setOnScrollListener(this);  
  107.   
  108.         animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);  
  109.         animation.setInterpolator(new LinearInterpolator());  
  110.         animation.setDuration(250);  
  111.         animation.setFillAfter(true);  
  112.   
  113.         reverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);  
  114.         reverseAnimation.setInterpolator(new LinearInterpolator());  
  115.         reverseAnimation.setDuration(200);  
  116.         reverseAnimation.setFillAfter(true);  
  117.   
  118.         state = DONE;  
  119.         isRefreshable = false;  
  120.           
  121.         moreView = LayoutInflater.from(context).inflate(R.layout.listfooter_more, null);  
  122.         moreView.setVisibility(View.VISIBLE);  
  123.         moreProgressBar = (ProgressBar) moreView.findViewById(R.id.pull_to_refresh_progress);  
  124.         loadMoreView = (TextView) moreView.findViewById(R.id.load_more);  
  125.         moreView.setOnClickListener(new View.OnClickListener() {  
  126.               
  127.             @Override  
  128.             public void onClick(View v) {  
  129.                 onLoad();  
  130.             }  
  131.         });  
  132.         addFooterView(moreView);  
  133.     }  
  134.   
  135.     public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2, int arg3) {  
  136.         firstItemIndex = firstVisiableItem;  
  137.     }  
  138.   
  139.     public void onScrollStateChanged(AbsListView arg0, int arg1) {  
  140.           
  141.     }  
  142.   
  143.     public boolean onTouchEvent(MotionEvent event) {  
  144.   
  145.         if (isRefreshable) {  
  146.             switch (event.getAction()) {  
  147.             case MotionEvent.ACTION_DOWN:  
  148.                 if (firstItemIndex == 0 && !isRecored) {  
  149.                     isRecored = true;  
  150.                     startY = (int) event.getY();  
  151.                 }  
  152.                 break;  
  153.   
  154.             case MotionEvent.ACTION_UP:  
  155.   
  156.                 if (state != REFRESHING && state != LOADING) {  
  157.                     if (state == DONE) {  
  158.                           
  159.                     }  
  160.                     if (state == PULL_To_REFRESH) {  
  161.                         state = DONE;  
  162.                         changeHeaderViewByState();  
  163.                     }  
  164.                     if (state == RELEASE_To_REFRESH) {  
  165.                         state = REFRESHING;  
  166.                         changeHeaderViewByState();  
  167.                         onRefresh();  
  168.                     }  
  169.                 }  
  170.   
  171.                 isRecored = false;  
  172.                 isBack = false;  
  173.   
  174.                 break;  
  175.   
  176.             case MotionEvent.ACTION_MOVE:  
  177.                 int tempY = (int) event.getY();  
  178.   
  179.                 if (!isRecored && firstItemIndex == 0) {  
  180.                     isRecored = true;  
  181.                     startY = tempY;  
  182.                 }  
  183.   
  184.                 if (state != REFRESHING && isRecored && state != LOADING) {  
  185.   
  186.                     // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动  
  187.                     // 可以松手去刷新了  
  188.                     if (state == RELEASE_To_REFRESH) {  
  189.   
  190.                         setSelection(0);  
  191.   
  192.                         // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步  
  193.                         if (((tempY - startY) / RATIO  0) {  
  194.                             state = PULL_To_REFRESH;  
  195.                             changeHeaderViewByState();  
  196.                         }  
  197.                         // 一下子推到顶了  
  198.                         else if (tempY - startY = headContentHeight) {  
  199.                             state = RELEASE_To_REFRESH;  
  200.                             isBack = true;  
  201.                             changeHeaderViewByState();  
  202.                         }  
  203.                         else if (tempY - startY  0) {  
  204.                             state = PULL_To_REFRESH;  
  205.                             changeHeaderViewByState();  
  206.                         }  
  207.                     }  
  208.   
  209.                     if (state == PULL_To_REFRESH) {  
  210.                         headView.setPadding(0, -1 * headContentHeight + (tempY - startY) / RATIO, 0, 0);  
  211.   
  212.                     }  
  213.   
  214.                     if (state == RELEASE_To_REFRESH) {  
  215.                         headView.setPadding(0, (tempY - startY) / RATIO - headContentHeight, 0, 0);  
  216.                     }  
  217.   
  218.                 }  
  219.   
  220.                 break;  
  221.             }  
  222.         }  
  223.   
  224.         return super.onTouchEvent(event);  
  225.     }  
  226.   
  227.     // 当状态改变时候,调用该方法,以更新界面  
  228.     private void changeHeaderViewByState() {  
  229.         switch (state) {  
  230.         case RELEASE_To_REFRESH:  
  231.             arrowImageView.setVisibility(View.VISIBLE);  
  232.             progressBar.setVisibility(View.GONE);  
  233.             tipsTextview.setVisibility(View.VISIBLE);  
  234.             lastUpdatedTextView.setVisibility(View.VISIBLE);  
  235.   
  236.             arrowImageView.clearAnimation();  
  237.             arrowImageView.startAnimation(animation);  
  238.             tipsTextview.setText("松开刷新");  
  239.   
  240.             break;  
  241.         case PULL_To_REFRESH:  
  242.             progressBar.setVisibility(View.GONE);  
  243.             tipsTextview.setVisibility(View.VISIBLE);  
  244.             lastUpdatedTextView.setVisibility(View.VISIBLE);  
  245.             arrowImageView.clearAnimation();  
  246.             arrowImageView.setVisibility(View.VISIBLE);  
  247.             // 是由RELEASE_To_REFRESH状态转变来的  
  248.             if (isBack) {  
  249.                 isBack = false;  
  250.                 arrowImageView.clearAnimation();  
  251.                 arrowImageView.startAnimation(reverseAnimation);  
  252.   
  253.                 tipsTextview.setText("下拉刷新");  
  254.             } else {  
  255.                 tipsTextview.setText("下拉刷新");  
  256.             }  
  257.             break;  
  258.   
  259.         case REFRESHING:  
  260.             headView.setPadding(0, 0, 0, 0);  
  261.             progressBar.setVisibility(View.VISIBLE);  
  262.             arrowImageView.clearAnimation();  
  263.             arrowImageView.setVisibility(View.GONE);  
  264.             tipsTextview.setText("正在刷新...");  
  265.             lastUpdatedTextView.setVisibility(View.VISIBLE);  
  266.   
  267.             break;  
  268.         case DONE:  
  269.             headView.setPadding(0, -1 * headContentHeight, 0, 0);  
  270.   
  271.             progressBar.setVisibility(View.GONE);  
  272.             arrowImageView.clearAnimation();  
  273.             arrowImageView.setImageResource(R.drawable.arrow);  
  274.             tipsTextview.setText("下拉刷新");  
  275.             lastUpdatedTextView.setVisibility(View.VISIBLE);  
  276.   
  277.             break;  
  278.         }  
  279.     }  
  280.   
  281.     public void setonRefreshListener(OnRefreshListener refreshListener) {  
  282.         this.refreshListener = refreshListener;  
  283.         isRefreshable = true;  
  284.     }  
  285.       
  286.     public void setonLoadListener(OnLoadListener loadListener) {  
  287.         this.loadListener = loadListener;  
  288.     }  
  289.   
  290.     public interface OnRefreshListener {  
  291.         public void onRefresh();  
  292.     }  
  293.       
  294.     public interface OnLoadListener {  
  295.         public void onLoad();  
  296.     }  
  297.   
  298.     @SuppressWarnings("deprecation")  
  299.     public void onRefreshComplete() {  
  300.         state = DONE;  
  301.         lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());  
  302.         changeHeaderViewByState();  
  303.     }  
  304.       
  305.     private void onLoad() {  
  306.         if (loadListener != null) {  
  307.             moreProgressBar.setVisibility(View.VISIBLE);  
  308.             loadMoreView.setText(getContext().getString(R.string.load_more));  
  309.             loadListener.onLoad();  
  310.         }  
  311.     }  
  312.       
  313.     public void onLoadComplete() {  
  314. //      moreView.setVisibility(View.GONE);  
  315.         moreProgressBar.setVisibility(View.GONE);  
  316.         loadMoreView.setText(getContext().getString(R.string.more_data));  
  317.     }  
  318.   
  319.     private void onRefresh() {  
  320.         if (refreshListener != null) {  
  321.             refreshListener.onRefresh();  
  322.         }  
  323.     }  
  324.   
  325.     private void measureView(View child) {  
  326.         ViewGroup.LayoutParams p = child.getLayoutParams();  
  327.         if (p == null) {  
  328.             p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);  
  329.         }  
  330.         int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);  
  331.         int lpHeight = p.height;  
  332.         int childHeightSpec;  
  333.         if (lpHeight > 0) {  
  334.             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);  
  335.         } else {  
  336.             childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);  
  337.         }  
  338.         child.measure(childWidthSpec, childHeightSpec);  
  339.     }  
  340.   
  341.     @SuppressWarnings("deprecation")  
  342.     public void setAdapter(BaseAdapter adapter) {  
  343.         lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());  
  344.         super.setAdapter(adapter);  
  345.     }  
  346.   
  347. }  

在 CustomListView 中有2个回调接口,OnRefreshListener 和 OnLoadListener ,分别对应 下拉和点击加载更多 时候的回调函数。在下拉刷新完成之后要调用 mListView.onRefreshComplete(); 来隐藏掉 头部,调用 mListView.onLoadComplete(); 隐藏掉 底部的加载view。

header.xml

[html] view plain copy
  1.   
  2.   
  3.   
  4.   
  5.   
  6.       
  7.   
  8.       
  9.   
  10.           
  11.   
  12.           
  13.   
  14.               
  15.   
  16.               
  17.   
  18.               
  19.   
  20.               
  21.           
  22.   
  23.           
  24.   
  25.           
  26.   
  27.               
  28.   
  29.               
  30.   
  31.               
  32.   
  33.               
  34.           
  35.       
  36.   
  37.   

listfooter_more.xml
[html] view plain copy
  1.   
  2.   
  3.   
  4.       
  5.       
  6.   
  7.       
  8.       
  9.   
  10.   

MainActivity.java

[java] view plain copy
  1. package com.example.uitest;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.content.Context;  
  8. import android.graphics.BitmapFactory;  
  9. import android.os.Bundle;  
  10. import android.os.Handler;  
  11. import android.util.Log;  
  12. import android.view.LayoutInflater;  
  13. import android.view.Menu;  
  14. import android.view.View;  
  15. import android.view.ViewGroup;  
  16. import android.widget.AdapterView;  
  17. import android.widget.AdapterView.OnItemClickListener;  
  18. import android.widget.BaseAdapter;  
  19. import android.widget.ImageView;  
  20. import android.widget.TextView;  
  21.   
  22. import com.example.uitest.model.AppInfo;  
  23. import com.example.uitest.view.CustomListView;  
  24. import com.example.uitest.view.CustomListView.OnLoadListener;  
  25. import com.example.uitest.view.CustomListView.OnRefreshListener;  
  26.   
  27. public class MainActivity extends Activity {  
  28.       
  29.     private static final String TAG = MainActivity.class.getSimpleName();  
  30.   
  31.     private static final int LOAD_DATA_FINISH = 10;  
  32.   
  33.     private static final int REFRESH_DATA_FINISH = 11;  
  34.       
  35.     private List mList = new ArrayList();  
  36.     private CustomListAdapter mAdapter;  
  37.     private CustomListView mListView;  
  38.     private int count = 10;  
  39.     private Handler handler = new Handler(){  
  40.         public void handleMessage(android.os.Message msg) {  
  41.             switch (msg.what) {  
  42.             case REFRESH_DATA_FINISH:  
  43.                   
  44.                 if(mAdapter!=null){  
  45.                     mAdapter.notifyDataSetChanged();  
  46.                 }  
  47.                 mListView.onRefreshComplete();  //下拉刷新完成  
  48.                 break;  
  49.             case LOAD_DATA_FINISH:  
  50.                 if(mAdapter!=null){  
  51.                     mAdapter.notifyDataSetChanged();  
  52.                 }  
  53.                 mListView.onLoadComplete(); //加载更多完成  
  54.                 break;  
  55.             default:  
  56.                 break;  
  57.             }  
  58.         };  
  59.     };  
  60.       
  61.     @Override  
  62.     protected void onCreate(Bundle savedInstanceState) {  
  63.         super.onCreate(savedInstanceState);  
  64.         setContentView(R.layout.activity_main);  
  65.           
  66.         buildAppData();  
  67.           
  68.         mAdapter = new CustomListAdapter(this);  
  69.         mListView = (CustomListView) findViewById(R.id.mListView);  
  70.         mListView.setAdapter(mAdapter);  
  71.           
  72.         mListView.setonRefreshListener(new OnRefreshListener() {  
  73.               
  74.             @Override  
  75.             public void onRefresh() {  
  76.                 //TODO 下拉刷新  
  77.                 Log.e(TAG, "onRefresh");  
  78.                 loadData(0);  
  79.             }  
  80.         });  
  81.           
  82.         mListView.setonLoadListener(new OnLoadListener() {  
  83.               
  84.             @Override  
  85.             public void onLoad() {  
  86.                 //TODO 加载更多  
  87.                 Log.e(TAG, "onLoad");  
  88.                 loadData(1);  
  89.             }  
  90.         });  
  91.           
  92.         mListView.setOnItemClickListener(new OnItemClickListener() {  
  93.   
  94.             @Override  
  95.             public void onItemClick(AdapterView parent, View view,  
  96.                     int position, long id) {  
  97.   
  98.                 Log.e(TAG, "click position:" + position);  
  99.   
  100.             }  
  101.   
  102.         });  
  103.     }  
  104.       
  105.     public void loadData(final int type){  
  106.         new Thread(){  
  107.             @Override  
  108.             public void run() {  
  109.                   
  110.                 for(int i=count;i  
  111.   
  112.   
  113.       
  114.   
  115.       
  116.   
  117.           
  118.   
  119.           
  120.   
  121.           
  122.       
  123.   
  124.       
  125.   
  126.   

工程下载地址:http://download.csdn.net/detail/fx_sky/5646017

关注
打赏
1482932726
查看更多评论
立即登录/注册

微信扫码登录

0.0407s