/**
* 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; } }}