一、先写头布局view文件:

<?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:orientation="horizontal" ><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="10dp" >
1、箭头:<ImageViewandroid:id="@+id/iv_arr"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:src="@drawable/common_listview_headview_red_arrow" />
2、进度条圆圈(隐藏):<ProgressBarandroid:id="@+id/pb_progress"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:indeterminateDrawable="@drawable/custom_progress"android:visibility="invisible" /></FrameLayout>
3、下拉刷新的文字:<LinearLayoutandroid:layout_width="wrap_content"android:layout_height="match_parent"android:layout_gravity="center"android:gravity="center"android:orientation="vertical" ><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="下拉刷新"android:textColor="#f00"android:textSize="16sp" /><TextViewandroid:id="@+id/tv_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:text="最后刷新时间:2015-03-10 17:07:07"android:textColor="@android:color/darker_gray"android:textSize="14sp" /></LinearLayout>
</LinearLayout>

二、自定义刷新时候的圆环

必须在progressbar里面设置android:indeterminateDrawable才能定义自己想要的环形
<ProgressBarandroid:id="@+id/pb_progress"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:indeterminateDrawable="@drawable/custom_progress"android:visibility="invisible" />
custom_progress.xml外面是旋转动画,里面套一个自定义shape
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"android:fromDegrees="0"android:pivotX="50%"android:pivotY="50%"android:toDegrees="360" ><shapeandroid:innerRadius="12dp"android:shape="ring"android:thickness="3dp"android:useLevel="false" > 这个让环形变成圆圈,缺点是让原来的旋转动画消失了,所以要在外面套上一层自定义旋转动画<gradientandroid:centerColor="#3f00"android:endColor="#f00"android:startColor="#fff" /></shape>
</rotate>

三、自定义的ListView

