项目中用到listview下拉刷新,上拉获取更多,找出之前的代码用,发现下拉刷新不太流畅,在网上搜的代码也是同样的问题,于是用了点时间优化下。下面贴出主要代码,有需要项目的可留下邮箱。

PullToRefreshListView.java文件

  1. public class PullToRefreshListView extends ListView implements OnScrollListener { 
  2.  
  3.     private static final int TAP_TO_REFRESH = 1;     // 初始状态 
  4.     private static final int PULL_TO_REFRESH = 2;    //拉动刷新 
  5.     private static final int RELEASE_TO_REFRESH = 3;  //释放刷新 
  6.     private static final int REFRESHING = 4;    //正在刷新 
  7.  
  8.     private static final String TAG = "PullToRefreshListView"
  9.     //刷新接口 
  10.     private OnRefreshListener mOnRefreshListener; 
  11.     //上拉刷新接口 
  12.     private OnPullUpRefreshListener mOnPullUpRefreshListener; 
  13.     //箭头图片 
  14.     private static  int REFRESHICON = R.drawable.goicon;  
  15.      //listview 滚动监听器 
  16.     private OnScrollListener mOnScrollListener; 
  17.      
  18.     //视图索引器 
  19.     private LayoutInflater mInflater; 
  20.     /** 
  21.      * 头部视图  内容  -- start 
  22.      */ 
  23.     private RelativeLayout mRefreshView; 
  24.     private TextView mRefreshViewText,zhanweiTextView; 
  25.     private ImageView mRefreshViewImage; 
  26.     private ProgressBar mRefreshViewProgress; 
  27.     private TextView mRefreshViewLastUpdated; 
  28.     /** 
  29.      * 头部视图  内容  -- end 
  30.      */ 
  31.     //当前listivew 的滚动状态 
  32.     private int mCurrentScrollState; 
  33.      
  34.     //当前listview 的刷新状态 
  35.     private int mRefreshState; 
  36.  
  37.     //动画效果 
  38.     //变为向下的箭头 
  39.     private RotateAnimation mFlipAnimation; 
  40.     //变为逆向的箭头 
  41.     private RotateAnimation mReverseFlipAnimation; 
  42.     //头视图的高度 
  43.     private int mRefreshViewHeight; 
  44.     //头视图 原始的 top padding 属性值 
  45.     private boolean mBounceHack; 
  46.  
  47.     public PullToRefreshListView(Context context) { 
  48.         super(context); 
  49.         init(context); 
  50.     } 
  51.  
  52.     public PullToRefreshListView(Context context, AttributeSet attrs) { 
  53.         super(context, attrs); 
  54.         init(context); 
  55.     } 
  56.  
  57.     public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) { 
  58.         super(context, attrs, defStyle); 
  59.         init(context); 
  60.     } 
  61.  
  62.     private void init(Context context) { 
  63.         // Load all of the animations we need in code rather than through XML 
  64.         //初始化动画 
  65.         mFlipAnimation = new RotateAnimation(0, -180
  66.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f, 
  67.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f); 
  68.         mFlipAnimation.setInterpolator(new LinearInterpolator()); 
  69.         mFlipAnimation.setDuration(250); 
  70.         mFlipAnimation.setFillAfter(true); 
  71.          
  72.          
  73.          
  74.         mReverseFlipAnimation = new RotateAnimation(-1800
  75.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f, 
  76.                 RotateAnimation.RELATIVE_TO_SELF, 0.5f); 
  77.         mReverseFlipAnimation.setInterpolator(new LinearInterpolator()); 
  78.         mReverseFlipAnimation.setDuration(250); 
  79.         mReverseFlipAnimation.setFillAfter(true); 
  80.  
  81.         mInflater = (LayoutInflater) context.getSystemService( 
  82.                 Context.LAYOUT_INFLATER_SERVICE); 
  83.  
  84.         mRefreshView = (RelativeLayout) mInflater.inflate(R.layout.pull_to_refresh_header, thisfalse);//(R.layout.pull_to_refresh_header, null); 
  85.         zhanweiTextView=(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_header_top_text); 
  86.           mRefreshViewText = 
  87.             (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text); 
  88.         mRefreshViewImage = 
  89.             (ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_p_w_picpath); 
  90.         mRefreshViewProgress = 
  91.             (ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress); 
  92.         mRefreshViewLastUpdated = 
  93.             (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at); 
  94.  
  95.         mRefreshViewImage.setMinimumHeight(50); 
  96.         mRefreshView.setOnClickListener(new OnClickRefreshListener()); 
  97.  
  98.         mRefreshState = TAP_TO_REFRESH; 
  99.  
  100.         addHeaderView(mRefreshView); 
  101.          
  102.         addFooterView((RelativeLayout) mInflater.inflate(R.layout.pull_to_refresh_footer, thisfalse)); 
  103.  
  104.         super.setOnScrollListener(this); 
  105.  
  106.         measureView(mRefreshView); 
  107.          
  108.         mRefreshViewHeight = mRefreshView.findViewById(R.id.pull_to_refresh_header).getMeasuredHeight(); 
  109.         //获取头文件的测量高度 
  110.     } 
  111.  
  112.     @Override 
  113.     protected void onAttachedToWindow() { 
  114.         setSelection(1); 
  115.     } 
  116.  
  117.     @Override 
  118.     public void setAdapter(ListAdapter adapter) { 
  119.         super.setAdapter(adapter); 
  120.  
  121.         setSelection(1); 
  122.     } 
  123.  
  124.     /** 
  125.      * Set the listener that will receive notifications every time the list 
  126.      * scrolls. 
  127.      *  
  128.      * @param l The scroll listener.  
  129.      */ 
  130.     @Override 
  131.     public void setOnScrollListener(AbsListView.OnScrollListener l) { 
  132.         mOnScrollListener = l; 
  133.     } 
  134.  
  135.     /** 
  136.      * Register a callback to be invoked when this list should be refreshed. 
  137.      *  
  138.      * @param onRefreshListener The callback to run. 
  139.      */ 
  140.     public void setOnRefreshListener(OnRefreshListener onRefreshListener) { 
  141.         mOnRefreshListener = onRefreshListener; 
  142.     } 
  143.      
  144.     public void setOnPullUpRefreshListener(OnPullUpRefreshListener onPullUpRefreshListener){ 
  145.         mOnPullUpRefreshListener=onPullUpRefreshListener; 
  146.     } 
  147.      
  148.     /** 
  149.      * Set a text to represent when the list was last updated.  
  150.      * @param lastUpdated Last updated at. 
  151.      */ 
  152.     public void setLastUpdated(CharSequence lastUpdated) { 
  153.         if (lastUpdated != null) { 
  154.             mRefreshViewLastUpdated.setVisibility(View.VISIBLE); 
  155.             mRefreshViewLastUpdated.setText(lastUpdated); 
  156.         } else { 
  157.             mRefreshViewLastUpdated.setVisibility(View.GONE); 
  158.         } 
  159.     } 
  160.  
  161.     @Override 
  162.     public boolean onTouchEvent(MotionEvent event) { 
  163.         mBounceHack = false;  //不反弹 
  164.         switch (event.getAction()) { 
  165.             case MotionEvent.ACTION_UP: 
  166.                 //将垂直滚动条设置为可用状态 
  167.                 if (!isVerticalScrollBarEnabled()) { 
  168.                     setVerticalScrollBarEnabled(true); 
  169.                 } 
  170.                  
  171.                 //如果头部刷新条出现,并且不是正在刷新状态 
  172.                 if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) { 
  173.                     if ((mRefreshView.getBottom() >= mRefreshViewHeight 
  174.                             || mRefreshView.getTop() >= 0
  175.                             && mRefreshState == RELEASE_TO_REFRESH) {   //如果头部视图处于拉离顶部的情况 
  176.                         // Initiate the refresh 
  177.                         mRefreshState = REFRESHING;  //将标量设置为,正在刷新 
  178.                         prepareForRefresh();  //准备刷新 
  179.                         onRefresh();   //刷新 
  180.                     } else if (mRefreshView.getBottom() < mRefreshViewHeight 
  181.                             || mRefreshView.getTop() <= 0) { 
  182.                         // Abort refresh and scroll down below the refresh view 
  183.                         // 停止刷新,并且滚动到头部刷新视图的下一个视图 
  184.                         resetHeader(); 
  185.                         setSelection(1);  //定位在第二个列表项 
  186.                     } 
  187.                 } 
  188.                 break
  189.             case MotionEvent.ACTION_DOWN: 
  190.                 break
  191.              
  192.             case MotionEvent.ACTION_MOVE: 
  193.                 break
  194.         } 
  195.         return super.onTouchEvent(event); 
  196.     } 
  197.  
  198.     /** 
  199.      * Resets the header to the original state.   
  200.      *  初始化头部视图 状态 
  201.      */ 
  202.     private void resetHeader() { 
  203.         if (mRefreshState != TAP_TO_REFRESH) { 
  204.             mRefreshState = TAP_TO_REFRESH; //初始刷新状态 
  205.             // Set refresh view text to the pull label 
  206.             //将文字初始化 
  207.             mRefreshViewText.setText(R.string.pull_to_refresh_tap_label); 
  208.             // Replace refresh drawable with arrow drawable 
  209.             //设置初始图片 
  210.             mRefreshViewImage.setImageResource(REFRESHICON); 
  211.             // Clear the full rotation animation 
  212.             // 清除动画 
  213.             mRefreshViewImage.clearAnimation(); 
  214.             // Hide progress bar and arrow. 
  215.             //隐藏头视图 
  216.             mRefreshViewImage.setVisibility(View.GONE); 
  217.             //隐藏进度条 
  218.             mRefreshViewProgress.setVisibility(View.GONE); 
  219.             zhanweiTextView.setVisibility(VISIBLE); 
  220.         } 
  221.     } 
  222.  
  223.      
  224.     //测量视图的高度 
  225.     private void measureView(View child) { 
  226.         //获取头部视图属性 
  227.         ViewGroup.LayoutParams p = child.getLayoutParams(); 
  228.         if (p == null) { 
  229.             p = new ViewGroup.LayoutParams( 
  230.                     ViewGroup.LayoutParams.MATCH_PARENT, 
  231.                     ViewGroup.LayoutParams.WRAP_CONTENT); 
  232.         } 
  233.          
  234.         int childWidthSpec = ViewGroup.getChildMeasureSpec(0
  235.                 0 + 0, p.width); 
  236.         int lpHeight = p.height; 
  237.         int childHeightSpec; 
  238.          
  239.         if (lpHeight > 0) {  //如果视图的高度大于0 
  240.             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);    
  241.         } else { 
  242.             childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 
  243.         } 
  244.         child.measure(childWidthSpec, childHeightSpec); 
  245.          
  246.     } 
  247.  
  248.     /**** 
  249.      * 滑动事件 
  250.      */ 
  251.     @Override 
  252.     public void onScroll(AbsListView view, int firstVisibleItem, 
  253.             int visibleItemCount, int totalItemCount) { 
  254.         // When the refresh view is completely visible, change the text to say 
  255.         // "Release to refresh..." and flip the arrow drawable. 
  256.         if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL   //如果是接触滚动状态,并且不是正在刷新的状态 
  257.                 && mRefreshState != REFRESHING) { 
  258.             if (firstVisibleItem == 0) {    //如果显示出来了第一个列表项 
  259.                 //显示刷新图片 
  260.                 mRefreshViewImage.setVisibility(View.VISIBLE); 
  261.                 if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20 
  262.                         || mRefreshView.getTop() >= 0
  263.                         && mRefreshState != RELEASE_TO_REFRESH) {  //如果下拉了listiview,则显示上拉刷新动画 
  264.                     mRefreshViewText.setText(R.string.pull_to_refresh_release_label); 
  265.                     mRefreshViewImage.clearAnimation(); 
  266.                     mRefreshViewImage.startAnimation(mFlipAnimation); 
  267.                     mRefreshState = RELEASE_TO_REFRESH; 
  268.                      
  269.                      
  270.                 } else if (mRefreshView.getBottom() < mRefreshViewHeight + 20 
  271.                         && mRefreshState != PULL_TO_REFRESH) {    //如果没有到达,下拉刷新距离,则回归原来的状态 
  272.                     mRefreshViewText.setText(R.string.pull_to_refresh_pull_label); 
  273.                     if (mRefreshState != TAP_TO_REFRESH) { 
  274.                         mRefreshViewImage.clearAnimation(); 
  275.                         mRefreshViewImage.startAnimation(mReverseFlipAnimation); 
  276.                          
  277.                         Log.i(TAG, "现在处于回弹状态"); 
  278.                          
  279.                     } 
  280.                     mRefreshState = PULL_TO_REFRESH; 
  281.                 } 
  282.             } else {    
  283.                 mRefreshViewImage.setVisibility(View.GONE);  //隐藏刷新图片 
  284.                 resetHeader();   //初始化,头部 
  285.             } 
  286.         } else if (mCurrentScrollState == SCROLL_STATE_FLING  //如果是自己滚动状态+ 第一个视图已经显示 + 不是刷新状态 
  287.                 && firstVisibleItem == 0 
  288.                 && mRefreshState != REFRESHING) { 
  289.             setSelection(1); 
  290.             mBounceHack = true;   //状态为回弹 
  291.         } else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) { 
  292.             setSelection(1); 
  293.         } 
  294.         if (mOnScrollListener != null) { 
  295.             mOnScrollListener.onScroll(view, firstVisibleItem, 
  296.                     visibleItemCount, totalItemCount); 
  297.         } 
  298.     } 
  299.  
  300.      
  301.     //滚动状态改变 
  302.     @Override 
  303.     public void onScrollStateChanged(AbsListView view, int scrollState) { 
  304.         mCurrentScrollState = scrollState; 
  305.  
  306.         if (mCurrentScrollState == SCROLL_STATE_IDLE) {   //如果滚动停顿 
  307.             mBounceHack = false
  308.             if(getLastVisiblePosition()==getCount()-1){ 
  309.                 onPullUpRefresh();//上拉刷新 
  310.                 System.out.println("shanglashuaxin"); 
  311.             } 
  312.         } 
  313.  
  314.         if (mOnScrollListener != null) { 
  315.             mOnScrollListener.onScrollStateChanged(view, scrollState); 
  316.         } 
  317.     } 
  318.  
  319.      
  320.      
  321.     //准备刷新 
  322.     public void prepareForRefresh() { 
  323.  
  324.         mRefreshViewImage.setVisibility(View.GONE); 
  325.         // We need this hack, otherwise it will keep the previous drawable. 
  326.         mRefreshViewImage.setImageDrawable(null); 
  327.         mRefreshViewProgress.setVisibility(View.VISIBLE); 
  328.  
  329.         // Set refresh view text to the refreshing label 
  330.        mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label); 
  331.  
  332.         mRefreshState = REFRESHING; 
  333.     } 
  334.  
  335.     //刷新 
  336.     public void onRefresh() { 
  337.         Log.d(TAG, "执行刷新"); 
  338.         zhanweiTextView.setVisibility(View.GONE); 
  339.         setSelection(0); 
  340.         if (mOnRefreshListener != null) { 
  341.             mOnRefreshListener.onRefresh(); 
  342.         } 
  343.     } 
  344.  
  345.     //上拉刷新 
  346.     public void onPullUpRefresh(){ 
  347.         if(mOnPullUpRefreshListener!=null){ 
  348.             mOnPullUpRefreshListener.onPullUpRefresh(); 
  349.         } 
  350.     } 
  351.      
  352.     /** 
  353.      * 刷新完成 的回调函数 
  354.      * Resets the list to a normal state after a refresh. 
  355.      * @param lastUpdated Last updated at. 
  356.      */ 
  357.     public void onRefreshComplete(CharSequence lastUpdated) { 
  358.         setLastUpdated(lastUpdated); 
  359.         onRefreshComplete(1);  
  360.     } 
  361.  
  362.     /** 
  363.      *  刷新完成回调函数 
  364.      * Resets the list to a normal state after a refresh. 
  365.      */ 
  366.     public void onRefreshComplete(int i) {         
  367.         resetHeader(); 
  368.         setSelection(i); 
  369.     } 
  370.  
  371.     /** 
  372.      * Invoked when the refresh view is clicked on. This is mainly used when 
  373.      * there's only a few items in the list and it's not possible to drag the 
  374.      * list. 
  375.      */ 
  376.      
  377.     private class OnClickRefreshListener implements OnClickListener { 
  378.  
  379.         @Override 
  380.         public void onClick(View v) { 
  381.             if (mRefreshState != REFRESHING) { 
  382.                 //准备刷新 
  383.                 prepareForRefresh();   
  384.                 //刷新    
  385.                 onRefresh();  
  386.             } 
  387.         } 
  388.  
  389.     } 
  390.  
  391.     /** 
  392.      * 下拉刷新方法接口 
  393.      */ 
  394.     public interface OnRefreshListener { 
  395.          
  396.         public void onRefresh(); 
  397.     } 
  398.     /** 
  399.      * 上拉刷新方法接口 
  400.      */ 
  401.     public interface OnPullUpRefreshListener{ 
  402.         public void onPullUpRefresh(); 
  403.     } 
  404.  
  405.      

