Android PullToRefresh为 Android 应用提供一个向下滑动即刷新列表的功能。

项目如图:

效果如图:

包含测试文件就2个目标文件!

主要类如下:

public class PullToRefreshListView extends ListView implements OnScrollListener
{private static final int TAP_TO_REFRESH = 1;private static final int PULL_TO_REFRESH = 2;private static final int RELEASE_TO_REFRESH = 3;private static final int REFRESHING = 4;private static final String TAG = "PullToRefreshListView";private OnRefreshListener mOnRefreshListener;/*** 收到通知的监听器每次滚动列表。*/private OnScrollListener mOnScrollListener;private LayoutInflater mInflater;private RelativeLayout mRefreshView;private TextView mRefreshViewText;private ImageView mRefreshViewImage;private ProgressBar mRefreshViewProgress;private TextView mRefreshViewLastUpdated;private int mCurrentScrollState;private int mRefreshState;private RotateAnimation mFlipAnimation;private RotateAnimation mReverseFlipAnimation;private int mRefreshViewHeight;private int mRefreshOriginalTopPadding;private int mLastMotionY;private boolean mBounceHack;public PullToRefreshListView(Context context){super(context);init(context);}public PullToRefreshListView(Context context, AttributeSet attrs){super(context, attrs);init(context);}public PullToRefreshListView(Context context, AttributeSet attrs,int defStyle){super(context, attrs, defStyle);init(context);}private void init(Context context){//我们需要在代码中加载所有的动画,而不是通过XMLmFlipAnimation = new RotateAnimation(0, -180,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);mFlipAnimation.setInterpolator(new LinearInterpolator());mFlipAnimation.setDuration(250);mFlipAnimation.setFillAfter(true);mReverseFlipAnimation = new RotateAnimation(-180, 0,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);mReverseFlipAnimation.setInterpolator(new LinearInterpolator());mReverseFlipAnimation.setDuration(250);mReverseFlipAnimation.setFillAfter(true);mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);mRefreshView = (RelativeLayout) mInflater.inflate(R.layout.pull_to_refresh_header, this, false);mRefreshViewText = (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);mRefreshViewImage = (ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);mRefreshViewProgress = (ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);mRefreshViewLastUpdated = (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);mRefreshViewImage.setMinimumHeight(50);mRefreshView.setOnClickListener(new OnClickRefreshListener());mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();mRefreshState = TAP_TO_REFRESH;addHeaderView(mRefreshView);super.setOnScrollListener(this);measureView(mRefreshView);mRefreshViewHeight = mRefreshView.getMeasuredHeight();}@Overrideprotected void onAttachedToWindow(){super.onAttachedToWindow();setSelection(1);}@Overridepublic void setAdapter(ListAdapter adapter){super.setAdapter(adapter);setSelection(1);}/*** 设置将接收通知的侦听器,每次滚动列表。* @param l*            The scroll listener.*/@Overridepublic void setOnScrollListener(AbsListView.OnScrollListener l){mOnScrollListener = l;}/*** 注册一个回调函数被调用时,此列表应被刷新。* @param onRefreshListener*            The callback to run.*/public void setOnRefreshListener(OnRefreshListener onRefreshListener){mOnRefreshListener = onRefreshListener;}/*** 设置文本表示当列表的最后更新时间。* @param lastUpdated*            Last updated at.*/public void setLastUpdated(CharSequence lastUpdated){if (lastUpdated != null){mRefreshViewLastUpdated.setVisibility(View.VISIBLE);mRefreshViewLastUpdated.setText(lastUpdated);} else{mRefreshViewLastUpdated.setVisibility(View.GONE);}}@Overridepublic boolean onTouchEvent(MotionEvent event){final int y = (int) event.getY();mBounceHack = false;switch (event.getAction()){case MotionEvent.ACTION_UP:if (!isVerticalScrollBarEnabled()){setVerticalScrollBarEnabled(true);}if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING){if ((mRefreshView.getBottom() >= mRefreshViewHeight || mRefreshView.getTop() >= 0) && mRefreshState == RELEASE_TO_REFRESH){// Initiate the refreshmRefreshState = REFRESHING;prepareForRefresh();onRefresh();} else if (mRefreshView.getBottom() < mRefreshViewHeight|| mRefreshView.getTop() <= 0){// Abort refresh and scroll down below the refresh viewresetHeader();setSelection(1);}}break;case MotionEvent.ACTION_DOWN:mLastMotionY = y;break;case MotionEvent.ACTION_MOVE:applyHeaderPadding(event);break;}return super.onTouchEvent(event);}private void applyHeaderPadding(MotionEvent ev){// getHistorySize has been available since API 1int pointerCount = ev.getHistorySize();for (int p = 0; p < pointerCount; p++){if (mRefreshState == RELEASE_TO_REFRESH){if (isVerticalFadingEdgeEnabled()){setVerticalScrollBarEnabled(false);}int historicalY = (int) ev.getHistoricalY(p);// Calculate the padding to apply, we divide by 1.7 to// simulate a more resistant effect during pull.int topPadding = (int) (((historicalY - mLastMotionY) - mRefreshViewHeight) / 1.7);mRefreshView.setPadding(mRefreshView.getPaddingLeft(),topPadding, mRefreshView.getPaddingRight(),mRefreshView.getPaddingBottom());}}}/***设置的头部填充返回到原来的大小。*/private void resetHeaderPadding(){mRefreshView.setPadding(mRefreshView.getPaddingLeft(),mRefreshOriginalTopPadding, mRefreshView.getPaddingRight(),mRefreshView.getPaddingBottom());}/*** 复位到原来的状态的标头。*/private void resetHeader(){if (mRefreshState != TAP_TO_REFRESH){mRefreshState = TAP_TO_REFRESH;resetHeaderPadding();// 将刷新视图文本拉标签mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);// Replace refresh drawable with arrow drawablemRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);//清除旋转动画mRefreshViewImage.clearAnimation();// 隐藏进度条和箭头。mRefreshViewImage.setVisibility(View.GONE);mRefreshViewProgress.setVisibility(View.GONE);}}private void measureView(View child){ViewGroup.LayoutParams p = child.getLayoutParams();if (p == null){p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);}int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);int lpHeight = p.height;int childHeightSpec;if (lpHeight > 0){childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,MeasureSpec.EXACTLY);} else{childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);}child.measure(childWidthSpec, childHeightSpec);}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount){// 当刷新的观点是完全可见的,改变的文字说:“放开刷新...”翻转的箭头绘制的。if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL&& mRefreshState != REFRESHING){if (firstVisibleItem == 0){mRefreshViewImage.setVisibility(View.VISIBLE);if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20 || mRefreshView.getTop() >= 0) && mRefreshState != RELEASE_TO_REFRESH){mRefreshViewText.setText(R.string.pull_to_refresh_release_label);mRefreshViewImage.clearAnimation();mRefreshViewImage.startAnimation(mFlipAnimation);mRefreshState = RELEASE_TO_REFRESH;} else if (mRefreshView.getBottom() < mRefreshViewHeight + 20&& mRefreshState != PULL_TO_REFRESH){mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);if (mRefreshState != TAP_TO_REFRESH){mRefreshViewImage.clearAnimation();mRefreshViewImage.startAnimation(mReverseFlipAnimation);}mRefreshState = PULL_TO_REFRESH;}} else{mRefreshViewImage.setVisibility(View.GONE);resetHeader();}} else if (mCurrentScrollState == SCROLL_STATE_FLING&& firstVisibleItem == 0 && mRefreshState != REFRESHING){setSelection(1);mBounceHack = true;} else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING){setSelection(1);}if (mOnScrollListener != null){mOnScrollListener.onScroll(view, firstVisibleItem,visibleItemCount, totalItemCount);}}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState){mCurrentScrollState = scrollState;if (mCurrentScrollState == SCROLL_STATE_IDLE){mBounceHack = false;}if (mOnScrollListener != null){mOnScrollListener.onScrollStateChanged(view, scrollState);}}public void prepareForRefresh(){resetHeaderPadding();mRefreshViewImage.setVisibility(View.GONE);// 我们需要这个技巧,否则它会保持以前的drawable。mRefreshViewImage.setImageDrawable(null);mRefreshViewProgress.setVisibility(View.VISIBLE);// 将刷新视图文本清爽的标签mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);mRefreshState = REFRESHING;}public void onRefresh(){Log.d(TAG, "onRefresh");if (mOnRefreshListener != null){mOnRefreshListener.onRefresh();}}/*** 重置列表刷新后到正常状态。* * @param lastUpdated*            Last updated at.*/public void onRefreshComplete(CharSequence lastUpdated){setLastUpdated(lastUpdated);onRefreshComplete();}/*** 重置列表刷新后到正常状态。*/public void onRefreshComplete(){Log.d(TAG, "onRefreshComplete");resetHeader();// 如果刷新视图是可见的,当加载完成,向下滚动到下一个项目。if (mRefreshView.getBottom() > 0){invalidateViews();setSelection(1);}}/*** 点击刷新视图时调用。这主要是用于当有几个项目在列表中,这是不可能的拖动列表。*/private class OnClickRefreshListener implements OnClickListener{@Overridepublic void onClick(View v){if (mRefreshState != REFRESHING){prepareForRefresh();onRefresh();}}}/***当列表被刷新的回调被调用的接口定义。*/public interface OnRefreshListener{/*** 列表被刷新时调用的* <p>* A call to {@link PullToRefreshListView #onRefreshComplete()} is* expected to indicate that the refresh has completed.*/public void onRefresh();}
}

测试代码如下:

public class PullToRefreshActivity extends ListActivity
{private LinkedList<String> mListItems;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.pull_to_refresh);// 设置一个监听器时要调用的列表被刷新。((PullToRefreshListView) getListView()).setOnRefreshListener(new OnRefreshListener(){@Overridepublic void onRefresh(){// 请刷新列表。new GetDataTask().execute();}});mListItems = new LinkedList<String>();mListItems.addAll(Arrays.asList(mStrings));ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, mListItems);setListAdapter(adapter);}private class GetDataTask extends AsyncTask<Void, Void, String[]>{@Overrideprotected String[] doInBackground(Void... params){//后台作业。try{Thread.sleep(2000);} catch (InterruptedException e){;}return mStrings;}@Overrideprotected void onPostExecute(String[] result){mListItems.addFirst("Added after refresh...");// 刷新完成((PullToRefreshListView) getListView()).onRefreshComplete();super.onPostExecute(result);}}private String[] mStrings ={ "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance","Ackawi", "Acorn", "Adelost", "Affidelice au Chablis","Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre","Allgauer Emmentaler" };
}

