您的位置:首页 > 移动开发 > Android开发

android 开发笔记 自定义可下拉刷新上拉加载的ListView

2016-11-22 18:16 465 查看
后续可以根据自己需求更改头布局和尾布局,不多说直接上代码

这是我们自定义的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(OnRefreshL
4000
istener 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);
}
});
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android listview 布局