您的位置:首页 > 其它

下拉刷新和上拉加载的ListView-MutilListView

2015-07-02 16:14 351 查看
public class LoadListView extends ListView implements OnScrollListener {
private int firstItem;// 当前可以见第一个Item的位置
private int lastItem;// 当前可以见最后一个Item的位置
private int totalItemCount;// list总数量

private OnLoadListener mListener;// 回调接口
private boolean isLoading = false;;// 是否正在加载

private View footer;// 底布局文件
private View head;// 头布局文件
private int headHeigth;// 布局高度

// 下拉刷新相关
private boolean isRemark;// 是否在第一个Item按下
private int startY;// 滑动开始前的Y值
private int state;// 当前状态
private final int NONE = 0;// 正常状态
private final int PULL = 1;// 提示下拉状态
private final int RELESE = 2;// 提示释放状态
private final int REFLASHING = 3;// 刷新状态状态
private int scrollState;// 当前listview的状态

public LoadListView(Context context) {
super(context);
initView(context);
}

public LoadListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}

public LoadListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context);
}

private void initView(Context context) {
LayoutInflater mInflater = LayoutInflater.from(context);
// 底布局操作相关
footer = mInflater.inflate(R.layout.listiview_footer, null);
footer.findViewById(R.id.footer_ll_layout).setVisibility(View.GONE);
this.addFooterView(footer);

head = mInflater.inflate(R.layout.listview_head, null);
// 通知父布局Head占用的大小
measureHead(head);
// 获取高度
headHeigth = head.getMeasuredHeight();
// 设置头布局为高度的负值而隐藏
setHeaderPaddingTop(-headHeigth);
this.addHeaderView(head);
this.setOnScrollListener(this);
}

/**
* 通知父布局Head占用的大小 (此处本人也未彻底搞懂)
*
* @param view
*/
private void measureHead(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);
}

/**
* 设置Head布局的上边距,以达到隐藏头布局的目的
*
* @param paddingTop
*/
private void setHeaderPaddingTop(int paddingTop) {
head.setPadding(head.getPaddingLeft(), paddingTop,
head.getPaddingRight(), head.getPaddingBottom());
// 刷新View的方法
head.invalidate();
}

/**
* 下拉刷新 监听手指的滑动状态
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 如果实在顶部开始滑动 则记录当前y的位置,后面用来计算滑动的距离
if (firstItem == 0) {
startY = (int) ev.getY();
isRemark = true;
}
break;
case MotionEvent.ACTION_MOVE:
onMove(ev);// 判断手指滑动过程中的动作
break;
case MotionEvent.ACTION_UP:
// 手指抬起后用来判断是否到达刷新数据要求的目的
if (state == RELESE) {
state = REFLASHING;
// 加载最新数据
reflushData();
} else if (state == PULL || state == NONE) {
state = NONE;
isRemark = false;
reflushViewByState();
}
break;
}
return super.onTouchEvent(ev);
}

private void onMove(MotionEvent ev) {
if (!isRemark) {
return;
}
int tempY = (int) ev.getY();
Log.v("y", tempY + "");
// 滑动的距离
int distance = tempY - startY;
// 头布局慢慢显示出来的宽度
int topPadding = distance - headHeigth;
switch (state) {
case NONE:
if (distance > 0) {
state = PULL;
reflushViewByState();
} else {
}
break;
case PULL:
// 绘制当前 拉动过程的头布局
setHeaderPaddingTop(topPadding);
// 如果距离大于头布局+100 dp且ListView在滑动过程中
if (distance > headHeigth + 100
&& scrollState == SCROLL_STATE_TOUCH_SCROLL) {
state = RELESE;
reflushViewByState();
}
break;
case RELESE:
// 绘制当前 拉动过程的头布局
setHeaderPaddingTop(topPadding);
if (distance < headHeigth + 100) {
state = PULL;
reflushViewByState();
} else if (distance <= 0) {
state = NONE;
isRemark = false;
reflushViewByState();
} else if (distance > 500) {
}
break;
}
}

/**
* 刷新数据的执行方法
*/
private void reflushData() {
state = REFLASHING;
isRemark = false;
reflushViewByState();
mListener.onRefresh();
}

/**
* 根据当前状态改变界面显示
*
* @param state
*/
private void reflushViewByState() {
TextView tip = (TextView) head.findViewById(R.id.head_tv_tips);
ImageView pic = (ImageView) head.findViewById(R.id.head_iv_pic);
ProgressBar pb = (ProgressBar) head.findViewById(R.id.head_pb_progress);

RotateAnimation anim = new RotateAnimation(0, 180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(500);
anim.setFillAfter(true);
RotateAnimation anim1 = new RotateAnimation(180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
anim1.setDuration(500);
anim1.setFillAfter(true);
switch (state) {
case NONE:
setHeaderPaddingTop(-headHeigth);
break;
case PULL:
tip.setText("下拉可以刷新!");
pic.setVisibility(View.VISIBLE);
pb.setVisibility(View.GONE);
// 设置相关动画
pic.clearAnimation();
pic.setAnimation(anim);
break;
case RELESE:
tip.setText("松开可以刷新!");
pic.setVisibility(View.VISIBLE);
pb.setVisibility(View.GONE);
// 设置相关动画
pic.setAnimation(anim1);
break;
case REFLASHING:
setHeaderPaddingTop(0);
tip.setText("正在刷新!");
pic.clearAnimation();// 这里一定要执行清楚动画,不然图片无法隐藏
pic.setVisibility(View.GONE);
pb.setVisibility(View.VISIBLE);
break;
}
}

// 下拉刷新完成回调
public void reflushCompleted() {
state = NONE;
isRemark = false;
reflushViewByState();
}

// 分页加载完成回调
public void flushCompleted() {
isLoading = false;
footer.findViewById(R.id.footer_ll_layout).setVisibility(View.GONE);
}

public void setOnLoadListener(OnLoadListener listener) {
this.mListener = listener;
}

public interface OnLoadListener {
// 分页加载
void onLoadMore();

// 下拉刷新
void onRefresh();
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (lastItem == totalItemCount && SCROLL_STATE_IDLE == scrollState) {
if (!isLoading) {
footer.findViewById(R.id.footer_ll_layout).setVisibility(
View.VISIBLE);
mListener.onLoadMore();
isLoading = true;
}
}
this.scrollState = scrollState;
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
this.lastItem = firstVisibleItem + visibleItemCount;
this.totalItemCount = totalItemCount;
this.firstItem = firstVisibleItem;
}
}


以上是实现了了下拉刷新和上拉加载第二页的ListView代码。

欢迎各位指出错误,大家多多指教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: