listview 下拉刷新加载数据

点击头条,头条会变成以下:

然后,过一段时间,刷新完成以后,listview又setSelection(1),增加一条数据,同时,把顶部给遮挡住:

这是点击刷新,然后是下拉刷新:

最后结果和点击刷新相同。那现在开始看下代码:

首先看下所用到的控件和变量:

  1. // 状态
  2. private static final int TAP_TO_REFRESH = 1;//点击刷新
  3. private static final int PULL_TO_REFRESH = 2;  //拉动刷新
  4. private static final int RELEASE_TO_REFRESH = 3; //释放刷新
  5. private static final int REFRESHING = 4;  //正在刷新
  6. // 当前滑动状态
  7. private int mCurrentScrollState;
  8. // 当前刷新状态
  9. private int mRefreshState;
  10. //头视图的高度
  11. private int mRefreshViewHeight;
  12. //头视图 原始的top padding 属性值
  13. private int mRefreshOriginalTopPadding;
  14. private int mLastMotionY;
  15. // 监听对listview的滑动动作
  16. private OnRefreshListener mOnRefreshListener;
  17. //箭头图片
  18. private static  int REFRESHICON = R.drawable.goicon;
  19. //listview 滚动监听器
  20. private OnScrollListener mOnScrollListener;
  21. private LayoutInflater mInflater;
  22. private RelativeLayout mRefreshView;
  23. //顶部刷新时出现的控件
  24. private TextView mRefreshViewText;
  25. private ImageView mRefreshViewImage;
  26. private ProgressBar mRefreshViewProgress;
  27. private TextView mRefreshViewLastUpdated;
  28. // 箭头动画效果
  29. //变为向下的箭头
  30. private RotateAnimation mFlipAnimation;
  31. //变为逆向的箭头
  32. private RotateAnimation mReverseFlipAnimation;
  33. //是否反弹
  34. private boolean mBounceHack;

看下点击刷新的代码过程:

在init()方法中初始化各个控件及设置监听:

  1. private void init(Context context) {
  2. // Load all of the animations we need in code rather than through XML
  3. mFlipAnimation = new RotateAnimation(0, -180,RotateAnimation.RELATIVE_TO_SELF,
  4. 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);
  5. mFlipAnimation.setInterpolator(new LinearInterpolator());
  6. mFlipAnimation.setDuration(250);
  7. mFlipAnimation.setFillAfter(true);
  8. mReverseFlipAnimation = new RotateAnimation(-180, 0,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);
  9. mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
  10. mReverseFlipAnimation.setDuration(250);
  11. mReverseFlipAnimation.setFillAfter(true);
  12. mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  13. mRefreshView = (RelativeLayout) mInflater.inflate(R.layout.pull_to_refresh_header, this, false);
  14. mRefreshViewText =(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);
  15. mRefreshViewImage =(ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);
  16. mRefreshViewProgress =(ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);
  17. mRefreshViewLastUpdated =(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);
  18. mRefreshViewImage.setMinimumHeight(50);
  19. mRefreshView.setOnClickListener(new OnClickRefreshListener());
  20. mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();
  21. mRefreshState = TAP_TO_REFRESH;
  22. //为listview头部增加一个view
  23. addHeaderView(mRefreshView);
  24. super.setOnScrollListener(this);
  25. measureView(mRefreshView);
  26. mRefreshViewHeight = mRefreshView.getMeasuredHeight();
  27. }

我们看到,mRefreshView控件既是listview用于刷新的头控件,这里它设置了监听事件:

  1. mRefreshView.setOnClickListener(new OnClickRefreshListener());

我们再来看下监听事件的定义:

  1. private class OnClickRefreshListener implements OnClickListener {
  2. @Override
  3. public void onClick(View v) {
  4. if (mRefreshState != REFRESHING) {
  5. prepareForRefresh();
  6. onRefresh();
  7. }
  8. }
  9. }

调用了preparForRefresh()(准备刷新)和onRefresh()(刷新)两个方法,然后在查看这两个方法的定义:

  1. public void prepareForRefresh() {
  2. resetHeaderPadding();   // 恢复header的边距
  3. mRefreshViewImage.setVisibility(View.GONE);
  4. // We need this hack, otherwise it will keep the previous drawable.
  5. // 注意加上,否则仍然显示之前的图片
  6. mRefreshViewImage.setImageDrawable(null);
  7. mRefreshViewProgress.setVisibility(View.VISIBLE);
  8. // Set refresh view text to the refreshing label
  9. mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);
  10. mRefreshState = REFRESHING;
  11. }
  12. public void onRefresh() {
  13. if (mOnRefreshListener != null) {
  14. mOnRefreshListener.onRefresh();
  15. }
  16. }

其中,后者还是回调方法。

我们看下preparForRefresh()方法中,引用了resetHeadPadding()方法:

  1. /**
  2. * Sets the header padding back to original size.
  3. * 将head的边距重置为初始的数值
  4. */
  5. private void resetHeaderPadding() {
  6. mRefreshView.setPadding(
  7. mRefreshView.getPaddingLeft(),
  8. mRefreshOriginalTopPadding,
  9. mRefreshView.getPaddingRight(),
  10. mRefreshView.getPaddingBottom());
  11. }

从新设置下header距上下左右的距离。

最重要的方法应该是:onScroll()和onTouchEvent()方法,先看下onTouchEvent()方法:

  1. @Override
  2. public boolean onTouchEvent(MotionEvent event) {
  3. //当前手指的Y值
  4. final int y = (int) event.getY();
  5. mBounceHack = false;
  6. switch (event.getAction()) {
  7. case MotionEvent.ACTION_UP:
  8. //将垂直滚动条设置为可用状态
  9. if (!isVerticalScrollBarEnabled()) {
  10. setVerticalScrollBarEnabled(true);
  11. }
  12. if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
  13. // 拖动距离达到刷新需要
  14. if ((mRefreshView.getBottom() >= mRefreshViewHeight
  15. || mRefreshView.getTop() >= 0)
  16. && mRefreshState == RELEASE_TO_REFRESH) {
  17. // 把状态设置为正在刷新
  18. // Initiate the refresh
  19. mRefreshState = REFRESHING; //将标量设置为,正在刷新
  20. // 准备刷新
  21. prepareForRefresh();
  22. // 刷新
  23. onRefresh();
  24. } else if (mRefreshView.getBottom() < mRefreshViewHeight
  25. || mRefreshView.getTop() <= 0) {
  26. // Abort refresh and scroll down below the refresh view
  27. //停止刷新,并且滚动到头部刷新视图的下一个视图
  28. resetHeader();
  29. setSelection(1); //定位在第二个列表项
  30. }
  31. }
  32. break;
  33. case MotionEvent.ACTION_DOWN:
  34. // 获得按下y轴位置
  35. mLastMotionY = y;
  36. break;
  37. case MotionEvent.ACTION_MOVE:
  38. //更行头视图的toppadding 属性
  39. applyHeaderPadding(event);
  40. break;
  41. }
  42. return super.onTouchEvent(event);
  43. }

当按下的时候,记录按下y轴的位置,然后在move中调用了applyHeaderPadding()方法,我们再看下这个方法:

  1. // 获得header距离
  2. private void applyHeaderPadding(MotionEvent ev) {
  3. //获取累积的动作数
  4. int pointerCount = ev.getHistorySize();
  5. for (int p = 0; p < pointerCount; p++) {
  6. //如果是释放将要刷新状态
  7. if (mRefreshState == RELEASE_TO_REFRESH) {
  8. if (isVerticalFadingEdgeEnabled()) {
  9. setVerticalScrollBarEnabled(false);
  10. }
  11. //历史累积的高度
  12. int historicalY = (int) ev.getHistoricalY(p);
  13. // Calculate the padding to apply, we divide by 1.7 to
  14. // simulate a more resistant effect during pull.
  15. // 计算申请的边距,除以1.7使得拉动效果更好
  16. int topPadding = (int) (((historicalY - mLastMotionY)- mRefreshViewHeight) / 1.7);
  17. mRefreshView.setPadding(
  18. mRefreshView.getPaddingLeft(),
  19. topPadding,
  20. mRefreshView.getPaddingRight(),
  21. mRefreshView.getPaddingBottom());
  22. }
  23. }
  24. }

通过记录滑动距离,实时变化头部mRefreshView的上下左右的距离。

最后,看下手指松开的ACTION_UP:

  1. case MotionEvent.ACTION_UP:
  2. //将垂直滚动条设置为可用状态
  3. if (!isVerticalScrollBarEnabled()) {
  4. setVerticalScrollBarEnabled(true);
  5. }
  6. if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
  7. // 拖动距离达到刷新需要
  8. if ((mRefreshView.getBottom() >= mRefreshViewHeight
  9. || mRefreshView.getTop() >= 0)
  10. && mRefreshState == RELEASE_TO_REFRESH) {
  11. // 把状态设置为正在刷新
  12. // Initiate the refresh
  13. mRefreshState = REFRESHING; //将标量设置为:正在刷新
  14. // 准备刷新
  15. prepareForRefresh();
  16. // 刷新
  17. onRefresh();
  18. } else if (mRefreshView.getBottom() < mRefreshViewHeight
  19. || mRefreshView.getTop() <= 0) {
  20. // Abort refresh and scroll down below the refresh view
  21. //停止刷新,并且滚动到头部刷新视图的下一个视图
  22. resetHeader();
  23. setSelection(1); //定位在第二个列表项
  24. }
  25. }
  26. break;

