1.定义个类继承ListView
添加头条目
添加脚条目
设置滚动监听(处理上啦加载)
重写触摸 事件(处理下拉刷新)
public class PullToReFreshListView extends ListView implements OnScrollListener {
private View headerView;
private int headermeasuredHeight;
private RotateAnimation up;
private RotateAnimation down;
private int downY;
/** 下拉刷新 **/
public static final int PULL_DOWN = 1;
/** 松开刷新 **/
public static final int RELEASE_REFRESH = 2;
/** 正在刷新 **/
public static final int REGFRESHING = 3;
/** 当前的状态 **/
public static int CURRENTSTATE = PULL_DOWN;
private ImageView mArrow;
private ProgressBar mPb;
private TextView mText;
private int footermeasuredHeight;
private View footerview;
/**是否加载更多,true:加载更多,false:没有加载更多**/
private boolean isLoadMore;
public PullToReFreshListView(Context context) {
// super(context);
this(context, null);
}
public PullToReFreshListView(Context context, AttributeSet attrs) {
// super(context, attrs);
this(context, attrs, 0);
}
public PullToReFreshListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
// 添加刷新头
addHeader();
// 添加底部条目
addFooter();
// 监听listview的滚动状态
setOnScrollListener(this);
}
/**
* 添加listview底部条目 2016-8-14 上午11:34:23
*/
private void addFooter() {
footerview = View.inflate(getContext(), R.layout.footer_item, null);
// 隐藏底部条目
footerview.measure(0, 0);
footermeasuredHeight = footerview.getMeasuredHeight();
footerview.setPadding(0, 0, 0, -footermeasuredHeight);
addFooterView(footerview);// 添加listview的底部条目
}
/**
* 添加listview的刷新头 2016-8-14 上午9:53:18
*/
private void addHeader() {
headerView = View.inflate(getContext(), R.layout.header_item, null);
// 初始化控件
mArrow = (ImageView) headerView.findViewById(R.id.arrow);
mPb = (ProgressBar) headerView.findViewById(R.id.pb);
mText = (TextView) headerView.findViewById(R.id.text);
// 隐藏刷新头
headerView.measure(0, 0);// 测量控件 测量规格为未指定
headermeasuredHeight = headerView.getMeasuredHeight();
headerView.setPadding(0, -headermeasuredHeight, 0, 0);
addHeaderView(headerView);// 将view对象,添加到listview的头部
initAnimation();
}
/**
* 初始化动画 2016-8-14 上午10:19:53
*/
private void initAnimation() {
// 箭头向上
up = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
up.setDuration(500);
up.setFillAfter(true);// 保持动画结束的状态
// 箭头向下
down = new RotateAnimation(-180, -360, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
down.setDuration(500);
down.setFillAfter(true);// 保持动画结束的状态
}
// 下拉显示刷新头操作
// 1.触摸listview
// 2.下拉操作
// 3.判断当前界面显示的第一个条目是否是listview的第一个条目,是下拉显示刷新头,不是,显示显示listview的其他条目
// 1.触摸listview
@Override
public boolean onTouchEvent(MotionEvent ev) {
// 2.下拉操作
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
int moveY = (int) ev.getY();
int distance = moveY - downY;
// 判断是否是下拉操作
// 3.判断当前界面显示的第一个条目是否是listview的第一个条目,是下拉显示刷新头,不是,显示显示listview的其他条目
// getFirstVisiblePosition : 获取当前界面显示的第一个条目的位置
if (distance > 0 && getFirstVisiblePosition() == 0) {
// 实现下拉显示刷新头
// 计算空白的区域
// 空白的区域 = 下拉的距离 - 刷新头的高度
int paddingTop = distance - headermeasuredHeight;
headerView.setPadding(0, paddingTop, 0, 0);
// 下拉刷新 -> 松开刷新
if (paddingTop > 0 && CURRENTSTATE == PULL_DOWN) {
CURRENTSTATE = RELEASE_REFRESH;
switchOption();
}
// 松开刷新 -> 下拉刷新
if (paddingTop < 0 && CURRENTSTATE == RELEASE_REFRESH) {
CURRENTSTATE = PULL_DOWN;
switchOption();
}
// 因为系统的listview无法显示空白区域的,所以使用系统的触摸事件会出问题,解决:不使用
return true;
}
break;
case MotionEvent.ACTION_UP:
// 松开刷新 -> 正在刷新,并且显示刷新头
if (CURRENTSTATE == RELEASE_REFRESH) {
CURRENTSTATE = REGFRESHING;
headerView.setPadding(0, 0, 0, 0);
switchOption();
// 刷新数据
if (onRefreshListener != null) {
onRefreshListener.regresh();
}
}
// 下拉刷新 -> 隐藏刷新头
if (CURRENTSTATE == PULL_DOWN) {
headerView.setPadding(0, -headermeasuredHeight, 0, 0);
}
break;
}
// 因为只有是下拉显示空白区域的时候才需要不使用系统的触摸事件,但是如果下拉不是空白区域,还是要使用系统的触摸事件,来实现下拉显示其他条目的操作的
return super.onTouchEvent(ev);
}
/**
* 根据状态更改控件的显示内容 2016-8-14 上午10:55:45
*/
private void switchOption() {
switch (CURRENTSTATE) {
case PULL_DOWN:
// 下拉刷新
mText.setText("下拉刷新");
mArrow.startAnimation(down);
break;
case RELEASE_REFRESH:
// 松开刷新
mText.setText("松开刷新");
mArrow.startAnimation(up);
break;
case REGFRESHING:
// 正在刷新
mText.setText("正在刷新");
mArrow.clearAnimation();// 清除动画
mArrow.setVisibility(View.GONE);
mPb.setVisibility(View.VISIBLE);
break;
}
}
// 取消刷新
/**
* 取消刷新 2016-8-14 上午11:25:34
*/
public void finish() {
// 正在刷新 -> 下拉刷新,并且隐藏刷新头
if (CURRENTSTATE == REGFRESHING) {
CURRENTSTATE = PULL_DOWN;
mText.setText("下拉刷新");
mPb.setVisibility(View.GONE);
mArrow.setVisibility(View.VISIBLE);
headerView.setPadding(0, -headermeasuredHeight, 0, 0);
}
//取消加载更多
//因为取消下拉刷新和上拉加载是在一个方法中,为了避免取消下拉刷新的时候,同时也会取消上拉加载,设置是否加载更多的标示
if (isLoadMore) {
footerview.setPadding(0, 0, 0, -footermeasuredHeight);
isLoadMore = false;
}
}
// 加载更多
// 1.监听listview的滚动状态,如果是停止滚动,显示加载更多条目,
// 2.上拉到listview的最后一个条目
// 当listview滚动状态改变的时候调用的方法
// scrollState : listview滚动的状态
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// 监听listview的滚动状态,如果是停止滚动,显示加载更多条目,上拉到listview的最后一个条目
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE
&& getLastVisiblePosition() == getCount() - 1 && isLoadMore == false) {
isLoadMore = true;
// 显示加载更多条目
footerview.setPadding(0, 0, 0, 0);
// 重新定位listview显示的最后一个条目
setSelection(getCount() - 1);// 跳转到listview的哪个条目,position : 条目的位置
// 加载更多数据
if (onRefreshListener != null) {
onRefreshListener.loadmore();
}
}
}
// 当listview滚动的时候调用的方法
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
}
// 回调函数实现刷新数据操作
// 3.创建保存接口实现对象的变量
public OnRefreshListener onRefreshListener;
// 2.创建获取接口实现对象的方法
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
this.onRefreshListener = onRefreshListener;
}
// 1.创建接口
public interface OnRefreshListener {
/** 下拉刷新 **/
public void regresh();
/**加载更多数据**/
public void loadmore();
}
public class MainActivity extends Activity {
private PullToReFreshListView mListView;
private int m;
private int n;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
/**
* 初始化控件
* 2016-8-14 上午9:31:39
*/
private void initView() {
mListView = (PullToReFreshListView) findViewById(R.id.listview);
final List<String> list = new ArrayList<String>();
//填充数据
for (int i = 0; i < 10; i++) {
list.add("德玛西亚"+i+"区");
}
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
mListView.setAdapter(arrayAdapter);
//刷新数据操作
mListView.setOnRefreshListener(new OnRefreshListener() {
@Override
public void regresh() {
//加载数据
//延迟一段时间,加载数据
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//list.add("艾欧尼亚"+(++m)+"区");
list.add(0, "艾欧尼亚"+(++m)+"区");//将数据添加list集合的哪个位置,location : 位置 object:添加的数据
//刷新界面
arrayAdapter.notifyDataSetChanged();
//取消刷新
mListView.finish();
}
}, 3000);//delayMillis : 延迟时间 Runnable : 执行的操作
}
@Override
public void loadmore() {
//延迟一段时间,加载数据
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//list.add("艾欧尼亚"+(++m)+"区");
list.add("黑色玫瑰"+(++n)+"区");//将数据添加list集合的哪个位置,location : 位置 object:添加的数据
//刷新界面
arrayAdapter.notifyDataSetChanged();
//取消刷新
mListView.finish();
}
}, 3000);//delayMillis : 延迟时间 Runnable : 执行的操作
}
});
}
3.布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.itheima.pulltorefreshlistview.PullToReFreshListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@android:color/darker_gray"
android:dividerHeight="0.5dp"
></com.itheima.pulltorefreshlistview.PullToReFreshListView>
</RelativeLayout>
4.头条目布局
<?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"
android:padding="6dp"
>
<RelativeLayout
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="20dp"
>
<ImageView
android:id="@+id/arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/arrow"
android:layout_centerInParent="true"
/>
<ProgressBar
android:id="@+id/pb"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerInParent="true"
android:indeterminateDrawable="@drawable/progressbarstyle"
android:visibility="gone"
/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center_vertical"
android:gravity="center_vertical|center_horizontal"
>
<!-- | : 加意思,两种效果全部生效 -->
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textColor="#FF0000"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最后刷时间:2016-08-14 09:48:06"
android:textColor="@android:color/darker_gray"
/>
</LinearLayout>
</LinearLayout>
5.脚条目布局文件
<?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"
android:gravity="center"
>
<ProgressBar
android:id="@+id/pb"
android:layout_width="30dp"
android:layout_height="30dp"
android:indeterminateDrawable="@drawable/progressbarstyle"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
/>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载更多..."
android:textColor="#FF0000"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
/>
</LinearLayout>