码迷,mamicode.com
首页 > 移动开发 > 详细

Android 下拉刷新,上滑加载更多

时间:2015-08-07 01:52:07      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:下拉刷新   上拉加载更多   android   

底部上拉效果

public class ListViewFooter 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 ListViewFooter(Context context) {
  super(context);
  initView(context);
 }
 
 public ListViewFooter(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);
 }
 
 
}


下拉顶部效果

public class ListViewHeader 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 ListViewHeader(Context context) {
  super(context);
  initView(context);
 }

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

 private void initView(Context context) {
  // 初始情况,设置下拉刷新view高度为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.getHeight();
 }

}


MainActivity

public class MainActivity extends Activity implements IXListViewListener {
 private MyListView 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 = (MyListView) 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 != 5; ++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>(MainActivity.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);
 }

}

自定义ListView

public class MyListView 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 ListViewHeader 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 ListViewFooter 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 MyListView(Context context) {
  super(context);
  initWithContext(context);
 }

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

 public MyListView(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 ListViewHeader(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 ListViewFooter(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);
  } else {
   mPullLoading = false;
   mFooterView.show();
   mFooterView.setState(ListViewFooter.STATE_NORMAL);
   // 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(ListViewFooter.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(ListViewHeader.STATE_READY);
   } else {
    mHeaderView.setState(ListViewHeader.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(ListViewFooter.STATE_READY);
   } else {
    mFooterView.setState(ListViewFooter.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(ListViewFooter.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();
   System.out.println("数据监测:" + getFirstVisiblePosition() + "---->"
     + getLastVisiblePosition());
   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(ListViewHeader.STATE_REFRESHING);
     if (mListViewListener != null) {
      mListViewListener.onRefresh();
     }
    }
    resetHeaderHeight();
   }
   if (getLastVisiblePosition() == mTotalItemCount - 1) {
    // invoke load more.
    if (mEnablePullLoad
      && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA) {
     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();
 }
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

Android 下拉刷新,上滑加载更多

标签:下拉刷新   上拉加载更多   android   

原文地址:http://blog.csdn.net/u010184245/article/details/47328123

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!