Android下拉刷新上拉加载简单的实现方法


项目中需要用到Android下拉刷新和上拉加载;所以学习了一个很简单的很方便的一个例子;自己也写过下拉刷新和上拉加载的功能;但是如果每个界面都要实现这个功能的话非常的麻烦;所以学习了别人很好的demo;然后分享一下;

我的学习步骤;

在网上下载demo;然后把必要的导入到项目中;

在此附上下载源码:

------------------------------------------分割线------------------------------------------

免费下载地址在 http://linux.bkjia.com/

用户名与密码都是www.bkjia.com

具体下载目录在 /2015年资料/6月/12日/Android下拉刷新上拉加载简单的实现方法/

下载方法见

------------------------------------------分割线------------------------------------------

所有的源代码如下;

XListViewFooter类

/**
 * @file XFooterView.java
 * @create Mar 31, 2012 9:33:43 PM
 * @author Maxwin
 * @description XListView's footer
 */
package me.maxwin.view;

import me.maxwin.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

public class XListViewFooter extends LinearLayout {
 public final static int STATE_NORMAL = 0;
 public final static int STATE_READY = 1;
 public final static int STATE_LOADING = 2;

 private Context mContext;

 private View mContentView;
 private View mProgressBar;
 private TextView mHintView;
 
 public XListViewFooter(Context context) {
  super(context);
  initView(context);
 }
 
 public XListViewFooter(Context context, AttributeSet attrs) {
  super(context, attrs);
  initView(context);
 }

 
 public void setState(int state) {
  mHintView.setVisibility(View.INVISIBLE);
  mProgressBar.setVisibility(View.INVISIBLE);
  mHintView.setVisibility(View.INVISIBLE);
  if (state == STATE_READY) {
   mHintView.setVisibility(View.VISIBLE);
   mHintView.setText(R.string.xlistview_footer_hint_ready);
  } else if (state == STATE_LOADING) {
   mProgressBar.setVisibility(View.VISIBLE);
  } else {
   mHintView.setVisibility(View.VISIBLE);
   mHintView.setText(R.string.xlistview_footer_hint_normal);
  }
 }
 
 public void setBottomMargin(int height) {
  if (height < 0) return ;
  LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();
  lp.bottomMargin = height;
  mContentView.setLayoutParams(lp);
 }
 
 public int getBottomMargin() {
  LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();
  return lp.bottomMargin;
 }
 
 
 /**
  * normal status
  */
 public void normal() {
  mHintView.setVisibility(View.VISIBLE);
  mProgressBar.setVisibility(View.GONE);
 }
 
 
 /**
  * loading status
  */
 public void loading() {
  mHintView.setVisibility(View.GONE);
  mProgressBar.setVisibility(View.VISIBLE);
 }
 
 /**
  * hide footer when disable pull load more
  */
 public void hide() {
  LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();
  lp.height = 0;
  mContentView.setLayoutParams(lp);
 }
 
 /**
  * show footer
  */
 public void show() {
  LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();
  lp.height = LayoutParams.WRAP_CONTENT;
  mContentView.setLayoutParams(lp);
 }
 
 private void initView(Context context) {
  mContext = context;
  LinearLayout moreView = (LinearLayout)LayoutInflater.from(mContext).inflate(R.layout.xlistview_footer, null);
  addView(moreView);
  moreView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
 
  mContentView = moreView.findViewById(R.id.xlistview_footer_content);
  mProgressBar = moreView.findViewById(R.id.xlistview_footer_progressbar);
  mHintView = (TextView)moreView.findViewById(R.id.xlistview_footer_hint_textview);
 }
 
 
}

XListViewHeader类

/**
 * @file XListViewHeader.java
 * @create Apr 18, 2012 5:22:27 PM
 * @author Maxwin
 * @description XListView's header
 */
package me.maxwin.view;

import me.maxwin.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

public class XListViewHeader extends LinearLayout {
 private LinearLayout mContainer;
 private ImageView mArrowImageView;
 private ProgressBar mProgressBar;
 private TextView mHintTextView;
 private int mState = STATE_NORMAL;