代码简单易懂!~~

学习的目标是成熟!~

开源项目之Android 向下刷新列表相关推荐

  1. Android 开源项目分类汇总(下)

    Android 开源项目分类汇总(下) 九.ScrollView Discrollview 支持滚动时 Item 淡入淡出,平移,缩放效果的 ScrollView 项目地址:https://githu ...

  2. Vue.JS项目中二级路由下刷新浏览器仍呈现当前路由的实现方案

    1.需求介绍: 以下介绍一下实现起来没什么疑问的需求:设备列表为一个主页,点击设备列表中的编辑按钮,进入设备信息主页面,默认打开设备配置页,点击设备状态.设备日志.固件升级,会切换下方内容. 本人对以 ...

  3. 从0到1编写个人博客项目使用springboot+vue(前后端分离) 到 购买服务器上传项目 到 GitHub开源项目、此过程下所遇问题及解决方法,至少你帮你少走70%弯路

    个人博客编写 后记 2022.12.2.4 : 30.此项目告一段落. ​ 编撰此博客本意里除去对找工作的帮助.更多地是想帮助未走过的人去探探路.总结经验.少走弯路.知识的宝贵不在于无价.而是无私.天 ...

  4. 使用ConnectBot开源项目在android设备上管理你的linux系统

    最近,工作中有使用android通过ssh管理linux系统的需求,找到了这个ConnectBot这个开源项目https://github.com/connectbot/connectbot.http ...

  5. android自定义视频列表,Github最火开源项目-高仿今日头条视频列表功能

    主要特点视频全屏播放和浮层小窗播放 可以完全自定义UI 能在ListView.ViewPager和ListView.ViewPager和Fragment等多重嵌套模式下全屏工作 手势修改进度和音量 视 ...

  6. 【开源项目】Android下自定义HASH【支持一个key对应多个value--根据key排序】

    package com.peace.love.carpo_test.tool;import java.util.List; import java.util.Map; import java.util ...

  7. 开源项目之Android繁体中文输入法

    一款功能强大的输入法,集合 "广东话.拼音.仓颉.速成"四种常用中文输入法,以及英文.数字及符号键盘,一按独立切换键即可变更.同一键盘可作中英文输入,无需切换,支持联想字功能,融合 ...

  8. 推荐GitHub上几个比较热门的开源项目,记得收藏下!!!

    来自:开源最前线(ID:OpenSourceTop)  废话少说,直接来干货 1 terminal https://github.com/microsoft/terminal Star 42377 W ...

  9. 【开源项目】Android 手写记事 App(半成品)

    该项目已上传到 CSDN 的 Git 平台中 项目地址:https://code.csdn.net/gd920129/whiteboard GIT SSH:git@code.csdn.net:gd92 ...

  10. 开源项目tpshop在windows下的部署

    一.前期需要下载的软件 (1)phpstudy,官网:https://www.xp.cn下载后直接解压安装即可 (2)Mysql和Navicat,参考博文http://t.csdn.cn/8ygS0 ...

