PullToRefreshListView

  • 自定义ListView
  • 带简洁的下拉刷新及上拉加载更多功能

  • PullToRefreshListView

    • 实现过程
    • 使用方法
    • GIF效果
    • 结束语

实现过程

  • 继承已有控件(ListView)实现自定义控件,下拉刷新三个状态效果如下:

  • 给ListView添加头部和脚部

  • 头部布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="60dp"android:gravity="center"android:orientation="horizontal"><ImageViewandroid:id="@+id/iv_arrow"android:layout_width="20dp"android:layout_height="45dp"android:layout_marginRight="20dp"android:src="@drawable/common_listview_headview_red_arrow" /><ImageViewandroid:id="@+id/iv_loading"android:layout_width="50dp"android:layout_height="50dp"android:src="@drawable/action_progress_image"android:visibility="gone" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="45dp"android:gravity="center"android:orientation="vertical"><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="25dp"android:text="下拉刷新"android:textSize="18sp" /><TextViewandroid:id="@+id/tv_time"android:layout_width="wrap_content"android:layout_height="20dp"android:text="最后刷新时间:mm:hh:ss" /></LinearLayout>
</LinearLayout>

  • 脚部布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:orientation="horizontal"><ProgressBarandroid:id="@+id/progressBar"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="玩命加载中..." />
</LinearLayout>

  • 下面贴出PullToRefreshListView完整代码,如下:
public class PullToRefreshListView extends ListView implements AbsListView.OnScrollListener {private View header;private int headerMeasuredHeight;private TextView tvTitle;private TextView tvTime;private ImageView ivArrow;private ImageView ivLoading;private RotateAnimation pullAnimaton;private RotateAnimation releaseAnimation;private RotateAnimation loadingAnimation;private onPullToRefreshListener onPullToRefreshListener;private View footer;private int footerMeasureHeight;public void setOnPullToRefreshListener(cn.com.bsoft.pulltorefreshlistview.view.onPullToRefreshListener onPullToRefreshListener) {this.onPullToRefreshListener = onPullToRefreshListener;}public PullToRefreshListView(Context context) {this(context, null);}public PullToRefreshListView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public PullToRefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);//给ListView添加头initHeader();initFooter();}private void initFooter() {footer = View.inflate(getContext(), R.layout.footer_view, null);footer.measure(0, 0);footerMeasureHeight = footer.getMeasuredHeight();footer.setPadding(0, -footerMeasureHeight, 0, 0);addFooterView(footer);setOnScrollListener(this);}private void initHeader() {header = View.inflate(getContext(), R.layout.header_view, null);header.measure(0, 0);//还运行在构造函数,此时不能直接获取header的高度,所以要调用测量,再获取header高度headerMeasuredHeight = header.getMeasuredHeight();header.setPadding(0, -headerMeasuredHeight, 0, 0);addHeaderView(header);tvTitle = ((TextView) header.findViewById(R.id.tv_title));tvTime = ((TextView) header.findViewById(R.id.tv_time));ivArrow = ((ImageView) header.findViewById(R.id.iv_arrow));ivLoading = ((ImageView) header.findViewById(R.id.iv_loading));//释放刷新动画releaseAnimation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);releaseAnimation.setDuration(300);releaseAnimation.setFillAfter(true);//动画完成后停在那//下拉动画pullAnimaton = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);pullAnimaton.setDuration(300);pullAnimaton.setFillAfter(true);//正在刷新动画loadingAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);loadingAnimation.setDuration(300);loadingAnimation.setRepeatCount(Animation.INFINITE);loadingAnimation.setInterpolator(new LinearInterpolator());//设置匀速的动画插入器loadingAnimation.setFillAfter(true);}private int downY;@Overridepublic boolean onTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:downY = (int) ev.getY();break;case MotionEvent.ACTION_MOVE:int moveY = (int) ev.getY();int dy = moveY - downY;downY = moveY;int headerPaddingTop = header.getPaddingTop();//1.判断当前完全显示的条目是不是listview的第一个条目//2.判断滑动的状态.向下滑显示listview  向上滑隐藏listviewif (state != State.REFRESHING && getFirstVisiblePosition() == 0 && (dy > 0 || headerPaddingTop > -headerMeasuredHeight)) {headerPaddingTop += dy;header.setPadding(0, headerPaddingTop, 0, 0);if (headerPaddingTop >= 0) {setState(State.RELEASE_TO_REFRESH);} else {setState(State.PULL_TO_REFRESH);}return true;}break;case MotionEvent.ACTION_UP://还原头部resetHeader();break;default:break;}return super.onTouchEvent(ev);}private void resetHeader() {if (state == State.PULL_TO_REFRESH) {//抬起手时  处于下拉刷新状态header.setPadding(0, -headerMeasuredHeight, 0, 0);} else if (state == State.RELEASE_TO_REFRESH) {//抬起手时  处于释放刷新状态//进入正在刷新状态header.setPadding(0, 0, 0, 0);setState(State.REFRESHING);if (onPullToRefreshListener != null) {onPullToRefreshListener.onRefresh();}}}private boolean isLoading = false;@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {int count = view.getAdapter().getCount();if (scrollState == OnScrollListener.SCROLL_STATE_IDLE&& getLastVisiblePosition() == count - 1&& isLoading == false) {isLoading = true;footer.setPadding(0, 0, 0, 0);setSelection(count - 1);//加载更多数据if (onPullToRefreshListener==null) {onPullToRefreshListener.loadMore();}}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}private enum State {RELEASE_TO_REFRESH, PULL_TO_REFRESH, REFRESHING, START}private State state = State.START;/*** 设置listview当前状态* @param state*/private void setState(State state) {if (this.state != state) {if (state == State.RELEASE_TO_REFRESH) {//释放刷新tvTitle.setText("释放刷新");ivArrow.setAnimation(releaseAnimation);} else if (state == State.PULL_TO_REFRESH) {tvTitle.setText("下拉刷新");ivArrow.setAnimation(pullAnimaton);} else if (state == State.REFRESHING) {tvTitle.setText("正在刷新");ivArrow.setVisibility(View.GONE);ivArrow.clearAnimation();ivLoading.setVisibility(View.VISIBLE);ivLoading.setAnimation(loadingAnimation);java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("hh:mm:ss");String date = dateFormat.format(new Date());tvTime.setText(date);}this.state = state;}}//刷新完成public void completeRefresh() {ivLoading.clearAnimation();ivLoading.setVisibility(View.GONE);ivArrow.setVisibility(View.VISIBLE);setState(State.PULL_TO_REFRESH);header.setPadding(0, -headerMeasuredHeight, 0, 0);}//加载完成public void completeLoadMore(){isLoading=false;footer.setPadding(0,-footerMeasureHeight,0,0);}
}
  • 接口实现:onPullToRefreshListener