public class RefreshListView extends ListView implements OnScrollListener,android.widget.AdapterView.OnItemClickListener {
//首先定义三种状态private static final int STATE_PULL_REFRESH = 0;// 下拉刷新private static final int STATE_RELEASE_REFRESH = 1;// 松开刷新private static final int STATE_REFRESHING = 2;// 正在刷新private View mHeaderView;private int startY = -1;// 滑动起点的y坐标private int mHeaderViewHeight;private int mCurrrentState = STATE_PULL_REFRESH;// 当前状态private TextView tvTitle;private TextView tvTime;private ImageView ivArrow;private ProgressBar pbProgress;private RotateAnimation animUp;private RotateAnimation animDown;public RefreshListView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initHeaderView(); //初始化头部viewinitFooterView(); //初始化尾部view}public RefreshListView(Context context, AttributeSet attrs) {super(context, attrs);initHeaderView();initFooterView();}public RefreshListView(Context context) {super(context);initHeaderView();initFooterView();}/*** 第一步!初始化头布局*/private void initHeaderView() {//1、找到头布局viewmHeaderView = View.inflate(getContext(), R.layout.refresh_header, null); //2、添加这个头布局到当前这个自定义ListView的头部this.addHeaderView(mHeaderView);tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);ivArrow = (ImageView) mHeaderView.findViewById(R.id.iv_arr);pbProgress = (ProgressBar) mHeaderView.findViewById(R.id.pb_progress);//3、测量这个头布局,得到头布局view的高度mHeaderView.measure(0, 0);mHeaderViewHeight = mHeaderView.getMeasuredHeight();//4、根据刚刚测量到的头布局高度,隐藏头布局mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);//5、先定义好动画,等到需要的时候再用initArrowAnim();//6、getCurrentTime:获取当前时间tvTime.setText("最后刷新时间:" + getCurrentTime());}/** 初始化脚布局*/private void initFooterView() {mFooterView = View.inflate(getContext(),R.layout.refresh_listview_footer, null);this.addFooterView(mFooterView);mFooterView.measure(0, 0);mFooterViewHeight = mFooterView.getMeasuredHeight();mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏this.setOnScrollListener(this);}//二、触摸事件@Overridepublic boolean onTouchEvent(MotionEvent ev) {switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN://6、得到落地坐标startY = (int) ev.getRawY();break;
case MotionEvent.ACTION_MOVE://7、 确保startY有效,其实没什么用      if (startY == -1) {startY = (int) ev.getRawY();}//8、 正在刷新时不做处理if (mCurrrentState == STATE_REFRESHING) {break;}//9、得到移动的时候的即时坐标int endY = (int) ev.getRawY();//10、得到移动偏移量int dy = endY - startY;//11、只有是下拉并且当前是第一个item,才允许下拉if (dy > 0 && getFirstVisiblePosition() == 0) {//12、计算paddingint padding = dy - mHeaderViewHeight;//13、设置当前头部view的paddingmHeaderView.setPadding(0, padding, 0, 0);//14、如果padding=0,表示整个头布局已经显示出来了,而且当前的状态不是松开刷新状态,此时要改变状态为松开刷新if (padding > 0 && mCurrrentState != STATE_RELEASE_REFRESH) {//15、状态改为松开刷新mCurrrentState = STATE_RELEASE_REFRESH;//16、根据当前状态改变view布局refreshState();//17、elseif padding小于0,代表没完全拉出来,而且不等于下拉刷新状态} else if (padding < 0 && mCurrrentState != STATE_PULL_REFRESH) {//18、改为下拉刷新状态mCurrrentState = STATE_PULL_REFRESH;//19、根据当前状态改变view布局refreshState();}//只有是下拉并且当前是第一个item,才允许自己处理return true;}break;
case MotionEvent.ACTION_UP:startY = -1;// 重置//20、若松开手的时候是松开刷新状态,将状态变成正在刷新状态if (mCurrrentState == STATE_RELEASE_REFRESH) {mCurrrentState = STATE_REFRESHING;// 正在刷新//21、把padding设置成0,完全显示头部viewmHeaderView.setPadding(0, 0, 0, 0);// 显示//22、根据当前状态更改头布局viewrefreshState();//23、如果松开手时还是下拉刷新状态,恢复隐藏的位置} else if (mCurrrentState == STATE_PULL_REFRESH) {mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏}break;default:break;}return super.onTouchEvent(ev);}/*** 根据状态修改头布局view*/private void refreshState() {switch (mCurrrentState) {case STATE_PULL_REFRESH:tvTitle.setText("下拉刷新");ivArrow.setVisibility(View.VISIBLE);pbProgress.setVisibility(View.INVISIBLE);//设置箭头转向动画ivArrow.startAnimation(animDown);break;case STATE_RELEASE_REFRESH:tvTitle.setText("松开刷新");ivArrow.setVisibility(View.VISIBLE);pbProgress.setVisibility(View.INVISIBLE);ivArrow.startAnimation(animUp);break;case STATE_REFRESHING:tvTitle.setText("正在刷新...");// 必须先清除动画,才能隐藏ivArrow.clearAnimation();ivArrow.setVisibility(View.INVISIBLE);pbProgress.setVisibility(View.VISIBLE);//24、当状态为正在刷新时,检测是否实现了监听回调,若有,调用接口方法,实现回调if (mListener != null) {mListener.onRefresh();//告诉调用者,正在刷新状态呢,快点请求网络吧}break;default:break;}}/*** 初始化箭头动画*/private void initArrowAnim() {// 箭头向上动画animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 0.5f);animUp.setDuration(200);animUp.setFillAfter(true);// 箭头向下动画animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animDown.setDuration(200);animDown.setFillAfter(true);}private View mFooterView;private int mFooterViewHeight;//25、写一个接口传递消息给外部OnRefreshListener mListener;public void setOnRefreshListener(OnRefreshListener listener) {mListener = listener;}public interface OnRefreshListener {public void onRefresh();public void onLoadMore();// 加载下一页数据}/**26、 当外部数据成功获取或失败之后,调用此方法隐藏头/尾布局*/public void onRefreshComplete(boolean success) {if (isLoadingMore) {// 正在加载更多...mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏脚布局isLoadingMore = false;} else {mCurrrentState = STATE_PULL_REFRESH;tvTitle.setText("下拉刷新");ivArrow.setVisibility(View.VISIBLE);pbProgress.setVisibility(View.INVISIBLE);mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏//如果成功了才更新时间if (success) {tvTime.setText("最后刷新时间:" + getCurrentTime());}}}/*** 获取当前时间*/public String getCurrentTime() {SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return format.format(new Date());}private boolean isLoadingMore;!!! 上拉刷新就implements OnScrollListener,实现未实现的方法:@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if (scrollState == SCROLL_STATE_IDLE|| scrollState == SCROLL_STATE_FLING) {//当滑动的状态是 fling或者空闲状态时,而且getLastVisiblePosition() == getCount() - 1,并且又不是LoadingMore状态,显示尾部布局,改变listview显示位置,设置isLoadingMore = true,最后实现接口回调,请求网络if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {           // 滑动到最后System.out.println("到底了.....");mFooterView.setPadding(0, 0, 0, 0);// 显示setSelection(getCount() - 1);// 改变listview显示位置isLoadingMore = true;if (mListener != null) {mListener.onLoadMore();}}}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {}OnItemClickListener mItemClickListener;@Overridepublic void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener listener) {super.setOnItemClickListener(this);mItemClickListener = listener;}@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {if (mItemClickListener != null) {mItemClickListener.onItemClick(parent, view, position- getHeaderViewsCount(), id);}}
}
  • 上拉加载更多:
