首先需要明确的是下拉刷新是一个布局文件是作为ListView的头布局HeaderView和加载更多的布局文件是作为ListView的脚布局
头布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp">
<ImageView
android:id="@+id/iv_arr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/common_listview_headview_red_arrow"/>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
android:id="@+id/progressBar"
android:layout_gravity="center" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#f00"
android:text="下拉刷新"/>
<TextView
android:id="@+id/tv_refresh_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_marginTop="5dp"
android:textColor="@android:color/darker_gray"
android:text="最后刷新时间:2015-03-16 07:16:16"/>
</LinearLayout>
</LinearLayout>
脚布局的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<ProgressBar
android:id="@+id/pb_pull_list_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"/>
<TextView
android:id="@+id/tv_pull_list_header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载中..."
android:textColor="#ff0000"
android:textSize="18sp" />
</LinearLayout>
我们需要重新一个RefreshListView来继承ListView
package com.example.administrator.smartbj.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.administrator.smartbj.R;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* 作者:Created by Kevin on 2016/1/16.
* 邮箱:
* 描述:下拉刷新的ListView
*/
public class RefreshListView extends ListView implements AbsListView.OnScrollListener {
private static final int STATE_PULL_REFRESH = 0; //下拉刷新
private static final int STATE_RELEASE_REFRESH = 1; //松开刷新
private static final int STATE_REFRESHING = 2; //正在刷新
private int mCurrentState = 0; //记录当前状态
private float startY;
private View mHeaderView;
private int mHeaderViewHeight;
private ImageView ivArr; //下拉刷新的箭头
private ProgressBar progressBar;// 刷新进度条
private TextView tvRefresh;// 刷新的状态
private TextView tvRefreshDate;//最后刷新时间
private RotateAnimation rotateUp;
private RotateAnimation rotateDown;
private View mFooterView;
private int mFooterViewMeasuredHeight;
public RefreshListView(Context context) {
super(context);
initHeaderView();
initFooterView();
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
initFooterView();
}
public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initHeaderView();
initFooterView();
}
/**
* 初始化头布局
*/
private void initHeaderView() {
mHeaderView = View.inflate(getContext(), R.layout.header_refresh, null);
this.addHeaderView(mHeaderView);
ivArr = (ImageView) mHeaderView.findViewById(R.id.iv_arr);
progressBar = (ProgressBar) mHeaderView.findViewById(R.id.progressBar);
tvRefresh = (TextView) mHeaderView.findViewById(R.id.tv_refresh);
tvRefreshDate = (TextView) mHeaderView.findViewById(R.id.tv_refresh_date);
initArrAnim();//初始化箭头上下的动画
mHeaderView.measure(0, 0);
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);//隐藏头布局
tvRefreshDate.setText(getCurrentTime());
}
/**
* 初始化脚布局
*/
private void initFooterView() {
mFooterView = View.inflate(getContext(), R.layout.refresh_listview_footer, null);
this.addFooterView(mFooterView);
mFooterView.measure(0, 0);
mFooterViewMeasuredHeight = mFooterView.getMeasuredHeight();
mFooterView.setPadding(0, -mFooterViewMeasuredHeight, 0, 0);//隐藏脚布局布局
this.setOnScrollListener(this);
}
//下拉刷新的触摸事件
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startY = ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
if (startY == 0) {
startY = ev.getRawY();
}
if (mCurrentState == STATE_REFRESHING) {
break;
}
float endY = ev.getRawY();
int dy = (int) (endY - startY + 0.5f);//偏移距离
if (dy > 0 && getFirstVisiblePosition() == 0) {//下拉并且当前是第一个item
//重新设置mHeaderView的padding
int padding = -mHeaderViewHeight + dy;
mHeaderView.setPadding(0, padding, 0, 0);
if (padding > 0 && mCurrentState != STATE_RELEASE_REFRESH) {
mCurrentState = STATE_RELEASE_REFRESH;
refreshState();
} else if (padding < 0 && mCurrentState != STATE_PULL_REFRESH) {
mCurrentState = STATE_PULL_REFRESH;
refreshState();
}
return true;
}
break;
case MotionEvent.ACTION_UP:
startY = 0; //重置
if (mCurrentState == STATE_RELEASE_REFRESH) {
mCurrentState = STATE_REFRESHING; //正在刷新
mHeaderView.setPadding(0, 0, 0, 0);//隐藏头布局
refreshState();
} else if (mCurrentState == STATE_PULL_REFRESH) {
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);//隐藏头布局
}
break;
}
return super.onTouchEvent(ev);
}
private void refreshState() {
switch (mCurrentState) {
case STATE_PULL_REFRESH:
tvRefresh.setText("下拉刷新");
ivArr.setVisibility(VISIBLE);
progressBar.setVisibility(INVISIBLE);
ivArr.startAnimation(rotateDown);
break;
case STATE_RELEASE_REFRESH:
tvRefresh.setText("松开刷新");
ivArr.setVisibility(VISIBLE);
progressBar.setVisibility(INVISIBLE);
ivArr.startAnimation(rotateUp);
break;
case STATE_REFRESHING:
tvRefresh.setText("正在刷新...");
ivArr.clearAnimation();//防止件箭头因动画未结束而不消失
ivArr.setVisibility(INVISIBLE);
progressBar.setVisibility(VISIBLE);
if (mListener != null) {
mListener.onRefresh();
}
break;
}
}
private void initArrAnim() {
//变为向上的箭头
rotateUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateUp.setDuration(500);
rotateUp.setFillAfter(true);
//变为向上的箭头
rotateDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateDown.setDuration(500);
rotateDown.setFillAfter(true);
}
OnRefreshListener mListener;
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
mListener = onRefreshListener;
}
public interface OnRefreshListener {
public void onRefresh();
public void onLoadMore();
}
/**
* 刷新完成后
*/
public void onRefreshComplete() {
if (isLoadingMore) {//加载更多则收起加载更多
isLoadingMore = false;
mFooterView.setPadding(0, -mFooterViewMeasuredHeight, 0, 0);
} else { //下拉刷新 收起下拉刷新
mCurrentState = STATE_PULL_REFRESH;
tvRefresh.setText("下拉刷新");
ivArr.setVisibility(VISIBLE);
progressBar.setVisibility(INVISIBLE);
//隐藏下拉刷新
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
tvRefreshDate.setText(getCurrentTime());
}
}
/**
* 获取当前时间
*
* @return 当前时间
*/
public String getCurrentTime() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
return format.format(new Date());
}
private boolean isLoadingMore;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) {
if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {//当划到最后一个的时候
System.out.println("到底了....");
this.setSelection(getCount() - 1);
mFooterView.setPadding(0, 0, 0, 0);
this.setSelection(getCount() - 1);
isLoadingMore = true;
//加载更多
if (mListener != null) {
mListener.onLoadMore();
}
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
}
最后再我们需要实现下拉刷洗和加载更多的页面设置监听回调后实现刷新后加载数据的功能即可。
listView.setOnRefreshListener(new RefreshListView.OnRefreshListener() {
@Override
public void onRefresh() {
getDataFromServer();
}
@Override
public void onLoadMore() {
if (!TextUtils.isEmpty(mMoreUrl)) {
getMoreDataFromServer();
} else {
Toast.makeText(mActivity, "已经到最后一页了", Toast.LENGTH_SHORT).show();
listView.onRefreshComplete();
}
}
});