仿照SingleLayoutListView.java代码,并完全重写,加上自己的代码风格,优化逻辑,添加了刷新完成头部隐藏动画效果。博客地址:http://blog.csdn.net/yang786654260/article/category/5710631
效果展示
MyRefreshListView
使用方法在本节代码后介绍。
代码下载地址:http://download.csdn.net/detail/yang786654260/9024793
package com.example.activity;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.example.logger.Logger;
/**
* @author yangshuai
* @version 创建时间:2015-8-17 上午9:52:51
* @类说明 自定义的上拉加载下拉刷新,加载头部或尾部布局之前最好先进行文件配置;
* @主要配置文件之头部
* {@link #setHeaderNeedRefreshAtFirstShown} 第一次显示时,是否需要刷新;<br>
* {@link #setRefreshListener} 设置下拉刷新监听,设置监听后下拉刷新才有效;<br>
* {@link #setHeaderResourse} 设置头部资源文件,设置布局前应先配置上面两个;<br>
* @主要配置文件之尾部
* {@link #setFooterAutoLoadMore} 设置是否自动加载更多;<br>
* {@link #setLoadMoreListener} 设置上拉加载监听,设置监听后上拉加载才有效;<br>
* {@link #onRefreshComplete} 下拉刷新完成;<br>
* {@link #setFooterResourse} 设置Footer资源id;<br>
* {@link #onLoadMoreComplete} 设置加载完成;<br>
* {@link #setFooterNoMoreDataWillBeLoadFlag} 已无更多加载;<br>
*@头部资源文件要求 头部布局需要有如下几个控件: 箭头ImageView默认向下指向,进度条ProgressBar,信息提示TextView,更新时间TextView
*@尾部资源文件要求 需要布局文件中有progressbar和TextView两个控件
*/
public class MyRefreshListView extends ListView implements OnScrollListener{
private Context context;
private LayoutInflater mInflater;
/**
* 判罚是否可以下拉刷新
*/
private boolean canRefresh = false;
/**
* 判罚是否可以上拉加载
*/
private boolean canLoadMore = false;
/**
* 屏幕上第一个item的索引
*/
private int mFirstItemIndex;
/**
* 屏幕上最后一个item索引
*/
private int mLastItemIndex;
/**
* 该listView的总数
*/
private int mItemCount;
//================================================== headerView start ============================================
private LinearLayout mHeaderView;
private int headerViewId = -1;
private int headerArrowImgId;
private int headerProgressPbId;
private int headerTipTvId;
private int headerTimeTvId;
private ProgressBar headerProgressBar;
private ImageView headerArrowImg;
private TextView headerTimeTv;
private TextView headerTipTv;
private int mHeaderViewHeight;
private int mHeaderViewWidth;
/**
* 在第一次显示时,是否需要刷新;<\br>
* if true 会加载一次onRefreshing方法,触发刷新监听
*/
private boolean headerNeedRefreshAtFirstShown = false;
/**
* 在第一次显示时,是否需要刷新;
* if true 会加载一次onRefreshing方法,触发刷新监听
* @param headerNeedRefreshAtFirstShown
*/
public void setHeaderNeedRefreshAtFirstShown( boolean headerNeedRefreshAtFirstShown){
this.headerNeedRefreshAtFirstShown = headerNeedRefreshAtFirstShown;
}
// 下拉刷新的状态标识 start
/** 松开刷新 */
private final static int HEADER_RELEASE_TO_REFRESH = 0;
/** 下拉刷新 */
private final static int HEADER_PULL_TO_REFRESH = 1;
/** 正在刷新 */
private final static int HEADER_REFRESHING = 2;
/** 刷新完成 or 什么都没做,恢复原状态。 */
private final static int HEADER_REFRESHED_FINISH = 3;
// 下拉刷新的状态标识 end
/**
* 往下拉时的提示语
*/
private String headerPullToRefreshTip = "轻轻下拉,刷新下限";
/**
* 释放刷新提示语
*/
private String headerReleaseToRefreshTip = "哪里的妖怪,快快放开我!";
/**
* 正在刷新提示语
*/
private String headerRefreshingTip = "正在刷新...";
/**
* 设置往下拉时的提示语
* @param string
*/
public void setHeaderPullToRefreshString(String string){
this.headerPullToRefreshTip = string;
}
/**
* 设置释放刷新的提示语
* @param string
*/
public void setHeaderReleaseToRefreshString(String string){
this.headerReleaseToRefreshTip = string;
}
/**
* 设置释放刷新的提示语
* @param string
*/
public void setHeaderRefreshingString(String string){
this.headerRefreshingTip = string;
}
/**
* 下拉刷新HeadView的实时状态
*/
private int mHeadState;
//箭头动画 start
/**
* 箭头旋转动画
*/
private RotateAnimation headerArrowAnimation;
/**
* 箭头还原动画
*/
private RotateAnimation headerArrowReverseAnimation;
/**
* 箭头旋转延时
*/
private int headerAarrowDuration = 250;
/**
* 设置箭头旋转延时
* @param arrowDuration
*/
public void setHeaderArrowDuration(int arrowDuration) {
this.headerAarrowDuration = arrowDuration;
headerArrowAnimation.setDuration(arrowDuration);
headerArrowReverseAnimation.setDuration(arrowDuration);
}
/**
* 箭头旋转加速器
*/
private Interpolator headerArrowInterpolator = new LinearInterpolator();
/**
* 设置箭头旋转加速器
*/
public void setHeaderArrowInterpolator(Interpolator arrowInterpolator) {
this.headerArrowInterpolator = arrowInterpolator;
headerArrowAnimation.setInterpolator(arrowInterpolator);
headerArrowReverseAnimation.setInterpolator(arrowInterpolator);
}
//箭头动画 end
//时间 start
/**
* 时间提示语
*/
private String headerTimeTip = "最近更新时间";
/**
* 设置时间提示语
* @param timeTipString
*/
public void setHeaderTimeTipString(String timeTipString) {
this.headerTimeTip = timeTipString;
}
/**
* 时间显示格式
*/
private String headerTimeDateFormat = "yyyy年MM月dd日 HH:mm";
/**
* 设置舌尖显示格式
* @param timeDateFormat
* 举例:"yyyy年MM月dd日 HH:mm"
*/
public void setHeaderTimeDateFormat(String timeDateFormat) {
this.headerTimeDateFormat = timeDateFormat;
}
//时间 end
/**
* 下拉刷新完成后,头部移动动画距离
*/
private float headerFinishTranslteDistance;
/**
* 下拉刷新完成后的提示语
*/
private String headerRefreshedFinishTip = "下拉刷新成功";
/**
* 设置下拉刷新完成后的提示语
* @param headerRefreshedFinishTip
*/
public void setHeaderRefreshedFinishTipString(String headerRefreshedFinishTip){
this.headerRefreshedFinishTip = headerRefreshedFinishTip;
}
/**
* 下拉完成后的移动动画
*/
private TranslateAnimation translateAnimation;
/**
* 头部隐藏动画延迟时间
*/
private int headerGoBackLocationDelayTime = 200;
/**
* 设置头部隐藏动画延迟时间
* @param headerGoBackLocationDelayTime
*/
public void setHeaderGoBackLocationDelayTime(int headerGoBackLocationDelayTime){
this.headerGoBackLocationDelayTime = headerGoBackLocationDelayTime;
}
//================================================== headerView end ==============================================
//================================================== footerView start ============================================
private int footerViewId;
private int footerProgressId;
private int footerTipTvId;
private LinearLayout mFooterView;
private ProgressBar footerProgressBar;
private TextView footerTipTv;
/**
* 使用自动加载更多
*/
private boolean footerUseAutoLoadMore = false;
/**
* 设置是否自动加载更多
* @param userAutoLoadMore
*/
public void setFooterAutoLoadMore(boolean useAutoLoadMore) {
this.footerUseAutoLoadMore = useAutoLoadMore;
}
/**
* 正在加载更多提示语
*/
private String footerLoadMoreTip = "正在加载...";
/**
* 设置正在加载更多提示语
*/
public void setFooterLoadMoreString(String loadMoreTip){
this.footerLoadMoreTip = loadMoreTip;
}
/**
* 加载完成提示语
*/
private String footerLoadMoreFinishTip = "点击加载完成";
/**
* 设置加载完成提示语
*/
public void setFooterLoadMoreFinishString(String loadMoreFinishTip){
this.footerLoadMoreFinishTip = loadMoreFinishTip;
}
/**
* 自动加载更多完成提示语
*/
private String footerAutoLoadMoreFinishTip = "上拉加载更多";
/**
* 设置自动加载更多完成提示语
*/
public void setFooterAutoLoadMoreFinishString(String autoLoadMoreFinishTip){
this.footerAutoLoadMoreFinishTip = autoLoadMoreFinishTip;
}
/**
* 判断是否可以加载更多
*/
private boolean footerNoMoreCanLoad = false;
/**
* 已无加载更多提示语
*/
private String footerNoMoreCanLoadTip = "已无更多可加载";
/**
* 已无更多提示语显示的持续时间
*/
private long footerNoMoreTipDelayTime = 3000;
/**
* 设置已无更多提示语显示的持续时间
*/
public void setFooterNoMoreTipDelayTime(long noMoreTipDelayTime){
this.footerNoMoreTipDelayTime = noMoreTipDelayTime;
}
/**
* 设置已无更多提示语
* @param noMoreCanLoadString
*/
public void setFooterNoMoreCanLoadString(String noMoreCanLoadString){
this.footerNoMoreCanLoadTip = noMoreCanLoadString;
}
/**
* footer状态
*/
private int mFooterState;
// 加载更多的状态标识 start
/** 加载中 */
public final static int FOOTER_LOADING = 1;
/** 完成刷新 */
private final static int FOOTER_LOAD_MORE_FINISH = 2;
/****** 无更多 *****/
private final static int FOOTER_NO_MORE_DATA = 3;
// 加载更多的状态标识 end
//================================================== footerView end =============================================
//================================================== 触摸监听 start ================================================
/**
* 开始触摸的y坐标
*/
private float mStartY;
/**
* 下拉距离比例,到达此比列显示释放刷新界面,跟进查看用法。
*/
private int RATIO = 3;
/**
* 判断上个布局是不是释放刷新
*/
private boolean HEADER_LAST_VIEW_IS_RELEASE;
//================================================== 触摸监听 end ==================================================
//================================================== 接口 start ==================================================
/**
* 下拉刷新监听
*/
private MyRefreshListener myRefreshListener = null;
/**
* 下拉刷新接口
* @author yangshuai
*/
public interface MyRefreshListener{
public void OnRefreshListener();
}
/**
* 下拉刷新接口监听
* @param myRefreshListener
*/
public void setRefreshListener(MyRefreshListener myRefreshListener){
if (myRefreshListener != null) {
canRefresh = true;
this.myRefreshListener = myRefreshListener;
}
}
/**
* 上拉加载接口监听
*/
private MyLoadMoreListener myLoadMoreListener = null;
/**
* 上拉加载接口
* @author yangshuai
*/
public interface MyLoadMoreListener{
public void OnLoadMore();
}
/**
* 设置上拉加载监听
* @param myLoadMoreListener
*/
public void setLoadMoreListener(MyLoadMoreListener myLoadMoreListener){
canLoadMore = true;
if (myLoadMoreListener != null) {
this.myLoadMoreListener = myLoadMoreListener;
}
}
//================================================== 接口 end ====================================================
//================================================== 初始化方法 start ==============================================
public MyRefreshListView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public MyRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyRefreshListView(Context context) {
super(context);
init(context);
}
private void init(Context context){
this.context = context;
setCacheColorHint(context.getResources().getColor(android.R.color.transparent));
setOnLongClickListener(null);
setOnScrollListener(this);
mInflater = LayoutInflater.from(context);
}
//================================================== 初始化方法 end ================================================
//========================================================= headerView相关方法 start==================================
/**
* 设置头部资源文件
* @param headerViewId
* 头部布局需要有如下几个控件:
* 箭头ImageView,进度条ProgressBar,信息提示TextView,更新时间TextView
*/
public void setHeaderResourse(int headerViewId,int arrowImgId,int progressPbId,int tipTvId,int timeTvId){
this.headerViewId = headerViewId;
this.headerArrowImgId = arrowImgId;
this.headerProgressPbId = progressPbId;
this.headerTipTvId = tipTvId;
this.headerTimeTvId = timeTvId;
setHeaderView();
}
/**
* 设置头部布局
*/
private void setHeaderView() {
mHeaderView = (LinearLayout) mInflater.inflate(headerViewId, null);
headerProgressBar = (ProgressBar) mHeaderView.findViewById(headerProgressPbId);
headerArrowImg = (ImageView) mHeaderView.findViewById(headerArrowImgId);
headerArrowImg.setMinimumHeight(70);
headerArrowImg.setMinimumWidth(50);
headerTimeTv = (TextView) mHeaderView.findViewById(headerTimeTvId);
headerTipTv = (TextView) mHeaderView.findViewById(headerTipTvId);
measureView(mHeaderView);
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
mHeaderViewWidth = mHeaderView.getMeasuredWidth();
headerFinishTranslteDistance = -mHeaderViewHeight;
mHeaderView.setPadding(0, -1 * mHeaderViewHeight, 0, 0);
mHeaderView.invalidate();
Toast.makeText(context, "W="+mHeaderViewWidth+"\nH="+mHeaderViewHeight, Toast.LENGTH_LONG).show();
addHeaderView(mHeaderView, null, false);
if (headerNeedRefreshAtFirstShown) {
mHeadState = HEADER_REFRESHING;
onRefreshing();
}else {
mHeadState = HEADER_REFRESHED_FINISH;
}
showHeaderViewByState();
initArrowRotateAnim();
}
/**
* 测量HeadView宽高(注意:此方法仅适用于LinearLayout)
* @param view
*/
private void measureView(View view) {
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params == null) {
params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childeWidthSpec = ViewGroup.getChildMeasureSpec(0, 0, params.width);
int PHeight = params.height;
int childeHeightSpec;
if (PHeight > 0) {
childeHeightSpec = MeasureSpec.makeMeasureSpec(PHeight, MeasureSpec.EXACTLY);
}else {
childeHeightSpec = MeasureSpec.makeMeasureSpec(PHeight, MeasureSpec.UNSPECIFIED);
}
view.measure(childeWidthSpec, childeHeightSpec);
}
/**
* 初始化箭头旋转动画
*/
private void initArrowRotateAnim() {
headerArrowAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
headerArrowAnimation.setDuration(headerAarrowDuration);
headerArrowAnimation.setInterpolator(headerArrowInterpolator);
headerArrowAnimation.setFillAfter(true);
headerArrowReverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
headerArrowReverseAnimation.setDuration(headerAarrowDuration);
headerArrowReverseAnimation.setInterpolator(headerArrowInterpolator);
headerArrowReverseAnimation.setFillAfter(true);
}
/**
* 通过不同的状态改变头部的显示
*/
private void showHeaderViewByState() {
switch (mHeadState) {
case HEADER_RELEASE_TO_REFRESH:
clearAnimation();
headerProgressBar.setVisibility(View.GONE);
headerArrowImg.setVisibility(View.VISIBLE);
headerArrowImg.clearAnimation();
headerArrowImg.startAnimation(headerArrowAnimation);
headerTipTv.setText(headerReleaseToRefreshTip);
break;
case HEADER_PULL_TO_REFRESH:
clearAnimation();
headerProgressBar.setVisibility(View.GONE);
headerArrowImg.setVisibility(View.VISIBLE);
headerArrowImg.clearAnimation();
setHeaderTipTvText(headerPullToRefreshTip);
if (HEADER_LAST_VIEW_IS_RELEASE) {
HEADER_LAST_VIEW_IS_RELEASE = false;
headerArrowImg.startAnimation(headerArrowReverseAnimation);
}
break;
case HEADER_REFRESHING:
clearAnimation();
mHeaderView.setPadding(0, 0, 0, 0);
headerArrowImg.clearAnimation();
headerArrowImg.setVisibility(View.GONE);
headerProgressBar.setVisibility(View.VISIBLE);
headerTipTv.setText(headerRefreshingTip);
break;
case HEADER_REFRESHED_FINISH:
translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0, Animation.ABSOLUTE, headerFinishTranslteDistance);
translateAnimation.setDuration(headerGoBackLocationDelayTime);
translateAnimation.setFillAfter(true);
translateAnimation.setInterpolator(new LinearInterpolator());
translateAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
headerProgressBar.setVisibility(View.GONE);
headerArrowImg.setVisibility(View.VISIBLE);
headerArrowImg.clearAnimation();
headerArrowImg.startAnimation(headerArrowAnimation);
setHeaderTipTvText(headerRefreshedFinishTip);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
clearAnimation();
mHeaderView.setPadding(0, -1 * mHeaderViewHeight, 0, 0);
headerArrowImg.clearAnimation();
setHeaderTipTvText(headerPullToRefreshTip);
}
});
startAnimation(translateAnimation);
break;
default:
break;
}
}
/**
* 设置提示TextView文字
*/
private void setHeaderTipTvText(String string) {
headerTipTv.setText(string);
}
/**
* 正在下拉刷新中
*/
private void onRefreshing(){
if (myRefreshListener != null) {
myRefreshListener.OnRefreshListener();
}
}
/**
* 下拉刷新完成
*/
public void onRefreshComplete(){
//在已经无更多加载的情况下,如果下拉刷新的话加载更多可以再启动
footerNoMoreCanLoad = false;
mHeadState = HEADER_REFRESHED_FINISH;
headerTimeTv.setText(getNewDate());
showHeaderViewByState();
}
/**
* 下拉刷新逻辑处理
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!canRefresh || mFirstItemIndex != 0 || mFooterState == FOOTER_LOADING) {
return super.onTouchEvent(ev);
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mStartY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
float tempY = ev.getY();
if (mHeadState == HEADER_REFRESHING) {
break;
}
if (mHeadState == HEADER_REFRESHED_FINISH) {
if (tempY - mStartY > 0) {
mHeadState = HEADER_PULL_TO_REFRESH;
showHeaderViewByState();
}
}
if (mHeadState == HEADER_PULL_TO_REFRESH) {
setSelection(0);
if ((tempY - mStartY)/RATIO >= mHeaderViewHeight) {
mHeadState = HEADER_RELEASE_TO_REFRESH;
HEADER_LAST_VIEW_IS_RELEASE = true;
showHeaderViewByState();
}else if (tempY - mStartY <= 0) {
mHeadState = HEADER_REFRESHED_FINISH;
showHeaderViewByState();
}
if (mHeadState == HEADER_PULL_TO_REFRESH) {
float paddingTop = -1 * mHeaderViewHeight + (tempY - mStartY)/RATIO;
Logger.d("paddingTop", ""+(int)paddingTop);
mHeaderView.setPadding(0, (int)paddingTop, 0, 0);
headerFinishTranslteDistance = -mHeaderViewHeight - paddingTop;
}
}
if (mHeadState == HEADER_RELEASE_TO_REFRESH) {
setSelection(0);
if (tempY - mStartY > 0 && (tempY - mStartY)/RATIO < mHeaderViewHeight) {
mHeadState = HEADER_PULL_TO_REFRESH;
showHeaderViewByState();
}else if (tempY - mStartY <= 0) {
mHeadState = HEADER_REFRESHED_FINISH;
showHeaderViewByState();
}
if (mHeadState == HEADER_RELEASE_TO_REFRESH) {
mHeaderView.setPadding(0, (int)(tempY - mStartY)/RATIO - mHeaderViewHeight, 0, 0);
}
}
break;
case MotionEvent.ACTION_UP:
if (mHeadState == HEADER_REFRESHING) {
break;
}
if (mHeadState == HEADER_PULL_TO_REFRESH) {
mHeadState = HEADER_REFRESHED_FINISH;
showHeaderViewByState();
}
if (mHeadState == HEADER_RELEASE_TO_REFRESH) {
headerFinishTranslteDistance = -mHeaderViewHeight;
mHeadState = HEADER_REFRESHING;
showHeaderViewByState();
onRefreshing();
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
//========================================================= headerView相关方法 end====================================
//========================================================= footerView相关方法 start==================================
/**
* 设置Footer资源id,需要布局文件中有progressbar和TextView两个控件
* @param mFooterView
* @param mFooterProgress progressBar
* @param mFooterTipTv TextView
*/
public void setFooterResourse(int mFooterView,int mFooterProgress,int mFooterTipTv){
this.footerViewId = mFooterView;
this.footerProgressId = mFooterProgress;
this.footerTipTvId = mFooterTipTv;
setFooterView();
}
/**
* 设置footer布局
*/
private void setFooterView(){
mFooterView = (LinearLayout) mInflater.inflate(footerViewId, null);
footerProgressBar = (ProgressBar) mFooterView.findViewById(footerProgressId);
footerTipTv = (TextView) mFooterView.findViewById(footerTipTvId);
addFooterView(mFooterView);
mFooterView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if ( !canLoadMore || canRefresh && mHeadState == HEADER_REFRESHING) {
return;
}
if (footerNoMoreCanLoad) {
return;
}
mFooterState = FOOTER_LOADING;
showFooterViewByState();
onLoadMore();
}
});
mFooterState = FOOTER_LOAD_MORE_FINISH;
}
/**
* 通过mFooterState改变footer布局显示
*/
private void showFooterViewByState(){
switch (mFooterState) {
case FOOTER_LOADING:
hideFooterViewHandler.removeMessages(0);
mFooterView.setVisibility(View.VISIBLE);
footerProgressBar.setVisibility(View.VISIBLE);
footerTipTv.setText(footerLoadMoreTip);
break;
case FOOTER_LOAD_MORE_FINISH:
mFooterView.setVisibility(View.VISIBLE);
footerProgressBar.setVisibility(View.GONE);
footerTipTv.setText(footerUseAutoLoadMore?footerAutoLoadMoreFinishTip:footerLoadMoreFinishTip);
hideFooterViewHandler.removeMessages(0);
hideFooterViewHandler.sendEmptyMessageDelayed(0, footerNoMoreTipDelayTime);
break;
case FOOTER_NO_MORE_DATA:
mFooterView.setVisibility(View.VISIBLE);
footerProgressBar.setVisibility(View.GONE);
footerTipTv.setText(footerNoMoreCanLoadTip);
hideFooterViewHandler.removeMessages(0);
hideFooterViewHandler.sendEmptyMessageDelayed(0, footerNoMoreTipDelayTime);
break;
default:
break;
}
}
/**
* 执行上拉加载数据更新
*/
private void onLoadMore(){
if (myLoadMoreListener != null) {
myLoadMoreListener.OnLoadMore();
}
}
/**
* 设置加载完成
*/
public void onLoadMoreComplete(){
mFooterState = FOOTER_LOAD_MORE_FINISH;
showFooterViewByState();
}
/**
* 延时隐藏footerView
*/
private Handler hideFooterViewHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
mFooterView.setVisibility(View.GONE);
super.handleMessage(msg);
}
};
/**
* 已无更多加载
*/
public void setFooterNoMoreDataWillBeLoadFlag(){
footerNoMoreCanLoad = true;
mFooterState = FOOTER_NO_MORE_DATA;
showFooterViewByState();
}
/**
* 加载更多逻辑处理
* @param view
* @param scrollState
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (footerNoMoreCanLoad || mFooterState == FOOTER_LOADING) {
return;
}
if (canLoadMore) {
if (!(mLastItemIndex == mItemCount && scrollState == SCROLL_STATE_IDLE) || mFooterState == FOOTER_LOADING) {
return;
}
if (canRefresh && mHeadState == HEADER_REFRESHING) {
mFooterView.setVisibility(View.GONE);
}else if(footerUseAutoLoadMore){
mFooterState = FOOTER_LOADING;
onLoadMore();
showFooterViewByState();
}else {
mFooterState = FOOTER_LOAD_MORE_FINISH;
showFooterViewByState();
}
}else {
mFooterView.setVisibility(View.GONE);
this.removeFooterView(mFooterView);
}
}
/**
* 获取屏幕上第一个和最后一个item的索引
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
mFirstItemIndex = firstVisibleItem;
mLastItemIndex = firstVisibleItem + visibleItemCount - 2;
mItemCount = totalItemCount - 2;
}
//========================================================= footerView相关方法 end====================================
/**
* 设置适配器,加载最开始的刷新时间
* @param adapter
*/
public void setAdapter(BaseAdapter adapter) {
headerTimeTv.setText(getNewDate());
super.setAdapter(adapter);
}
/**
* 获取最新时间
* @return
*/
private String getNewDate() {
return headerTimeTip+ new SimpleDateFormat(headerTimeDateFormat,Locale.CHINA).format(new Date());
}
}
使用方法
首先要自定义头部和尾部的布局
头部布局要求:线性布局
头部布局需要有如下几个控件: 箭头ImageView默认向下指向,进度条ProgressBar,信息提示TextView,更新时间TextView。
尾部布局要求:线性布局
需要布局文件中有progressbar和TextView两个控件。
头部示例(这个示例是SingleLayoutListView作者的)
<?xml version="1.0" encoding="utf-8"?>
<!-- ListView的头部 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal" >
<!-- 内容 -->
<RelativeLayout
android:id="@+id/head_contentLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
android:paddingTop="8dp" >
<!-- 箭头图像、进度条 -->
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="30dp" >
<!-- 箭头 -->
<ImageView
android:id="@+id/head_arrowImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:contentDescription="@string/app_name"
android:src="@drawable/icon_arrow" />
<!-- 进度条 -->
<ProgressBar
android:id="@+id/head_progressBar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/image_progress"
android:visibility="gone" />
</FrameLayout>
<!-- 提示、最近更新 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:orientation="vertical" >
<!-- 提示 -->
<TextView
android:id="@+id/head_tipsTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="释放提示"
android:textColor="@android:color/black"
android:textSize="18sp" />
<!-- 最近更新 -->
<TextView
android:id="@+id/head_lastUpdatedTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="更新时间"
android:textColor="@android:color/black"
android:textSize="12sp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
尾部布局示例(这个示例是SingleLayoutListView作者的)
<?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="match_parent"
android:gravity="center"
android:orientation="horizontal"
android:padding="15dp" >
<ProgressBar
android:id="@+id/pull_to_refresh_progress"
style="@android:style/Widget.ProgressBar.Small.Inverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone" >
</ProgressBar>
<TextView
android:id="@+id/load_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10.0dp"
android:gravity="center"
android:text="加载更多"
android:textColor="@android:color/black" >
</TextView>
</LinearLayout>
以上两个布局需要自己实现,实现后通过设置资源id,把id传入listView中:
myRefreshListView.setRefreshListener(new MyRefreshListener() {
@Override
public void OnRefreshListener() {
//下拉刷新监听
}
});
myRefreshListView.setLoadMoreListener(new MyLoadMoreListener() {
@Override
public void OnLoadMore() {
//加载更多监听
}
});
//在设置布局资源之前要进行需要的配置
myRefreshListView.setHeaderResourse(R.layout.pull_to_refresh_head, R.id.head_arrowImageView, R.id.head_progressBar, R.id.head_tipsTextView, R.id.head_lastUpdatedTextView);
myRefreshListView.setFooterResourse(R.layout.pull_to_refresh_load_more, R.id.pull_to_refresh_progress, R.id.load_more);
在数据加载完成后调用如下方法,更换布局显示:
//下拉刷新完成
myRefreshListView.onRefreshComplete();
//上拉加载完成
myRefreshListView.onLoadMoreComplete();
//上拉加载数据已无更多
myRefreshListView.setFooterNoMoreDataWillBeLoadFlag();