一、在initData时,得到缓存数据,
1、假如有缓存数据,则调用parseData(cache, false)解析result,得到“more”,保存下一页地址,然后判断是否加载更多,如果不是的话就把获取到的数据展示在ListView上,若是加载更多,则从原来的集合上追加数据,再notifyDataSetChanged();
  2、假如没有缓存数据,则通过请求地址getDataFromServer()网络获取数据,获取成功再解析(parseData)数据,隐藏下拉刷新框,保存result;获取失败则提示吐司,并隐藏下拉刷新框:
public void initData() {
String cache = CacheUtils.getCache(mUrl, mActivity);if (!TextUtils.isEmpty(cache)) {parseData(cache, false);}getDataFromServer();
二、给ListView设置监听事件
//在initView()时,ListView设置的下拉刷新监听回调
lvList.setOnRefreshListener(new OnRefreshListener() {
//当下拉刷新时,会自动回调此函数加载网络数据 
@Override
public void onRefresh() {
getDataFromServer();
}
//当上拉加载时,若mMoreUrl不为空,调用加载更多数据方法 
@Override
public void onLoadMore() {
if (mMoreUrl != null) {
getMoreDataFromServer();
} else {
//若mMoreUrl为空,那就是没有下一页了,则应该收起加载更多的布局
Toast.makeText(mActivity, "最后一页了", Toast.LENGTH_SHORT)
.show();
lvList.onRefreshComplete(false);// 收起加载更多的布局
}
}
});

三、网络获取数据
private void getDataFromServer() {
HttpUtils utils = new HttpUtils();
utils.send(HttpMethod.GET, mUrl, new RequestCallBack<String>() {
 
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
String result = (String) responseInfo.result;
System.out.println("页签详情页返回结果:" + result);
 
parseData(result, false);
//调用ListView的方法,通知ListView隐藏刷新头view 
lvList.onRefreshComplete(true);
 
// 设置缓存
CacheUtils.setCache(mUrl, result, mActivity);
}
 
@Override
public void onFailure(HttpException error, String msg) {
Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
error.printStackTrace();
 
lvList.onRefreshComplete(false);
}
});
}

四、网络获取更多(下一页)数据

private void getMoreDataFromServer() {
HttpUtils utils = new HttpUtils();
utils.send(HttpMethod.GET, mMoreUrl, new RequestCallBack<String>() {
 
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
String result = (String) responseInfo.result;
 
parseData(result, true);
 
lvList.onRefreshComplete(true);
}
 
@Override
public void onFailure(HttpException error, String msg) {
Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
error.printStackTrace();
lvList.onRefreshComplete(false);
}
});
}

五、解析result数据:
protected void parseData(String result, boolean isMore) {
Gson gson = new Gson();
mTabDetailData = gson.fromJson(result, TabData.class);
System.out.println("页签详情解析:" + mTabDetailData);
 
//1、在得到数据之后,解析数据,得到“more”中的地址
String more = mTabDetailData.data.more;
//2、若“more”不为空,则拼接下一页的链接地址,赋值给mMoreUrl
if (!TextUtils.isEmpty(more)) {
mMoreUrl = GlobalContants.SERVER_URL + more;
} else {
//3、否则没有下一页
mMoreUrl = null;
}
//4、如果不是加载更多,是刷新页面,则ArrayList<TabNewsData> mNewsList(新闻数据集合)= 新获取到的数据 
if (!isMore)
{
//5、给集合重新赋值,刷新界面
mNewsList = mTabDetailData.data.news;

 
if (mNewsList != null) {
mNewsAdapter = new NewsAdapter();
lvList.setAdapter(mNewsAdapter);
}
} else { 
//6、如果是加载下一页,需要将数据追加给原来的集合
ArrayList<TabNewsData> news = mTabDetailData.data.news;
mNewsList.addAll(news);
mNewsAdapter.notifyDataSetChanged();
}
}