当滑动距离大于一个item的距离时,添加一个item,否则,弹回。

看完onTouchEvent(),然后再看一下onScroll()方法:

  1. @Override
  2. public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
  3. // When the refresh view is completely visible, change the text to say
  4. // "Release to refresh..." and flip the arrow drawable.
  5. // 在refreshview完全可见时,设置文字为松开刷新,同时翻转箭头
  6. //如果是接触滚动状态,并且不是正在刷新的状态
  7. if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL&& mRefreshState != REFRESHING) {
  8. if (firstVisibleItem == 0) {
  9. //如果显示出来了第一个列表项,显示刷新图片
  10. mRefreshViewImage.setVisibility(View.VISIBLE);
  11. //如果下拉了listiview,则显示上拉刷新动画
  12. if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20|| mRefreshView.getTop() >= 0)
  13. && mRefreshState != RELEASE_TO_REFRESH) {
  14. mRefreshViewText.setText(R.string.pull_to_refresh_release_label);
  15. mRefreshViewImage.clearAnimation();
  16. mRefreshViewImage.startAnimation(mFlipAnimation);
  17. mRefreshState = RELEASE_TO_REFRESH;
  18. //如果下拉距离不够,则回归原来的状态
  19. } else if (mRefreshView.getBottom() < mRefreshViewHeight + 20
  20. && mRefreshState != PULL_TO_REFRESH) {
  21. mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);
  22. if (mRefreshState != TAP_TO_REFRESH) {
  23. mRefreshViewImage.clearAnimation();
  24. mRefreshViewImage.startAnimation(mReverseFlipAnimation);
  25. }
  26. mRefreshState = PULL_TO_REFRESH;
  27. }
  28. } else {
  29. mRefreshViewImage.setVisibility(View.GONE);
  30. resetHeader();
  31. }
  32. //如果是滚动状态+ 第一个视图已经显示+ 不是刷新状态
  33. } else if (mCurrentScrollState == SCROLL_STATE_FLING  && firstVisibleItem == 0
  34. && mRefreshState != REFRESHING) {
  35. setSelection(1);
  36. mBounceHack = true;
  37. } else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) {
  38. setSelection(1);
  39. }
  40. if (mOnScrollListener != null) {
  41. mOnScrollListener.onScroll(view, firstVisibleItem,visibleItemCount, totalItemCount);
  42. }
  43. }

该方法是在滑动过程中,各种状况的处理。

onScroll()方法和onTouchEvent()方法的执行过程应该是,先onTouchEvent()的ACTION_DOWN,然后是ACTION_MOVE和onScroll()方法同时进行,最后是onTouchEvent()的ACTION_UP。也可以自己打log看一下。这样在onTouchEvent()处理header,就是mRefreshView的外部的各个熟悉,onScroll()里面处理header(mRefreshView)里面内部的控件变化,从逻辑上来说比较清晰。

在onScroll()中,引用方法resetHeader()方法:

  1. /**
  2. * Resets the header to the original state.
  3. * 重置header为之前的状态
  4. */
  5. private void resetHeader() {
  6. if (mRefreshState != TAP_TO_REFRESH) {
  7. mRefreshState = TAP_TO_REFRESH;
  8. resetHeaderPadding();
  9. // 将刷新图标换成箭头
  10. // Set refresh view text to the pull label
  11. mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);
  12. // Replace refresh drawable with arrow drawable
  13. // 清除动画
  14. mRefreshViewImage.setImageResource(REFRESHICON);
  15. // Clear the full rotation animation
  16. mRefreshViewImage.clearAnimation();
  17. // Hide progress bar and arrow.
  18. // 隐藏图标和进度条
  19. mRefreshViewImage.setVisibility(View.GONE);
  20. mRefreshViewProgress.setVisibility(View.GONE);
  21. }
  22. }

resetHead就是header(mRefreshView)的内部的具体操作。

当一切都完成以后,就可以调用onRefreshComplete()方法:

  1. /**
  2. * Resets the list to a normal state after a refresh.
  3. * 重置listview为普通的listview
  4. * @param lastUpdated
  5. * Last updated at.
  6. */
  7. public void onRefreshComplete(CharSequence lastUpdated) {
  8. setLastUpdated(lastUpdated);
  9. onRefreshComplete();
  10. }
  11. /**
  12. * Resets the list to a normal state after a refresh.
  13. * 重置listview为普通的listview,
  14. */
  15. public void onRefreshComplete() {
  16. resetHeader();
  17. // If refresh view is visible when loading completes, scroll down to
  18. // the next item.
  19. if (mRefreshView.getBottom() > 0) {
  20. invalidateViews();  //重绘视图
  21. setSelection(1);
  22. }
  23. }

