后续可以根据自己需求更改头布局和尾布局,不多说直接上代码
这是我们自定义的ListView
public class MyPullToRefreshListView extends ListView implements AbsListView.OnScrollListener,ValueAnimator.AnimatorUpdateListener {
private int index = 0;//当前listview处于的位置 0代表头部,1代表中间,2代表尾部
private View headerView,footerView;
private TextView headerTv,footerTv;
private int mode = 0;//0代表完成 1代表下拉刷新 2代表释放立即刷新 3代表正在刷新 4代表上拉加载 5代表释放立即加载 6代表正在加载
private final int DONE = 0;
private final int DOWN_TO_REFRESH = 1;
private final int RELEASE_TO_REFRESH = 2;
private final int REFRESHING = 3;
private final int UP_TO_LOAD = 4;
private final int RELEASE_TO_LOAD = 5;
private final int LOADING = 6;
private ValueAnimator animator;
private PointF p;
private int layoutHeight; //头的高度
private int lineHeight = 50; //释放刷新的高度
private int rote = 3;//设置刷新的距离比较缓慢
//加载和刷新的监听事件
public interface OnRefreshListener{
//正在加载
void onLoad();
//正在刷新
void onRefresh();
}
private OnRefreshListener listener;
public void setOnRefreshListener(OnRefreshListener listener) {
this.listener = listener;
}
public MyPullToRefreshListView(Context context) {
super(context);
init();
}
public MyPullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
//按下
p = new PointF();
p.x = ev.getX();
p.y = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
//获取现在的位置
PointF m = new PointF();
m.x = ev.getX();
m.y = ev.getY();
int disx = (int) (m.y - p.y)/rote;
//如果在头部
if(index == 0){
if(disx<=0){
return super.dispatchTouchEvent(ev);//事件向下分发
}
//处理下拉的操作,如果正在刷新数据或者正在加载,就不处理
if(mode != REFRESHING && mode != LOADING){
//设置现在的状态是下拉刷新
mode = DOWN_TO_REFRESH;
selectMode();
//慢慢地看到头
headerView.setPadding(0,-layoutHeight+disx,0,0);
//判断是否达到临界值
if(-layoutHeight+disx >=lineHeight){
//设置现在状态是释放立即刷新
mode = RELEASE_TO_REFRESH;
selectMode();
}
return true;//事件在此进行处理
}
}
//尾部
else if(index == 2){
if(disx >= 0){
return super.dispatchTouchEvent(ev);//事件向下进行分发
}
//处理上拉的操作,如果正在刷新数据或者正在加载,就不处理
if(mode != REFRESHING && mode != LOADING){
//将listview定位到尾部
ListAdapter adapter = getAdapter();
setSelection(adapter.getCount()-1);
//设置现在的状态上拉加载
mode = UP_TO_LOAD;
selectMode();
disx = Math.abs(disx);
//慢慢地看到尾部
footerView.setPadding(0,0,0,-layoutHeight+disx);
//到达临界值
if(-layoutHeight+disx >= lineHeight){
//设置现在的状态释放立即加载
mode = RELEASE_TO_LOAD;
selectMode();
}
return true;//事件在此进行处理
}
}else{
//改变开始的位置
p = m;
}
break;
case MotionEvent.ACTION_UP:
//如果不是正在加载或者正在刷新
if(mode != REFRESHING && mode != LOADING){
//判断是否已经到达临界点
if(mode == RELEASE_TO_REFRESH){ //释放立即刷新
//显示正在刷新
mode = REFRESHING;
selectMode();
if(listener!=null){
listener.onRefresh();
}
animator.setIntValues(headerView.getPaddingTop(),0);
animator.start();
}else if(mode == RELEASE_TO_LOAD){ //释放立即加载
mode = LOADING;
selectMode();
if(listener!=null){
listener.onLoad();
}
animator.setIntValues(footerView.getPaddingBottom(),0);
animator.start();
}else if(mode == DOWN_TO_REFRESH){ //下拉刷新
//隐藏头部
animator.setIntValues(headerView.getPaddingTop(),-layoutHeight);
animator.start();
}else if(mode == UP_TO_LOAD){ //上拉加载
//隐藏尾部
animator.setIntValues(footerView.getPaddingBottom(),-layoutHeight);
animator.start();
}
}
break;
}
return super.dispatchTouchEvent(ev); //事件向下分发
}
//设置刷新完成
public void complete(){
animator.setIntValues(0,-layoutHeight);
animator.start();
//设置完成
mode = DONE;
selectMode();
}
//根据状态设置Listview的位置
public void selectMode(){
switch (mode){
case DONE:
//隐藏头和尾
headerView.setPadding(0,-layoutHeight,0,0);
footerView.setPadding(0,0,0,-layoutHeight);
break;
case DOWN_TO_REFRESH:
//下拉刷新
headerTv.setText(R.string.DownToRefresh);
break;
case UP_TO_LOAD:
//上拉加载
footerTv.setText(R.string.UpToLoad);
break;
case RELEASE_TO_REFRESH:
//释放立即刷新
headerTv.setText(R.string.UpToRefresh);
break;
case RELEASE_TO_LOAD:
//释放立即加载
footerTv.setText(R.string.DownToLoad);
break;
case REFRESHING:
//正在刷新
headerTv.setText(R.string.Refreshing);
break;
case LOADING:
//正在加载
footerTv.setText(R.string.Loading);
break;
}
}
//初始化信息
public void init(){
//获取头和尾的高度
layoutHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getContext().getResources().getDisplayMetrics());
//设置listview的滑动监听事件
setOnScrollListener(this);
//加头和加尾部
headerView = View.inflate(getContext(), R.layout.refresh,null);
footerView = View.inflate(getContext(),R.layout.refresh,null);
headerTv = (TextView) headerView.findViewById(R.id.refresh_tv);
footerTv = (TextView) footerView.findViewById(R.id.refresh_tv);
//设置头部隐藏
//设置尾部隐藏
selectMode();
addHeaderView(headerView);
addFooterView(footerView);
animator = new ValueAnimator();
animator.setDuration(500);
animator.addUpdateListener(this);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/**
*
* @param view
* @param firstVisibleItem 当前可见的第一个item的位置
* @param visibleItemCount 当前可见item的总个数
* @param totalItemCount //listview的总个数
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if(firstVisibleItem == 0){
//处于头部
index = 0;
}else if(firstVisibleItem + visibleItemCount == totalItemCount){
//处于尾部
index = 2;
}else{
//处于中间
index = 1;
}
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//改变header的pading
if(mode == REFRESHING || mode == DOWN_TO_REFRESH){
headerView.setPadding(0,(Integer)animation.getAnimatedValue(),0,0);
}
if(mode == LOADING || mode == UP_TO_LOAD){
footerView.setPadding(0,0,0,(Integer)animation.getAnimatedValue());
}
}
}
下面是头和尾的布局文件,根据需求更改
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:id="@+id/refresh_tv"
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="22sp"
android:text="@string/Done"
android:gravity="center"/>
</LinearLayout>
Activity调用代码
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (MyPullToRefreshListView) findViewById(R.id.mylist);
datas = new ArrayList<>();
for (int i = 0; i < 15; i++) {
datas.add("测试数据"+i);
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,datas);
listView.setAdapter(adapter);
listView.setOnRefreshListener(new MyPullToRefreshListView.OnRefreshListener() {
@Override
public void onLoad() {
//模拟加载数据
listView.postDelayed(new Runnable() {
@Override
public void run() {
listView.complete();
}
},2000);
}
@Override
public void onRefresh() {
//模拟刷新数据
listView.postDelayed(new Runnable() {
@Override
public void run() {
listView.complete();
}
},2000);
}
});
}