 private Animation mRotateUpAnim;
 private Animation mRotateDownAnim;
 
 private final int ROTATE_ANIM_DURATION = 180;
 
 public final static int STATE_NORMAL = 0;
 public final static int STATE_READY = 1;
 public final static int STATE_REFRESHING = 2;

 public XListViewHeader(Context context) {
  super(context);
  initView(context);
 }

 /**
  * @param context
  * @param attrs
  */
 public XListViewHeader(Context context, AttributeSet attrs) {
  super(context, attrs);
  initView(context);
 }

 private void initView(Context context) {
  // 鍒濆鎯呭喌锛岃缃笅鎷夊埛鏂皏iew楂樺害涓�0
  LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
    LayoutParams.FILL_PARENT, 0);
  mContainer = (LinearLayout) LayoutInflater.from(context).inflate(
    R.layout.xlistview_header, null);
  addView(mContainer, lp);
  setGravity(Gravity.BOTTOM);

  mArrowImageView = (ImageView)findViewById(R.id.xlistview_header_arrow);
  mHintTextView = (TextView)findViewById(R.id.xlistview_header_hint_textview);
  mProgressBar = (ProgressBar)findViewById(R.id.xlistview_header_progressbar);
 
  mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
    0.5f);
  mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
  mRotateUpAnim.setFillAfter(true);
  mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
    0.5f);
  mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
  mRotateDownAnim.setFillAfter(true);
 }

 public void setState(int state) {
  if (state == mState) return ;
 
  if (state == STATE_REFRESHING) { // 鏄剧ず杩涘害
   mArrowImageView.clearAnimation();
   mArrowImageView.setVisibility(View.INVISIBLE);
   mProgressBar.setVisibility(View.VISIBLE);
  } else { // 鏄剧ず绠ご鍥剧墖
   mArrowImageView.setVisibility(View.VISIBLE);
   mProgressBar.setVisibility(View.INVISIBLE);
  }
 
  switch(state){
  case STATE_NORMAL:
   if (mState == STATE_READY) {
    mArrowImageView.startAnimation(mRotateDownAnim);
   }
   if (mState == STATE_REFRESHING) {
    mArrowImageView.clearAnimation();
   }
   mHintTextView.setText(R.string.xlistview_header_hint_normal);
   break;
  case STATE_READY:
   if (mState != STATE_READY) {
    mArrowImageView.clearAnimation();
    mArrowImageView.startAnimation(mRotateUpAnim);
    mHintTextView.setText(R.string.xlistview_header_hint_ready);
   }
   break;
  case STATE_REFRESHING:
   mHintTextView.setText(R.string.xlistview_header_hint_loading);
   break;
   default:
  }
 
  mState = state;
 }
 
 public void setVisiableHeight(int height) {
  if (height < 0)
   height = 0;
  LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContainer
    .getLayoutParams();
  lp.height = height;
  mContainer.setLayoutParams(lp);
 }

 public int getVisiableHeight() {
  return mContainer.getLayoutParams().height;
 }

}

XListView类

/**
 * @file XListView.java
 * @package me.maxwin.view
 * @create Mar 18, 2012 6:28:41 PM
 * @author Maxwin
 * @description An ListView support (a) Pull down to refresh, (b) Pull up to load more.
 *   Implement IXListViewListener, and see stopRefresh() / stopLoadMore().
 */
package me.maxwin.view;

import me.maxwin.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.TextView;

public class XListView extends ListView implements OnScrollListener {

 private float mLastY = -1; // save event y
 private Scroller mScroller; // used for scroll back
 private OnScrollListener mScrollListener; // user's scroll listener

 // the interface to trigger refresh and load more.
 private IXListViewListener mListViewListener;

 // -- header view
 private XListViewHeader mHeaderView;
 // header view content, use it to calculate the Header's height. And hide it
 // when disable pull refresh.
 private RelativeLayout mHeaderViewContent;
 private TextView mHeaderTimeView;
 private int mHeaderViewHeight; // header view's height
 private boolean mEnablePullRefresh = true;
 private boolean mPullRefreshing = false; // is refreashing.

 // -- footer view
 private XListViewFooter mFooterView;
 private boolean mEnablePullLoad;
 private boolean mPullLoading;
 private boolean mIsFooterReady = false;
 
 // total list items, used to detect is at the bottom of listview.
 private int mTotalItemCount;

 // for mScroller, scroll back from header or footer.
 private int mScrollBack;
 private final static int SCROLLBACK_HEADER = 0;
 private final static int SCROLLBACK_FOOTER = 1;

 private final static int SCROLL_DURATION = 400; // scroll back duration
 private final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >= 50px
              // at bottom, trigger
              // load more.
 private final static float OFFSET_RADIO = 1.8f; // support iOS like pull
             // feature.

 /**
  * @param context
  */
 public XListView(Context context) {
  super(context);
  initWithContext(context);
 }

 public XListView(Context context, AttributeSet attrs) {
  super(context, attrs);
  initWithContext(context);
 }

 public XListView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  initWithContext(context);
 }

 private void initWithContext(Context context) {
  mScroller = new Scroller(context, new DecelerateInterpolator());
  // XListView need the scroll event, and it will dispatch the event to
  // user's listener (as a proxy).
  super.setOnScrollListener(this);

  // init header view
  mHeaderView = new XListViewHeader(context);
  mHeaderViewContent = (RelativeLayout) mHeaderView
    .findViewById(R.id.xlistview_header_content);
  mHeaderTimeView = (TextView) mHeaderView
    .findViewById(R.id.xlistview_header_time);
  addHeaderView(mHeaderView);

  // init footer view
  mFooterView = new XListViewFooter(context);

  // init header height
  mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(
    new OnGlobalLayoutListener() {
     @Override
     public void onGlobalLayout() {
      mHeaderViewHeight = mHeaderViewContent.getHeight();
      getViewTreeObserver()
        .removeGlobalOnLayoutListener(this);
     }
    });
 }

 @Override
 public void setAdapter(ListAdapter adapter) {
  // make sure XListViewFooter is the last footer view, and only add once.
  if (mIsFooterReady == false) {
   mIsFooterReady = true;
   addFooterView(mFooterView);
  }
  super.setAdapter(adapter);
 }

 /**
  * enable or disable pull down refresh feature.
  *
  * @param enable
  */
 public void setPullRefreshEnable(boolean enable) {
  mEnablePullRefresh = enable;
  if (!mEnablePullRefresh) { // disable, hide the content
   mHeaderViewContent.setVisibility(View.INVISIBLE);
  } else {
   mHeaderViewContent.setVisibility(View.VISIBLE);
  }
 }

 /**
  * enable or disable pull up load more feature.
  *
  * @param enable
  */
 public void setPullLoadEnable(boolean enable) {
  mEnablePullLoad = enable;
  if (!mEnablePullLoad) {
   mFooterView.hide();
   mFooterView.setOnClickListener(null);
   //make sure "pull up" don't show a line in bottom when listview with one page
   setFooterDividersEnabled(false);
  } else {
   mPullLoading = false;
   mFooterView.show();
   mFooterView.setState(XListViewFooter.STATE_NORMAL);
   //make sure "pull up" don't show a line in bottom when listview with one page 
   setFooterDividersEnabled(true);
   // both "pull up" and "click" will invoke load more.
   mFooterView.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
     startLoadMore();
    }
   });
  }
 }

 /**
  * stop refresh, reset header view.
  */
 public void stopRefresh() {
  if (mPullRefreshing == true) {
   mPullRefreshing = false;
   resetHeaderHeight();
  }
 }

 /**
  * stop load more, reset footer view.
  */
 public void stopLoadMore() {
  if (mPullLoading == true) {
   mPullLoading = false;
   mFooterView.setState(XListViewFooter.STATE_NORMAL);
  }
 }

 /**
  * set last refresh time
  *
  * @param time
  */
 public void setRefreshTime(String time) {
  mHeaderTimeView.setText(time);
 }

 private void invokeOnScrolling() {
  if (mScrollListener instanceof OnXScrollListener) {
   OnXScrollListener l = (OnXScrollListener) mScrollListener;
   l.onXScrolling(this);
  }
 }

 private void updateHeaderHeight(float delta) {
  mHeaderView.setVisiableHeight((int) delta
    + mHeaderView.getVisiableHeight());
  if (mEnablePullRefresh && !mPullRefreshing) { // 鏈浜庡埛鏂扮姸鎬侊紝鏇存柊绠ご
   if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
    mHeaderView.setState(XListViewHeader.STATE_READY);
   } else {
    mHeaderView.setState(XListViewHeader.STATE_NORMAL);
   }
  }
  setSelection(0); // scroll to top each time
 }

 /**
  * reset header view's height.
  */
 private void resetHeaderHeight() {
  int height = mHeaderView.getVisiableHeight();
  if (height == 0) // not visible.
   return;
  // refreshing and header isn't shown fully. do nothing.
  if (mPullRefreshing && height <= mHeaderViewHeight) {
   return;
  }
  int finalHeight = 0; // default: scroll back to dismiss header.
  // is refreshing, just scroll back to show all the header.
  if (mPullRefreshing && height > mHeaderViewHeight) {
   finalHeight = mHeaderViewHeight;
  }
  mScrollBack = SCROLLBACK_HEADER;
  mScroller.startScroll(0, height, 0, finalHeight - height,
    SCROLL_DURATION);
  // trigger computeScroll
  invalidate();
 }

 private void updateFooterHeight(float delta) {
  int height = mFooterView.getBottomMargin() + (int) delta;
  if (mEnablePullLoad && !mPullLoading) {
   if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load
             // more.
    mFooterView.setState(XListViewFooter.STATE_READY);
   } else {
    mFooterView.setState(XListViewFooter.STATE_NORMAL);
   }
  }
  mFooterView.setBottomMargin(height);