重新绘制listivew,然后setSelection(1)。完成!

下载地址:http://download.csdn.net/detail/u014608640/8400233

时间: 2024-11-11 19:46:00

listview 下拉刷新加载数据的相关文章

Android UI--自定义ListView(实现下拉刷新+加载更多)

http://blog.csdn.net/wwj_748/article/details/12512885 Android UI--自定义ListView(实现下拉刷新+加载更多) 关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆.不过我就没发现比较实用的,要不就是实现起来太复杂,要不就是不健全的.因为小巫近期要开发新浪微博客户端,需要实现ListView的下拉刷新,所以就想把这个UI整合到项目当中去,这里只是一个demo,可以根据项目的需要进行修改. 就不要太在乎界面了哈:

Android Demo 下拉刷新+加载更多+滑动删除

小伙伴们在逛淘宝或者是各种app上,都可以看到这样的功能,下拉刷新和加载更多以及滑动删除,刷新,指刷洗之后使之变新,比喻突破旧的而创造出新的,比如在手机上浏览新闻的时候,使用下拉刷新的功能,我们可以第一时间掌握最新消息,加载更多是什么nie,简单来说就是在网页上逛淘宝的时候,我们可以点击下一页来满足我们更多的需求,但是在手机端就不一样了,没有上下页,怎么办nie,方法总比困难多,细心的小伙伴可能会发现,在手机端中,有加载更多来满足我们的要求,其实加载更多也是分页的一种体现.小伙伴在使用手机版QQ

uni-app下拉刷新加载刷新数据

onPullDownRefresh 监听该页面用户下拉刷新事件 需要在 pages.json 里 开启 enablePullDownRefresh "globalStyle": { } 当处理完数据刷新后,uni.stopPullDownRefresh 可以停止当前页面的下拉刷新 uni.startPullDownRefresh(OBJECT) success Function 否 接口调用成功的回调 fail Function 否 接口调用失败的回调函数 complete Funct

Android智能下拉刷新加载框架—看这些就够了

一些值得学习的几个下拉刷新上拉加载开源库 Android智能下拉刷新框架-SmartRefreshLayout 支持所有的 View(AbsListView.RecyclerView.WebView....View) 和多层嵌套的视图结构 支持自定义并且已经集成了很多炫酷的 Header 和 Footer (图). 支持和ListView的同步滚动 和 RecyclerView.AppBarLayout.CoordinatorLayout 的嵌套滚动 NestedScrolling. 支持在An

Android ListView 下拉刷新 点击加载更多

最近项目中用到了ListView的下拉刷新的功能,总结了一下前辈们的代码,单独抽取出来写了一个demo作为示例. 效果图 下拉刷新: 加载更多: CustomListView.java [java] view plaincopy package com.example.uitest.view; import java.util.Date; import com.example.uitest.R; import android.content.Context; import android.uti

十分钟实现ListView下拉刷新上滑加载更多

说到ListView下拉刷新几乎每个APP都会用到,所以ListView下拉刷新是很重要的,就像ListView优化一样是你必会的东西. ListView实现下拉刷新如果我们开发人员自己编写相对来说比较费事的,当我们使用第三方库之后我们再来开发这个功能就会省事很多.相比与自己实现可以少编写不少代码,Android-PullToRefresh库可以轻松实现ListView的下拉刷新功能. 要使用Android—PullToRefesh库对ListView实现下拉刷新要经过以下几个步骤: 1.下载A

页面滚动动态加载数据,页面下拉自动加载内容 jquery

<!DOCTYPE=html> <html> <head> < script src="js/jquery.js" type="text/javascript"></ script> < script type="text/javascript"> $(document).ready(function(){ var range = 50; //距下边界长度/单位px var

ListView下拉刷新

public class MyListView extends ListView implements OnScrollListener { private static final int STATE_NORMAL = 0;  // 正常状态 private static final int STATE_PULL = 1;    // 下来状态 private static final int STATE_RELEASE = 2; // 释放状态 private static final in

Android—自定义控件实现ListView下拉刷新

这篇博客为大家介绍一个android常见的功能——ListView下拉刷新(参考自他人博客,网址忘记了,阅读他的代码自己理解注释的,希望能帮助到大家): 首先下拉未松手时候手机显示这样的界面: 下面的代码是自定的扎样的控件: package com.dhsr.smartID.view; import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import andr