ListView的下拉刷新和上拉加载相关推荐

  1. android--------自定义控件ListView实现下拉刷新和上拉加载

    开发项目过程中基本都会用到listView的下拉刷新和上滑加载更多,为了方便重写的ListView来实现下拉刷新,同时添加了上拉自动加载更多的功能. Android下拉刷新可以分为两种情况: 1.获取 ...

  2. Flutter如何实现下拉刷新和上拉加载更多

    效果 下拉刷新 如果实现下拉刷新,必须借助RefreshIndicator,在listview外面包裹一层RefreshIndicator,然后在RefreshIndicator里面实现onRefre ...

  3. Android下拉刷新和上拉加载更多

    Android下拉刷新和上拉加载更多 下拉刷新 通过android系统提供的组件:SwipeRefreshLayout 一.基本使用 1 xml中 添加 SwipeRefreshLayout 组件 该 ...

  4. 使用SwipeRefreshLayout和RecyclerView实现仿“简书”下拉刷新和上拉加载更多

    原文地址: http://blog.csdn.net/leoleohan/article/details/50989549/ 一.概述 我们公司目前开发的所有Android APP都是遵循iOS风格设 ...

  5. android pulldown view,Android控件PullRefreshViewGroup实现下拉刷新和上拉加载

    本文实例为大家分享了Android实现下拉刷新和上拉加载更多的具体代码,供大家参考,具体内容如下 先分享下源码:Android实现下拉刷新和上拉加载更多 实现思路:由PullRefreshViewGr ...

  6. 微信小程序下拉刷新和上拉加载

    效果图 微信小程序实现下拉刷新和上拉加载有2中方法 1 用系统自带的 个人感觉特别简单 2 使用scroll-view  实现, scroll-view 里面有2个属性是滑动到顶部以及到底部如下 其实 ...

  7. php mescroll,mescroll下拉刷新和上拉加载js框架

    插件描述:mescroll精致的下拉刷新和上拉加载js框架.原生js, 支持vue, 不依赖jquery, zepto, 比iScroll,dropload精简强大; 一套代码多端运行: 完美运行于a ...

  8. 【好程序员笔记分享】——下拉刷新和上拉加载更多

    -iOS培训,iOS学习-------型技术博客.期待与您交流!------------ iOS学习之路--下拉刷新和上拉加载更多 简介 本文中笔者将和大家分享应用app中常用到的表单内容的下拉刷新和 ...

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

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

  10. 入门微信小程序(含实战) [第九篇] -- 下拉刷新和上拉加载

    下拉刷新和上拉加载是两个独立又密切联系的功能,上拉加载需要服务器端有分页机制,而下拉刷新除了重新获取信息外还要对之前的状态和页码进行初始化. 一个一个来吧. 服务器端分页 其实yii2早就已经为我们准 ...

最新文章

  1. 分类算法:决策树(C4.5)
  2. crontab定时任务运行
  3. 2017前端资源汇总
  4. 浅谈编程-----非计算机专业以及非培训班的一些感悟
  5. AndroidStudio安卓原生开发_UI控件_SeekBar_ProgressBar_DataPicker---Android原生开发工作笔记99
  6. 腾讯信息流推荐业务实践:内容分发场景的多目标架构实践
  7. Keras中RNN、LSTM、GRU等输入形状batch_input_shape=(batch_size,time_steps,input_dim)及TimeseriesGenerator详解
  8. TCP连接的建立和断开
  9. 想买个这样的笔记本电脑
  10. arduino学习系列——DHT11温湿度传感器的使用
  11. [ZT]硬盘整数分区计算方法
  12. mac系统的UTF-8 BOM编码
  13. 基于JSP+Servlet+MySQL的在线问卷调查系统(附论文)
  14. 破解大众点评 css加密
  15. Winform(XtraReport)实现打印方法(转载)
  16. 简记_PSpice仿真软件学习笔记(二)
  17. 报表中的地图怎么做?
  18. 微信分享到朋友圈的链接没有图片。开发工具中正常没有报错-解决方案
  19. 2022年苹果开发者账号/AppleID如何更改绑定的手机号
  20. 信号量 - linux内核锁(三)

热门文章

  1. duilib加载资源
  2. BT656协议讲解与解码
  3. css字体居中(css字体居中对齐)
  4. 手机卫星定位系统_真的可以通过手机号码,准确定位对方信息吗?
  5. 美丽炫酷的Html5简历网页模板
  6. Linux E: 无法定位软件包
  7. webpack搭建react脚手架
  8. QTreeView节点拖放
  9. 微信小程序之input前加图标
  10. Reflex WMS入门系列三十七:三种不同风格的RF界面