//  setSelection(mTotalItemCount - 1); // scroll to bottom
 }

 private void resetFooterHeight() {
  int bottomMargin = mFooterView.getBottomMargin();
  if (bottomMargin > 0) {
   mScrollBack = SCROLLBACK_FOOTER;
   mScroller.startScroll(0, bottomMargin, 0, -bottomMargin,
     SCROLL_DURATION);
   invalidate();
  }
 }

 private void startLoadMore() {
  mPullLoading = true;
  mFooterView.setState(XListViewFooter.STATE_LOADING);
  if (mListViewListener != null) {
   mListViewListener.onLoadMore();
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent ev) {
  if (mLastY == -1) {
   mLastY = ev.getRawY();
  }

  switch (ev.getAction()) {
  case MotionEvent.ACTION_DOWN:
   mLastY = ev.getRawY();
   break;
  case MotionEvent.ACTION_MOVE:
   final float deltaY = ev.getRawY() - mLastY;
   mLastY = ev.getRawY();
   if (getFirstVisiblePosition() == 0
     && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {
    // the first item is showing, header has shown or pull down.
    updateHeaderHeight(deltaY / OFFSET_RADIO);
    invokeOnScrolling();
   } else if (getLastVisiblePosition() == mTotalItemCount - 1
     && (mFooterView.getBottomMargin() > 0 || deltaY < 0)) {
    // last item, already pulled up or want to pull up.
    updateFooterHeight(-deltaY / OFFSET_RADIO);
   }
   break;
  default:
   mLastY = -1; // reset
   if (getFirstVisiblePosition() == 0) {
    // invoke refresh
    if (mEnablePullRefresh
      && mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
     mPullRefreshing = true;
     mHeaderView.setState(XListViewHeader.STATE_REFRESHING);
     if (mListViewListener != null) {
      mListViewListener.onRefresh();
     }
    }
    resetHeaderHeight();
   } else if (getLastVisiblePosition() == mTotalItemCount - 1) {
    // invoke load more.
    if (mEnablePullLoad
        && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA
        && !mPullLoading) {
     startLoadMore();
    }
    resetFooterHeight();
   }
   break;
  }
  return super.onTouchEvent(ev);
 }

 @Override
 public void computeScroll() {
  if (mScroller.computeScrollOffset()) {
   if (mScrollBack == SCROLLBACK_HEADER) {
    mHeaderView.setVisiableHeight(mScroller.getCurrY());
   } else {
    mFooterView.setBottomMargin(mScroller.getCurrY());
   }
   postInvalidate();
   invokeOnScrolling();
  }
  super.computeScroll();
 }

 @Override
 public void setOnScrollListener(OnScrollListener l) {
  mScrollListener = l;
 }

 @Override
 public void onScrollStateChanged(AbsListView view, int scrollState) {
  if (mScrollListener != null) {
   mScrollListener.onScrollStateChanged(view, scrollState);
  }
 }

 @Override
 public void onScroll(AbsListView view, int firstVisibleItem,
   int visibleItemCount, int totalItemCount) {
  // send to user's listener
  mTotalItemCount = totalItemCount;
  if (mScrollListener != null) {
   mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,
     totalItemCount);
  }
 }

 public void setXListViewListener(IXListViewListener l) {
  mListViewListener = l;
 }

 /**
  * you can listen ListView.OnScrollListener or this one. it will invoke
  * onXScrolling when header/footer scroll back.
  */
 public interface OnXScrollListener extends OnScrollListener {
  public void onXScrolling(View view);
 }

 /**
  * implements this interface to get refresh/load more event.
  */
 public interface IXListViewListener {
  public void onRefresh();

  public void onLoadMore();
 }
}