public interface onPullToRefreshListener {public void onRefresh();public void loadMore();
}

使用方法

  • 1.布局中直接引用PullToRefreshListView即可
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="cn.com.bsoft.pulltorefreshlistview.activity.MainActivity"><cn.com.bsoft.pulltorefreshlistview.view.PullToRefreshListViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/ptr_listview" />
</RelativeLayout>
  • 2.在界面中找到控件传入接口即可:setOnPullToRefreshListener
public class MainActivity extends AppCompatActivity {private PullToRefreshListView pullToRefreshListView;private ArrayAdapter<String> adapter;private List<String> dataList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);pullToRefreshListView = ((PullToRefreshListView) findViewById(R.id.ptr_listview));List<String> datas = getDatas();adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, datas);pullToRefreshListView.setAdapter(adapter);//设置回调监听pullToRefreshListView.setOnPullToRefreshListener(new onPullToRefreshListener() {//下拉刷新的回调@Overridepublic void onRefresh() {//模拟获取数据new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}final String addData = "弱水三千只取一瓢";//刷新适配器在主线程runOnUiThread(new Runnable() {@Overridepublic void run() {dataList.add(0, addData);adapter.notifyDataSetChanged();//数据获取完之后调用completeRefresh()方法pullToRefreshListView.completeRefresh();}});}}).start();}//上拉加载更多的回调@Overridepublic void loadMore() {//模拟获取数据new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}final String addData = "一点寒芒先到  随后枪出如龙";runOnUiThread(new Runnable() {@Overridepublic void run() {dataList.add(0, addData);adapter.notifyDataSetChanged();//数据获取完之后调用completeLoadMore()方法pullToRefreshListView.completeLoadMore();}});}}).start();}});}public List<String> getDatas() {dataList = new ArrayList<>();for (int i = 0; i < 20; i++) {dataList.add("最怕一生碌碌无为,却安慰自己说说平凡可贵!");}return dataList;}
}

GIF效果

结束语

  • 第一次玩GIF图,花了半小时还没处理好,上拉加载更多的数据还没出来就结束了。
  • 另外也是第一次使用Markdown编辑器,还不熟练。
  • 以上就是非常简洁的下拉刷新及上拉加载更多的ListView。
  • 不敢跟各种大神的自定义控件做比较,贴出来作为自己学习的小结把,当然,能帮到初学Android的新人那就更好了。