Activity中的使用 MainActivity.java

  1. public class MainActivity extends Activity { 
  2.  
  3.     private ArrayList<String> list; 
  4.     @Override 
  5.     protected void onCreate(Bundle savedInstanceState) { 
  6.         super.onCreate(savedInstanceState); 
  7.         setContentView(R.layout.activity_main); 
  8.         final PullToRefreshListView listView=(PullToRefreshListView)
  9.  findViewById(R.id.listview); 
  10.         list=new ArrayList<String>(); 
  11.         for(int i=0;i<30;i++){ 
  12.             list.add(String.valueOf(i)); 
  13.         } 
  14.         final ArrayAdapter<String> adapter=new ArrayAdapter<String>
  15. (MainActivity.this, R.layout.list_text, R.id.showText, list); 
  16.         listView.setAdapter(adapter); 
  17.         //设置下拉刷新监听器 
  18.         listView.setOnRefreshListener(new OnRefreshListener() { 
  19.             //下拉刷新时执行的操作 
  20.             @Override 
  21.             public void onRefresh() { 
  22.                 new Thread(new Runnable() { 
  23.                     @Override 
  24.                     public void run() { 
  25.                         try { 
  26.                             Thread.sleep(2000);//模拟网络操作 
  27.                         } catch (InterruptedException e) { 
  28.                             e.printStackTrace(); 
  29.                         } 
  30.                         runOnUiThread(new Runnable() { 
  31.                             @Override 
  32.                             public void run() { 
  33.                                 //刷新完成时操作 
  34.                                 listView.onRefreshComplete("上次刷新时间xxx"); 
  35.                             } 
  36.                         }); 
  37.                     } 
  38.                 }).start(); 
  39.             } 
  40.         }); 
  41.         //设置上拉刷新监听器 
  42.         listView.setOnPullUpRefreshListener(new OnPullUpRefreshListener() { 
  43.              
  44.             @Override 
  45.             public void onPullUpRefresh() { 
  46.  
  47.                 new Thread(new Runnable() { 
  48.                     @Override 
  49.                     public void run() { 
  50.                         try { 
  51.                             Thread.sleep(2000); 
  52.                         } catch (InterruptedException e) { 
  53.                             e.printStackTrace(); 
  54.                         } 
  55.                         runOnUiThread(new Runnable() { 
  56.                              
  57.                             @Override 
  58.                             public void run() { 
  59.                                 int size=list.size(); 
  60.                                 for(int i=size;i<size+20;i++){ 
  61.                                     list.add("这是第"+String.valueOf(i)+"条内容"); 
  62.                                 } 
  63.                                 adapter.notifyDataSetChanged(); 
  64.                             } 
  65.                         }); 
  66.                     } 
  67.                 }).start(); 
  68.              
  69.             } 
  70.         }); 
  71.     } 
  72.  

布局activity_main.xml

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     xmlns:tools="http://schemas.android.com/tools" 
  3.     android:layout_width="match_parent" 
  4.     android:layout_height="match_parent" 
  5.     tools:context=".MainActivity" > 
  6.  
  7.     <com.zhicheng.pulllistview.PullToRefreshListView 
  8.         android:id="@+id/listview" 
  9.         android:layout_height="fill_parent" 
  10.         android:layout_width="fill_parent" 
  11.         /> 
  12.  
  13. </RelativeLayout> 

布局pull_to_refresh_header.xml

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:layout_height="fill_parent" 
  4.     android:layout_width="fill_parent" 
  5.     > 
  6.     <TextView  
  7.         android:id="@+id/pull_to_refresh_header_top_text" 
  8.         android:layout_height="wrap_content" 
  9.         android:layout_width="wrap_content" 
  10.         android:layout_centerHorizontal="true" 
  11.         android:paddingBottom="60dp" 
  12.         /> 
  13. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  14.     android:layout_width="fill_parent" 
  15.     android:layout_height="fill_parent" 
  16.     android:paddingTop="15dip" 
  17.     android:paddingBottom="15dip" 
  18.     android:gravity="center" 
  19.     android:id="@+id/pull_to_refresh_header" 
  20.     android:layout_below="@id/pull_to_refresh_header_top_text" 
  21.     > 
  22.     <ProgressBar  
  23.         android:id="@+id/pull_to_refresh_progress" 
  24.         android:indeterminate="true" 
  25.         android:layout_width="20dp" 
  26.         android:layout_height="20dp" 
  27.         android:layout_marginRight="20dp" 
  28.         android:layout_marginTop="10dp" 
  29.         android:layout_marginLeft="50dp" 
  30.         android:visibility="gone" 
  31.         android:layout_centerVertical="true" 
  32.         /> 
  33.     <ImageView 
  34.         android:id="@+id/pull_to_refresh_p_w_picpath" 
  35.         android:layout_width="wrap_content" 
  36.         android:layout_height="wrap_content" 
  37.         android:layout_marginLeft="30dip" 
  38.         android:layout_marginRight="20dip" 
  39.         android:visibility="gone" 
  40.         android:layout_gravity="center" 
  41.         android:gravity="center" 
  42.         android:src="@drawable/goicon" 
  43.         android:contentDescription="@string/app_name" 
  44.         /> 
  45.     <TextView 
  46.         android:id="@+id/pull_to_refresh_text" 
  47.         android:text="@string/pull_to_refresh_tap_label" 
  48.         android:textAppearance="?android:attr/textAppearanceMedium" 
  49.         android:textStyle="bold" 
  50.         android:paddingTop="5dip" 
  51.         android:layout_width="fill_parent" 
  52.         android:layout_height="wrap_content" 
  53.         android:layout_gravity="center" 
  54.         android:gravity="center" 
  55.         /> 
  56.     <TextView 
  57.         android:id="@+id/pull_to_refresh_updated_at" 
  58.         android:layout_below="@+id/pull_to_refresh_text" 
  59.         android:visibility="gone" 
  60.         android:textAppearance="?android:attr/textAppearanceSmall" 
  61.         android:layout_width="fill_parent" 
  62.         android:layout_height="wrap_content" 
  63.         android:layout_gravity="center" 
  64.         android:gravity="center" 
  65.         /> 
  66. </RelativeLayout> 
  67. </RelativeLayout> 

布局pull_to_refresh_footer.xml

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     android:layout_width="match_parent" 
  3.     android:layout_height="match_parent" 
  4.     android:paddingTop="10dp" 
  5.     android:paddingBottom="10dp" 
  6.      > 
  7.  
  8.     <ProgressBar  
  9.         android:layout_height="15dp" 
  10.         android:layout_width="15dp" 
  11.         android:layout_marginRight="5dp" 
  12.         android:layout_toLeftOf="@+id/pull_to_refresh_footer_text" 
  13.         android:layout_centerVertical="true" 
  14.         /> 
  15.     <TextView  
  16.         android:id="@+id/pull_to_refresh_footer_text" 
  17.         android:layout_height="wrap_content" 
  18.         android:layout_width="wrap_content" 
  19.         android:layout_centerHorizontal="true" 
  20.         android:layout_centerVertical="true" 
  21.         android:text="@string/toload20" 
  22.         /> 
  23. </RelativeLayout>