教你自定义ListView实现下拉刷新,上拉加载更多
2016-10-13 11:56
441 查看
虽然listview 快被RecyclerView取代了,但作为新人的你有必要知道。网上其实已经有很多关于listview上下拉刷新的例子,今天想带大家写一个快速实现 并且简单例子。
我先上几张效果图吧
![](https://img-blog.csdn.net/20161013115624894)
![](https://img-blog.csdn.net/20161013115647238)
![](https://img-blog.csdn.net/20161013115704426)
![](https://img-blog.csdn.net/20161013115736117)
ok 我先说一下大体思路,
我们先分别写出头布局和脚布局,稍后用 addHeaderView(headView); addFootView(footView);加载到自定义的布局中,默认全部都隐藏
根据我们下滑的状态,来分别对应显示下拉 和上拉刷新的状态
在自定义的listiview,中设置回调 用于状态显示完之后数据的显示
我把主要的代码列出来
欢迎入我的qq群 讨论 312327703
附上源码点击可下载
我先上几张效果图吧
ok 我先说一下大体思路,
我们先分别写出头布局和脚布局,稍后用 addHeaderView(headView); addFootView(footView);加载到自定义的布局中,默认全部都隐藏
根据我们下滑的状态,来分别对应显示下拉 和上拉刷新的状态
在自定义的listiview,中设置回调 用于状态显示完之后数据的显示
我把主要的代码列出来
package com.example.administrator.listview_demo; import android.annotation.TargetApi; import android.content.Context; import android.icu.text.SimpleDateFormat; import android.os.Build; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.animation.Animation; import android.view.animation.RotateAnimation; import android.widget.AbsListView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; /** * Created by Xavier on 2016/9/27. */ public class RefreshListView extends ListView implements AbsListView.OnScrollListener{ private View footView; private View headView; private float downY; // 按下的y坐标 private float moveY; // 移动后的y坐标 private View mArrowView; // 箭头布局 private TextView mTitleText; // 头布局标题 private ProgressBar pb; // 进度指示器 private TextView mLastRefreshTime; // 最后刷新时间 private Context mContext; private int measuredHeighthead; //头布局高度 private int measuredHeightfoot; //脚布局 private RotateAnimation rotateUpAnim; // 箭头向上动画 private RotateAnimation rotateDownAnim; // 箭头向下动画 public static final int PULL_TO_REFRESH = 0;// 下拉刷新 public static final int RELEASE_REFRESH = 1;// 释放刷新 public static final int REFRESHING = 2; // 刷新中 private int currentState = PULL_TO_REFRESH; // 当前刷新模式 private boolean isLoadingMore; // 是否正在加载更多 private OnRefreshListener mListener; // 刷新监听 public RefreshListView(Context context) { this(context,null); } public RefreshListView(Context context, AttributeSet attrs) { this(context, attrs,0); } public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext=context; init(); } private void init() { initAnimation(); initHead(); initFoot(); setOnScrollListener(this); } private void initHead() { headView = View.inflate(mContext, R.layout.layout_header_list, null); mArrowView = headView.findViewById(R.id.iv_arrow); pb = (ProgressBar) headView.findViewById(R.id.pb); mTitleText = (TextView) headView.findViewById(R.id.tv_title); mLastRefreshTime = (TextView) headView.findViewById(R.id.tv_desc_last_refresh); headView.measure(0,0); measuredHeighthead = headView.getMeasuredHeight(); headView.setPadding(0,-measuredHeighthead,0,0); addHeaderView(headView); } private void initFoot() { footView = View.inflate(mContext, R.layout.layout_footer_list, null); footView.measure(0,0); measuredHeightfoot = footView.getMeasuredHeight(); footView.setPadding(0,-measuredHeightfoot,0,0); addFooterView(footView); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: downY=ev.getY(); break; case MotionEvent.ACTION_MOVE: moveY=ev.getY(); if(currentState == REFRESHING){ return super.onTouchEvent(ev); } float offset = moveY - downY; // 移动的偏移量 if(offset > 0 && getFirstVisiblePosition() == 0){ //int paddingTop = -自身高度 + 偏移量 int paddingTop = (int) (- measuredHeighthead + offset); headView.setPadding(0, paddingTop, 0, 0); if(paddingTop >= 0 && currentState != RELEASE_REFRESH){// 头布局完全显示 System.out.println("切换成释放刷新模式: " + paddingTop); // 切换成释放刷新模式 currentState = RELEASE_REFRESH; updateHeader(); // 根据最新的状态值更新头布局内容 }else if(paddingTop < 0 && currentState != PULL_TO_REFRESH){ // 头布局不完全显示 System.out.println("切换成下拉刷新模式: " + paddingTop); // 切换成下拉刷新模式 currentState = PULL_TO_REFRESH; updateHeader(); // 根据最新的状态值更新头布局内容 } return true; } break; case MotionEvent.ACTION_UP: // 根据刚刚设置状态 if(currentState == PULL_TO_REFRESH){ // - paddingTop < 0 不完全显示, 恢复 headView.setPadding(0, -measuredHeighthead, 0, 0); }else if(currentState == RELEASE_REFRESH) { // - paddingTop >= 0 完全显示, 执行正在刷新... headView.setPadding(0, 0, 0, 0); currentState = REFRESHING; updateHeader(); } break; default: break; } return super.onTouchEvent(ev); } /** * 根据状态更新头布局内容 */ private void updateHeader() { switch (currentState) { case PULL_TO_REFRESH: // 切换回下拉刷新 // 做动画, 改标题 mArrowView.startAnimation(rotateDownAnim); mTitleText.setText("下拉刷新"); break; case RELEASE_REFRESH: // 切换成释放刷新 // 做动画, 改标题 mArrowView.startAnimation(rotateUpAnim); mTitleText.setText("释放刷新"); break; case REFRESHING: // 刷新中... mArrowView.clearAnimation(); mArrowView.setVisibility(View.INVISIBLE); pb.setVisibility(View.VISIBLE); mTitleText.setText("正在刷新中..."); if(mListener != null){ mListener.onRefresh(); // 通知调用者, 让其到网络加载更多数据. } break; default: break; } } /** * 初始化头布局的动画 */ private void initAnimation() { // 向上转, 围绕着自己的中心, 逆时针旋转0 -> -180. rotateUpAnim = new RotateAnimation(0f, -180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateUpAnim.setDuration(300); rotateUpAnim.setFillAfter(true); // 动画停留在结束位置 // 向下转, 围绕着自己的中心, 逆时针旋转 -180 -> -360 rotateDownAnim = new RotateAnimation(-180f, -360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateDownAnim.setDuration(300); rotateDownAnim.setFillAfter(true); // 动画停留在结束位置 } @TargetApi(Build.VERSION_CODES.N) private String getTime() { long currentTimeMillis = System.currentTimeMillis(); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return format.format(currentTimeMillis); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // 最新状态是空闲状态, 并且当前界面显示了所有数据的最后一条. 加载更多 if(isLoadingMore){ return; // 已经在加载更多.返回 } if(scrollState == SCROLL_STATE_IDLE && getLastVisiblePosition() >= (getCount() - 1)){ isLoadingMore = true; System.out.println("scrollState: 开始加载更多"); footView.setPadding(0, 0, 0, 0); setSelection(getCount()); // 跳转到最后一条, 使其显示出加载更多. if(mListener != null){ mListener.onLoadMore(); } } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } public interface OnRefreshListener{ void onRefresh(); // 下拉刷新 void onLoadMore();// 加载更多 } public void setRefreshListener(OnRefreshListener mListener) { this.mListener = mListener; } /** * 刷新结束, 恢复界面效果 */ public void onRefreshComplete() { if(isLoadingMore){ // 加载更多 footView.setPadding(0, -measuredHeightfoot, 0, 0); isLoadingMore = false; }else { // 下拉刷新 currentState = PULL_TO_REFRESH; mTitleText.setText("下拉刷新"); // 切换文本 headView.setPadding(0, -measuredHeighthead, 0, 0);// 隐藏头布局 pb.setVisibility(View.INVISIBLE); mArrowView.setVisibility(View.VISIBLE); String time = getTime(); mLastRefreshTime.setText("最后刷新时间: " + time); } } }
欢迎入我的qq群 讨论 312327703
附上源码点击可下载
相关文章推荐
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- 使用SwipeRefreshLayout和自定义listview实现下拉刷新上啦加载更多
- Android中自定义ListView实现上拉加载更多和下拉刷新
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- 使用SwipeRefreshLayout和自定义的PullToReFreshListView实现下拉刷新和上拉加载更多
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI自定义ListView实现下拉刷新和加载更多效果
- 自定义ListView实现下拉刷新,上拉加载更多
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- ListView实现下拉刷新和上拉加载更多时遇到的诸多问题与解析
- android ListView的上部下拉刷新下部点击加载更多具体实现及拓展
- android ListView的上部下拉刷新下部点击加载更多具体实现及拓展
- Android scrollview中嵌套listview实现listview的下拉刷新上拉加载更多
- android ListView上拉加载更多 下拉刷新功能实现(采用pull-to-refresh)