最新文章

  1. 公钥和私钥的简单通俗说明
  2. Intel Realsense D435 pyrealsense2 get_option_range() 获取rs.option中参数值取值范围 获取默认值
  3. gc日志一般关注什么_GC日志说明
  4. OpenCV:简单计算曲线弧度-弓形弧度
  5. python asyncio理解_深入理解asyncio(二)
  6. SpringBoot集成Es使用ElasticSearchTemplate7.x版本自动注入失败解决
  7. PyTorch学习笔记——词向量简介
  8. ArrayList转换类型为DataTable类型
  9. qrect在图片上显示矩形框_Mac上用LabelImg手动标记图片
  10. c语言求婚代码大全,求一个C语言表白的代码
  11. 大话设计模式笔记(二十四)の解释器模式
  12. 优化广域网带宽,让应用加速
  13. 15岁黑客Cosmo的堕落历程
  14. 中国水产科学研究院教授黄樟翰走进伊宅购集团考察伊家田园项目
  15. python初学入门操作
  16. golang mysql 非阻塞_Golang 实现轻量、快速的基于 Reactor 模式的非阻塞 TCP 网络库...
  17. 知道创宇高级威胁情报团队:以APT测绘及APT防御应对高级威胁
  18. 互联网内容产业永远有机会
  19. linux 同步套件,为Linux安装套件强化系统安全
  20. k8s之HPA(Pod水平自动伸缩)

热门文章

  1. jQuery siblings() 方法
  2. easyui php分页,jQuery EasyUI 教程-Pagination(分页)
  3. C++语言99个常见编程错误 常见错误24:晦涩难懂的operator-
  4. 【大数据技术详解】搭建redis集群服务的步骤和配置以及解决创建集群时会遇到的错误:NodeX replied with error:ERRInvalid node address specified
  5. Redis imgrate迁移键 (error) ERR Target instance replied with error: NOAUTH Authentication required.
  6. java给pdf文件加水印
  7. 日本战国武将绰号与称号一览表
  8. 拿棱镜门黑客软件攻击“俄版百度”,不偷情报只想装大V,FBI们被抓包了
  9. 一文看尽 6篇 CVPR2021 伪装目标检测、旋转目标检测论文
  10. 深入理解机器学习——类别不平衡学习(Imbalanced Learning):常用技术概览