下拉刷新及上拉加载更多的ListView相关推荐

  1. jquery手机端页面下拉刷新,上划加载更多

    手机页面下拉刷新,上划加载更多,IOS不能下拉的问题解决 -转圈的是需要引用样式,代码删除了 上划加载时的样子 <script type="text/javascript"& ...

  2. 微信小程序04---头像上传、瀑布流、下拉刷新、触底加载更多、分包

    目录 一.头像上传 1.选择图片   wx.chooseImage() 2.上传文件   wx.uploadFile() 二.瀑布流+下拉刷新+触底加载 三.分包加载 什么是分包 为什么要使用分包 如 ...

  3. 【Android开源控件】SmartRefreshLayout实现下拉刷新,上划加载

  4. Flutter 21: 图解 ListView 下拉刷新与上拉加载 (三)【RefreshIndicator】

    小菜前段时间整理了两种 ListView 的异步加载数据时,下拉刷新与上滑加载更多的方式,每种方式都有自己的优势,网上也有很多大神讲解过 ListView 数据流的种种处理方式,小菜根据实际遇到的情况 ...

  5. 安卓下拉刷新、上拉加载数据显示

    整个是一个scrollView,嵌套一个线性布局,下拉刷新.或者上拉加载后,通过addView()方法,加载消息体,每一个消息体是一个复杂的子view. 做一个类似qq客户端"好友动态&qu ...

  6. Flutter ListView封装,下拉刷新、上拉加载更多

    Flutter ListView封装,下拉刷新.上拉加载更多 ​ 封装了Flutter的ListView,只要传递请求数据的方法和绘制item的方法进去就可以绘制ListView,同时支持下拉刷新.上 ...

  7. 使用MUI框架,模拟手机端的下拉刷新,上拉加载操作。

    套用mui官方文档的一句话:"开发者只需关心业务逻辑,实现加载更多数据即可".真的是不错的框架. 想更多的了解这个框架:http://dev.dcloud.net.cn/mui/ ...

  8. vue使用better-scroll实现下拉刷新、上拉加载

    本文目的是为了实现列表的下拉刷新.上拉加载,所以选择了better-scroll这个库. 用好这个库,需要理解下面说明 必须包含两个大的div,外层和内层div 外层div设置可视的大小(宽或者高)- ...

  9. vue better-scroll 使用 下拉刷新、上拉加载

    我的目的是为了实现列表的下拉刷新.上拉加载,所以选择了better-scroll这个库. 用好这个库,需要理解下面说明 必须包含两个大的div,外层和内层div 外层div设置可视的大小(宽或者高)- ...

  10. vant实现下拉刷新和上拉加载_微信小程序 - 实现下拉刷新、上拉加载

    在小程序开发中使用下拉刷新和上拉加载非常多,比如常用的展示型首页,而实现这个功能有两种形式,第一种是使用 scroll-view 组件,第二种是不使用 scroll-view 组件而让整个页面刷新,那 ...

最新文章

  1. MySql忘记密码了咋办
  2. GridView自定义分页导航
  3. 原创 | CRUD更要知道的Spring事务传播机制
  4. Android Tcp操作
  5. 解决Windows7 Embedded连接手机问题
  6. 滴滴算法大赛算法解决过程 - 拟合算法
  7. 算法(伪代码)的书写
  8. .net中使用XPath语言在xml中判断是否存在节点值的方法
  9. 最新QQ邮箱滑块JS逆向教程
  10. ArcGIS Pro 性能诊断
  11. 到底工资要多少合适?
  12. 易语言 html 替换全角 半角,易语言全角与半角转换的使用讲解
  13. 电脑键盘部分按键失灵_Win7系统键盘部分按键失灵了怎么办?
  14. iOS——百度地图点击标注事件
  15. 导出excel合并单元格
  16. 人工智能研究中心快递柜——代码分析十一
  17. 程序员简历模版【A4纸正反两面】(20220511)
  18. 中级软件设计师简要知识点(5):网络与多媒体基础知识
  19. autojs免root脚本引擎编写的QQ空间点赞脚本源码
  20. AES实现加解密-Java

热门文章

  1. 【算法分析】实验 1. 基于贪心的会议安排问题
  2. android 自定义方形章,Android自定义View-圆形印章
  3. sql语句:简写拼音查询
  4. luffcc项目-11-购物车实现,切换有效期选项、购物车商品的删除操作,结算页面,订单的生成
  5. java mysql物联网土壤智能监控web前端+java后台+数据接程序
  6. xcpc网络赛个人总结(文笔不好,纯纯记录)
  7. win11升级后黑屏问题
  8. Java开发面试(持续更新)
  9. torch.bmm 函数
  10. JavaScript网页购物车