XListViewActivity类;主要学习这个类;调用其他的类就ok

package me.maxwin;

import java.util.ArrayList;

import me.maxwin.view.XListView;
import me.maxwin.view.XListView.IXListViewListener;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ArrayAdapter;

public class XListViewActivity extends Activity implements IXListViewListener {
 private XListView mListView;
 private ArrayAdapter<String> mAdapter;
 private ArrayList<String> items = new ArrayList<String>();
 private Handler mHandler;
 private int start = 0;
 private static int refreshCnt = 0;
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  geneItems();
  mListView = (XListView) findViewById(R.id.xListView);
  mListView.setPullLoadEnable(true);
  mAdapter = new ArrayAdapter<String>(this, R.layout.list_item, items);
  mListView.setAdapter(mAdapter);
//  mListView.setPullLoadEnable(false);
//  mListView.setPullRefreshEnable(false);
  mListView.setXListViewListener(this);
  mHandler = new Handler();
 }

 private void geneItems() {
  for (int i = 0; i != 20; ++i) {
   items.add("refresh cnt " + (++start));
  }
 }

 private void onLoad() {
  mListView.stopRefresh();
  mListView.stopLoadMore();
  mListView.setRefreshTime("鍒氬垰");
 }
 
 @Override
 public void onRefresh() {
  mHandler.postDelayed(new Runnable() {
   @Override
   public void run() {
    start = ++refreshCnt;
    items.clear();
    geneItems();
    // mAdapter.notifyDataSetChanged();
    mAdapter = new ArrayAdapter<String>(XListViewActivity.this, R.layout.list_item, items);
    mListView.setAdapter(mAdapter);
    onLoad();
   }
  }, 2000);
 }

 @Override
 public void onLoadMore() {
  mHandler.postDelayed(new Runnable() {
   @Override
   public void run() {
    geneItems();
    mAdapter.notifyDataSetChanged();
    onLoad();
   }
  }, 2000);
 }

}

layout文件源码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" android:background="#f0f0f0">

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <me.maxwin.view.XListView
        android:id="@+id/xListView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" android:cacheColorHint="#00000000">
    </me.maxwin.view.XListView>

</LinearLayout>

效果运行了就知道啦;哈哈;

相关内容