/**
* Created by on 2016/12/2.
* 自定义listview:
* 一、下拉刷新:
* 1. 添加头部布局,并设置位置隐藏
* 2. 监听滑动事件,判断当前显示在最顶端的item是否是第一个item
* 3. 监听onTouch事件,根据下拉的距离来判断下来状态的变化
* 二、加载更多:
* 1. 添加底部布局,并隐藏
* 2. 监听滑动事件,判断最后显示的item是不是最后一个item来决定是否加载更多
* 这里通过传递参数的方式来传递handler来延迟刷新
* (推荐)通过接口回调的方式可以实现加载数据
*/
public class ReFlashListView extends ListView implements AbsListView.OnScrollListener{
private Handler handler;//这个handler用来做一个延时处理刷新
private View header;//头布局
private int headerHeight;//header的高度
int firstVisibleItem;//listview中可见的第一个item的位置
int visibleItemCount;//可见的item的数量
int totalItemCounts;//已经显示出来的总数量
int scrollState;//滑动状态
int state;//滑动的状态
final int NONE = 0; //正常状态
final int PULL = 1; //提示下拉状态
final int RELSE = 2; //提示释放状态
final int RELSING = 3; //正在刷新状态
private boolean isTop = false; //判断按下的时候当前显示在最上面一个item是listview的第一个item
private int stateY;//按下的时候Y轴的位置
private ImageView iv_header;
private TextView tv_header;
private ProgressBar pg_header;
private View footer;//底部布局
private boolean isLoading = false;
public ReFlashListView(Context context) {
super(context);
initView(context);
}
public ReFlashListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public ReFlashListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
/**
* 实例化handler
*/
public void setListViewHandler(Handler handler){
this.handler = handler;
}
/**
* 给ListView添加头布局
* @param context
*/
private void initView(Context context){
header = LayoutInflater.from(context).inflate(R.layout.activity_view_listview_header, null);
iv_header = (ImageView) header.findViewById(R.id.iv_header);
tv_header = (TextView) header.findViewById(R.id.tv_header);
pg_header = (ProgressBar) header.findViewById(R.id.pg_header);
measureHeight(header);
headerHeight = header.getMeasuredHeight();
initHeaderTopPadding();
this.addHeaderView(header);
loadFooter(context);
this.setOnScrollListener(this);
}
/**
* 加载底部布局
*/
private void loadFooter(Context context){
footer = LayoutInflater.from(context).inflate(R.layout.activity_view_listview_footer, null);
footer.findViewById(R.id.ll_load_more).setVisibility(View.GONE);
this.addFooterView(footer);
}
/**
* 初始化header的位置
*/
public void initHeaderTopPadding(){
setTopPadding(-headerHeight);
}
/**
* 设置header的高度:隐藏header
*/
private void setTopPadding(int topPadding) {
header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom());
}
/**
* 高度父布局当前view的宽高
* 如果没有这一步,header.getMeasuredHeight() == 0
*/
private void measureHeight(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 temHeight = p.height;
if(temHeight > 0){
height = MeasureSpec.makeMeasureSpec(temHeight , MeasureSpec.EXACTLY);
}else {
height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
view.measure(width, height);
}
/**
* @param view
* @param scrollState:即滑动的状态。分为三种 0,1,2
0 表示停止滑动的状态 SCROLL_STATE_IDLE
1表示正在滚动,用户手指在屏幕上 SCROLL_STATE_TOUCH_SCROLL
2表示正在滑动。用户手指已经离开屏幕 SCROLL_STATE_FLING
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
this.scrollState = scrollState;
if((firstVisibleItem + visibleItemCount) == totalItemCounts && scrollState == SCROLL_STATE_IDLE){
if(!isLoading){
//显示出footer,并在这里加载数据
footer.findViewById(R.id.ll_load_more).setVisibility(View.VISIBLE);
/**
* TODO:加载数据
*/
}
}
}
/**
* @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.visibleItemCount = visibleItemCount;
this.totalItemCounts = totalItemCount;
}
/**
* 监听滑动状态的改变
* @param ev
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
if(firstVisibleItem == 0){//当前显示在最上面一个item是listview的第一个item
state = NONE;//设置状态,表示继续下拉可以触发刷新
isTop = true;
stateY = (int) ev.getY();
}
break;
case MotionEvent.ACTION_MOVE:
reFlashing(ev);
break;
case MotionEvent.ACTION_UP:
if(state == RELSE){
state = RELSING;
reFlasTip();
//加载数据 /**
* TODO:刷新数据
*/
}else if(state == PULL){ state = NONE; isTop = false; reFlasTip(); } break; } return super.onTouchEvent(ev); } /** * 判断移动过程中的操作 */ private void reFlashing(MotionEvent ev){ if(!isTop){ return; } int evY = (int) ev.getY(); int spaceY = evY - stateY; int topPadding = spaceY - headerHeight; if(topPadding >= headerHeight * 3){ topPadding = headerHeight * 2; } switch (state){ case NONE: if(spaceY >= 0){ //表示往下拉动 state = PULL; reFlasTip(); } break; case PULL: setTopPadding(topPadding); if(spaceY >= headerHeight+20 && scrollState == SCROLL_STATE_TOUCH_SCROLL){ //表示往下拉动,并且正在滚动 state = RELSE; reFlasTip(); }else if(spaceY <= 0){ state = NONE; isTop = false; reFlasTip(); } break; case RELSE: setTopPadding(topPadding); if(spaceY < headerHeight){ state = PULL; reFlasTip(); }else if(spaceY <= 0){ state = NONE; isTop = false; reFlasTip(); } break; } } /** * 根据下拉状态的变化改变header的提示 */ private void reFlasTip(){ switch (state){ case NONE: setTopPadding(-headerHeight); break; case PULL: tv_header.setText("下拉可以刷新"); break; case RELSE: tv_header.setText("松开可以刷新"); break; case RELSING: setTopPadding(headerHeight); tv_header.setText("正在刷新"); break; } }}