自定义ListView下拉刷新效果,代码和图片资源都在下面贴出了。
首先先说一下,一般正常人都用不着手写下拉刷新,而且前辈说不要重复造轮子,所以我还是推荐大家用下拉刷新库,简单又便捷 0.0
先上效果图:
具体如下:
1.自定义ListView
List_View_Refresh.java代码如下:
package com.example.uitest.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.uitest.R;
public class List_View_Refresh extends ListView implements AbsListView.OnScrollListener {
private static final int PULL = 0; //下拉状态
private static final int RELEASE = 1; //释放状态
private static final int REFRESHING = 2; //正在刷新
private int status = 0; //当前的状态
private float startY; //手指按下的Y坐标
private int first_visibleView; //第一个可见item 的索引
private int header_height; //头布局的高度
private boolean canPULL = false; //是否可以下拉 (当first_visibleView == 0 时就可以下拉)
private View header; //头布局
private OnRefreshListener refreshListener;
private ProgressBar progressBar;
private ImageView mImg;
private TextView mTv;
public List_View_Refresh(Context context) {
super(context);
initView(context);
}
public List_View_Refresh(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public List_View_Refresh(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
/**
* 设置头布局顶部的padding值
*
* @param padding 头布局的paddingTop值
*/
private void setPadding(int padding) {
header.setPadding(0, padding, 0, 0);
}
/**
* 设置下拉刷新的接口回调
*
* @param listener 下拉刷新的接口
*/
public void setOnRefreshListener(OnRefreshListener listener) {
this.refreshListener = listener;
}
/**
* 下拉刷新的接口
*/
public interface OnRefreshListener {
void onRefresh(); //刷新的方法 (里面写刷新的操作)
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/**
* 滚动列表或网格时要调用的回调方法。 滚动完成后将调用此方法 (用于获取第一个可见item 的索引)
*
* @param view –正在报告其滚动状态的视图
* @param firstVisibleItem – *** 第一个可见单元格的索引 ***
* @param visibleItemCount –可见单元格的数量
* @param totalItemCount –列表适配器中的项目数
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
this.first_visibleView = firstVisibleItem;
}
/**
* 初始化头布局
*
* @param context – 上下文对象
*/
private void initView(Context context) {
header = inflate(context, R.layout.my_header, null); //加载头布局
header.measure(0, 0); //调用测量的方法 (这个我理解不深,说不太清楚)
header_height = header.getMeasuredHeightAndState(); //获得头布局的高度
setPadding(-header_height); //设置头布局的padding(这是自己写的方法)
addHeaderView(header); //添加头布局 (这是本来就有的方法)
progressBar = findViewById(R.id.progressBar);
mImg = findViewById(R.id.mImg);
mTv = findViewById(R.id.mTv);
this.setOnScrollListener(this); //设置列表滚动的监听 (就上面实现的那个接口AbsListView.OnScrollListener)
}
/**
* 触摸事件
*
* @param ev
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: //当手指按下
if (first_visibleView == 0) {
canPULL = true;
startY = ev.getY(); //获得手指按下的Y坐标
}
break;
case MotionEvent.ACTION_MOVE: //手指移动
if (canPULL) {
touchMove(ev); //响应这波操作
}
break;
case MotionEvent.ACTION_UP: //当手指抬起
canPULL = false;
if (status == RELEASE) {
status = REFRESHING;
} else {
status = PULL;
setPadding(-header_height);
}
refreshByStatus();
break;
}
return super.onTouchEvent(ev);
}
/**
* 这个方法用于响应手指拖动,改变头布局的paddingTop值
*
* @param event
*/
private void touchMove(MotionEvent event) {
float space = (event.getY() - startY);
setPadding((int) (space - header_height));
if (space >= header_height + 60) { //达到某个值时改变下拉的状态status
status = RELEASE;
} else {
status = PULL;
}
refreshByStatus();
}
/**
* 这个方法用于根据status(状态)改变头布局的样式
*/
private void refreshByStatus() {
switch (status) {
case PULL:
mTv.setText("下拉刷新");
mImg.setImageResource(R.mipmap.list_bt);
mImg.setVisibility(VISIBLE);
progressBar.setVisibility(GONE);
break;
case RELEASE:
mTv.setText("释放刷新");
mImg.setImageResource(R.mipmap.listtop);
break;
case REFRESHING:
mTv.setText("正在刷新");
mImg.setVisibility(GONE);
progressBar.setVisibility(VISIBLE);
if (refreshListener != null) {
refreshListener.onRefresh();
}
break;
}
}
/**
* 这个方法用于结束这次刷新时复原(刷新完成时)
*/
public void freshFinish() {
status = PULL;
refreshByStatus();
setPadding(-header_height);
}
}
2.头布局
my_header.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="80dp"
android:gravity="center">
<ProgressBar
android:id="@+id/progressBar"
style="@android:style/Widget.DeviceDefault.Light.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<ImageView
android:id="@+id/mImg"
android:layout_width="30dp"
android:layout_height="60dp"
app:srcCompat="@mipmap/list_bt" />
<TextView
android:id="@+id/mTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新" />
</LinearLayout>
3.使用代码
//模拟数据源
List<String> stringList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
stringList.add("这是一条测试数据" + i);
}
//设置适配器
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(mContext, R.layout.support_simple_spinner_dropdown_item, stringList);
listvTest.setAdapter(arrayAdapter);
//设置下拉刷新的接口回调
listvTest.setOnRefreshListener(new List_View_Refresh.OnRefreshListener() {
@Override
public void onRefresh() {
//添加数据
for (int i = 0; i < 5; i++) {
arrayAdapter.add("这是一条刷新的数据" + (stringList.size() - 1));
}
//模拟耗时操作
handler.postDelayed(new Runnable() {
@Override
public void run() {
listvTest.freshFinish(); //这个方法用于结束这次刷新时复原(刷新完成时)
}
}, 1000);
}
});