您的位置:首页 > 其它

自定义ListView的下拉刷新和上拉加载更多

2016-08-06 09:50 399 查看
/**
* Created by Ext on 2016/8/5.
*/
public class LoadMoreListView extends ListView implements AbsListView.OnScrollListener {

private View mFooter;
private View mHeader;

private int mHeaderHeight;

private int totalItemCount;
private int lastVisibleItem; // 最后一个可见的item
private int firstVisibleItem;
private boolean isRemark; // 标记,当前是否在listView最顶端按下
private int startY; // 按下时的Y值

private int state; // 当前的状态
private final int NONE = 0; // 正常状态
private final int PULL = 1; // 提示下拉状态
private final int RELEASE = 2; // 提示释放状态
private final int REFRESHING = 3; // 刷新状态
private int scrollState; // 当前滚动状态

private TextView tipTv;
private ImageView arrowIv;
private ProgressBar progressBar;
private TextView updateTimeTv;

private boolean isLoading;
private ILoadMoreListener mLoadMoreListener;
private RotateAnimation animDown;
private RotateAnimation animUp;
private View mLoadingLayout;

public LoadMoreListView(Context context) {
this(context, null);
}

public LoadMoreListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public LoadMoreListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

initView(context);
}

/**
* 添加底部加载提示布局到ListView
* @param context
*/
private void initView(Context context) {

LayoutInflater inflater = LayoutInflater.from(context);
mFooter = inflater.inflate(R.layout.footer_layout, null);
mLoadingLayout = mFooter.findViewById(R.id.load_layout);
mLoadingLayout.setVisibility(View.GONE);
this.addFooterView(mFooter);

mHeader = inflater.inflate(R.layout.header_layout, null);
measureView(mHeader);
mHeaderHeight = mHeader.getMeasuredHeight();
topPadding(-mHeaderHeight);
this.addHeaderView(mHeader);

this.setOnScrollListener(this);
}

/**
* 通知父布局,占用的宽、高
* @param view
*/
private void measureView(View view) {
ViewGroup.LayoutParams p = view.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
// 宽度测量规格
int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
// 高度测量规格
int height;
int tempHeight = p.height;
if (tempHeight > 0) {
height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
} else {
height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
view.measure(width, height);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
if (firstVisibleItem == 0) {
isRemark = true;
startY = (int) ev.getY();
}
break;
case MotionEvent.ACTION_MOVE:
onMove(ev);
break;

case MotionEvent.ACTION_UP:
// 松手后头布局处于两种状态
if (state == RELEASE) {
state = REFRESHING;
refreshViewByState();
// 加载数据
if (mLoadMoreListener != null) {
mLoadMoreListener.onRefresh();
}
} else if (state == PULL) {
state = NONE;
isRemark = false;
refreshViewByState();
}
break;
}
return super.onTouchEvent(ev);
}

/**
* 判断移动过程操作
* @param ev
*/
private void onMove(MotionEvent ev){
if (!isRemark) {
return;
}
int tempY = (int)ev.getY();
// space 摁下后滑动的垂直距离
int space = tempY - startY;

int topPadding = space - mHeaderHeight;
if (topPadding > mHeaderHeight + 20) {
topPadding = mHeaderHeight + 20;
}

switch (state) {
case NONE:
if (space > 0) {
state = PULL;
refreshViewByState();
}
break;
case PULL:
// 滑动距离大于一定高度之后就更新状态
topPadding(topPadding);
if (space > mHeaderHeight + 10 && scrollState == SCROLL_STATE_TOUCH_SCROLL) {
state = RELEASE;
refreshViewByState();
}
break;
case RELEASE:
// 限制头部布局的topPadding
if (topPadding >= mHeaderHeight + 20) {
topPadding = mHeaderHeight;
}
topPadding(topPadding);
if (space < mHeaderHeight + 10) {
state = PULL;
refreshViewByState();
} else if (space <= 0) {
state = NONE;
isRemark = false;
refreshViewByState();
}
break;
case REFRESHING:
break;

}
}

/**
* 根据当前状态,改变界面显示(只要在滑动时状态变化就需要调用)
*/
private void refreshViewByState() {
if (tipTv == null) {
tipTv = (TextView) mHeader.findViewById(R.id.tip_tv);
}
if (arrowIv == null) {
arrowIv = (ImageView) mHeader.findViewById(R.id.arrow);
}
if (progressBar == null) {
progressBar = (ProgressBar) mHeader.findViewById(R.id.progress);
}

if (animDown == null) {
animDown = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animDown.setDuration(500);
animDown.setFillAfter(true);
}
if (animUp == null) {
animUp = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animUp.setDuration(500);
animUp.setFillAfter(true);
}

switch (state) {
case NONE:
topPadding(-mHeaderHeight);
break;

case PULL:
arrowIv.setVisibility(VISIBLE);
progressBar.setVisibility(GONE);
tipTv.setText("下拉可以刷新");
arrowIv.clearAnimation();
arrowIv.setAnimation(animDown);
break;

case RELEASE:
arrowIv.setVisibility(VISIBLE);
progressBar.setVisibility(GONE);
tipTv.setText("松开可以刷新");
arrowIv.clearAnimation();
arrowIv.setAnimation(animUp);
break;

case REFRESHING:
topPadding(10);
arrowIv.setVisibility(GONE);
progressBar.setVisibility(VISIBLE);
tipTv.setText("正在刷新");
arrowIv.clearAnimation();
break;
}
}

/**
* 加载完更多数据
*/
public void loadComplete() {
isLoading = false;
mLoadingLayout.setVisibility(View.GONE);
invalidate();
}

/**
* 获取完数据
*/
public void refreshComplete() {

state = NONE;
isRemark = false;
refreshViewByState();

if (updateTimeTv == null) {
updateTimeTv = (TextView) mHeader.findViewById(R.id.time_tv);
}
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
Date date = new Date(System.currentTimeMillis());
updateTimeTv.setText(format.format(date));
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

// 针对加载更多
if (totalItemCount == lastVisibleItem && scrollState == SCROLL_STATE_IDLE) {

if (!isLoading) {
isLoading = true;
mLoadingLayout.setVisibility(View.VISIBLE);
if (mLoadMoreListener != null) {
mLoadMoreListener.onLoadMore();
}
}
}
// 针对下拉刷新
this.scrollState = scrollState;
}

/**
*
* @param view
* @param firstVisibleItem 第一个可见的item的数据在数据集中的索引
* @param visibleItemCount 当前屏幕可见的item总数
* @param totalItemCount 数据集中数据的总数
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

this.firstVisibleItem = firstVisibleItem;
this.lastVisibleItem = firstVisibleItem + visibleItemCount;
this.totalItemCount = totalItemCount;
}

private void topPadding(int topPadding) {

mHeader.setPadding(mHeader.getPaddingLeft(), topPadding, mHeader.getPaddingRight(), mHeader.getPaddingBottom());
}

public void setLoadMoreListener(ILoadMoreListener mLoadMoreListener) {
this.mLoadMoreListener = mLoadMoreListener;
}

public interface ILoadMoreListener {
public void onLoadMore();

public void onRefresh();
}
}

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: