到頂部時下拉刷新,到底部時上拉加載更多!具體如圖
第1步,實現一個部分自定義控件,先繼承一個ListView
public class RefreshListView extends ListView {
//三種刷新的狀態
private static final int STATE_PULL_TO_REFRESH=0;//下拉刷新狀態
private static final int STATE_RELEASE_TO_REFRESH=1;//釋放刷新狀態
private static final int STATE_REFRESHING=2;//正在刷新狀態
private int currentSate=STATE_PULL_TO_REFRESH;//缺省爲下拉刷新狀態
private boolean isPullToRrefresh=false;//是否 是下拉刷新
private boolean isLoadMore=false;//是否加載更多
private View headerView;//頭部視圖
private View footerView;//腳部視圖
private ImageView arrowIv;//箭頭控件
private ProgressBar progressBar;//進度控件
private TextView titleTv;//頭部的標題
private TextView lastTimeTv;//最後刷新時間
private int headerViewHeight;//頭部的高度
private int footerHeight;//尾部的高度
private RotateAnimation upAnimation;//向上的動畫
private RotateAnimation downAnimation;//向下的動畫
private float downY;//按下時的Y軸座標
//構造方法
public RefreshListView(Context context) {
super(context);
init();//初使化數據
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
//1. 初始化方法
private void init() {
//1.1 初始化刷新頭部
initHeaderView();
//1.2 初始化加載更多底部(腳部)
initFooterView();
}
// 2. 初始化刷新頭
private void initHeaderView() {
//2.1 把頭佈局的xml轉化爲View對象
headerView = View.inflate(getContext(), R.layout.head_view, null);
//2.2 把頭佈局的xml的根節點視圖添加到ListView中,作爲listview的頭部
this.addHeaderView(headerView);
arrowIv=(ImageView) headerView.findViewById(R.id.arrow_iv);//箭頭座標
lastTimeTv=(TextView) headerView.findViewById(R.id.lastTime_tv);//時間座標
progressBar=(ProgressBar) headerView.findViewById(R.id.refrush_pb);//進度條
titleTv=(TextView) headerView.findViewById(R.id.title_tv);//刷新狀態顯示
//2.3隱藏刷新頭佈局 ,通過headView.setPadding(0,top,0,0); top=-headViewHeight 則剛好隱藏頭佈局
//控件只有在顯示的時候纔會分配寬和高,假如要在未顯示前使用控件的寬和高,需要先測量,再取得測量的寬和高
headerView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
headerViewHeight = headerView.getMeasuredHeight();
hideHeadView();
//2.4 初始化刷新頭的動畫
initAnimation();
}
private void initAnimation() {
upAnimation=createRotateAnimation(0,-180);
downAnimation=createRotateAnimation(-180,-360);
}
//創建旋轉動畫
private RotateAnimation createRotateAnimation(int fromDegrees, int toDegrees) {
RotateAnimation ro=new RotateAnimation(fromDegrees, toDegrees, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
ro.setFillAfter(true);//動畫停止停在最後一幀
ro.setDuration(500);
return ro;
}
//隱藏頭佈局
private void hideHeadView() {
setHeaderViewPadding(-headerViewHeight);
}
//設置頭佈局的paddingTop
public void setHeaderViewPadding(int paddingTop){
headerView.setPadding(0, paddingTop, 0, 0);
}
private void initFooterView() {
//尾部
footerView = View.inflate(getContext(), R.layout.foot_view, null);
//添加腳佈局到ListView
this.addFooterView(footerView);
//測量
footerView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
footerHeight = footerView.getMeasuredHeight();
//隱藏腳佈局
footerView.setPadding(0, -footerHeight, 0, 0);
//設置滾屏監聽
this.setOnScrollListener(new OnScrollListener() {
/**
* 當滾動狀態發生改變時回調
* 當處於空閒狀態,且當前最後一個顯示的item是列表中最後一個條目,則顯示腳部視圖
* OnScrollListener的三種狀態:
* SCROLL_STATE_FLING:快速滑動狀態,慣性滑動狀態,手指沒有接觸控件
* SCROLL_STATE_TOUCH_SCROLL:觸摸滑動狀態
* SCROLL_STATE_IDLE:空閒狀態
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(scrollState==OnScrollListener.SCROLL_STATE_IDLE&&getLastVisiblePosition()==getCount()-1&&!isLoadMore){
//顯示腳部視圖
footerView.setPadding(0, 0, 0, 0);
isLoadMore=true;
//把列表條目指向最後一個
setSelection(getCount()-1);
if(mListener!=null){
mListener.onLoadMore();
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
});
}
//事件觸摸處理
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN://按下去
downY = ev.getY(); //取得按下去的y的位置
break;
case MotionEvent.ACTION_MOVE://滑動
float moveY = ev.getY();
float dy=moveY-downY; //y方向的偏移量
//當向下滑動,即 moveY-downY>0 ,且listview第一個可見的item是listview的第一個列表條目 ,才滑出 刷新頭部
if(dy>0&&getFirstVisiblePosition()==0){
isPullToRrefresh=true;
int paddingTop=(int) (-headerViewHeight+dy); // -60 +20=-40
//設置頭佈局的paddingTop
setHeaderViewPadding(paddingTop);
//當paddingTop小於0(刷新頭部沒有完全可見),且當前不是下拉刷新狀態
if(paddingTop<0&& currentSate!=STATE_PULL_TO_REFRESH){
currentSate=STATE_PULL_TO_REFRESH;
updateHeadViewState();
}else if(paddingTop>=0&& currentSate!=STATE_RELEASE_TO_REFRESH){
currentSate=STATE_RELEASE_TO_REFRESH;
updateHeadViewState();
}
return true;
}
break;
case MotionEvent.ACTION_UP://擡起
if(isPullToRrefresh){
//處理下拉刷新的操作
if(currentSate==STATE_PULL_TO_REFRESH){
//當手指擡起時,且當前的狀態是下拉刷新,則隱藏刷新頭佈局
hideHeadView();
}else if(currentSate==STATE_RELEASE_TO_REFRESH){
currentSate=STATE_REFRESHING;
updateHeadViewState();
//調用下拉刷新回調方法
if(mListener!=null){
mListener.onRefreshing();
}
}
}
//本次下拉操作結束
isPullToRrefresh=false;
break;
}
return super.onTouchEvent(ev);
}
//頭佈局視圖狀態更新
private void updateHeadViewState() {
switch (currentSate) {
case STATE_PULL_TO_REFRESH:
//下拉刷新狀態
titleTv.setText("下拉刷新");
progressBar.setVisibility(View.INVISIBLE);
arrowIv.clearAnimation();
arrowIv.startAnimation(downAnimation);
break;
case STATE_RELEASE_TO_REFRESH:
//釋放刷新狀態
titleTv.setText("釋放刷新");
progressBar.setVisibility(View.INVISIBLE);
arrowIv.clearAnimation();
arrowIv.startAnimation(upAnimation);
break;
case STATE_REFRESHING:
titleTv.setText("正在刷新...");
//正在刷新狀態
arrowIv.clearAnimation();
arrowIv.setVisibility(View.INVISIBLE);
progressBar.setVisibility(View.VISIBLE);
setHeaderViewPadding(0); //顯示刷新頭部
/* if(mOnRefreshListener!=null){
mOnRefreshListener.onRefreshing();
}*/
break;
default:
break;
}
}
//設置監聽接口,實現下拉刷新和加載更多的事件回調
public static interface OnRefreshListener {
//下拉刷新回調的方法
void onRefreshing();
//加載更多的回調方法
void onLoadMore();
}
private OnRefreshListener mListener;
public void setOnRefreshListener(OnRefreshListener l){
mListener=l;
}
//刷新完成
public void setRefreshComplete() {
currentSate=STATE_PULL_TO_REFRESH;
hideHeadView();
titleTv.setText("下拉刷新");
progressBar.setVisibility(View.INVISIBLE);
arrowIv.setVisibility(View.VISIBLE);
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
lastTimeTv.setText( dateFormat.format(new Date()));
}
//加載更多完成
public void loadMoreComplete() {
//隱藏腳佈局
footerView.setPadding(0, -footerHeight, 0, 0);
isLoadMore=false;
}
}