您的位置:首页 > 其它

ListView实现下拉刷新(三)实现下拉刷新

2015-10-10 15:36 204 查看
该准备的东西都已经准备好了。在这篇文章里,我们就开始实现下拉刷新功能吧。

一、大体的逻辑分析

我们来简单分析一下需要做的逻辑吧。首先分析头布局有几种状态。不下拉时,为正常状态,此时头布局隐藏。下拉到一定高度,提示信息变为“下拉刷新”,箭头朝下,此为下拉状态。再往下拉,提示信息变为“松开刷新”,箭头朝上,此为提示刷新状态。而此时松开手指,则执行刷新操作,头布局变为进度条显示,箭头消失,此为正在刷新状态。相反的,其他状态下松开手指,都不执行刷新操作,应该将头布局恢复到正常状态。因为可确定头布局的状态有四种。

我们根据这四种状态,确定我们要做的事情。要监听ListView的滚动,故要实现OnScrollListener接口。还要监听手指触摸事件,根据手指的下拉移动来改变头布局的显示效果,根据手指的抬起来判断是否进行刷新操作,因为要实现onTouchEvent方法。也就是说,头布局状态的改变应该随着手指的移动而改变,因此在onTouchEvent里面我们要实现上面分析的四种状态的改变。当然,状态改变就意味着头布局显示效果的改变,这里可以嵌套在onTouchEvent方法里面。但考虑到避免方法臃肿,以及其他地方可能也需要改变头布局界面,比如数据加载完成后等情况,因此专门将头布局界面的改变抽取出来,凝聚为一个方法。

然后就是数据刷新,刷新操作要在MyListView里执行,但是数据要在MainActivity中获取。老规矩,用接口回调即可。

好了,基本上大体的逻辑就这么多了。下面我们将上面的分析转化为代码。

二、代码编写

废话我就不多说了,上面的分析很清楚了。继续完善MyListView即可。代码如下:

package com.fuly.load;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MyListView extends ListView implements OnScrollListener{

private View header;//头布局

private int headerHeight;//头布局自身的高度

private int scrollState;//当前滚动状态
private int firstVisibleItem;//当前可见的第一个item
private int startY;//刚开始触摸屏幕时的Y值

private int curState = 0;//当前header状态,默认为0
private final int NORMAL = 0;//正常状态
private final int PULL = 1;//状态下拉
private final int RELEASE = 2;//提示刷新状态
private final int RELEASING = 3;//状态正在刷新

private boolean canPull = false;//是否可以执行下拉操作

private refresfListener mListener;//回调接口

//三个构造方法都要重写
public MyListView(Context context) {
super(context);
initView( context);

}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView( context);

}
public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView( context);

}

//定义回调接口
public interface refresfListener{
void refresh();
}
public void setOnRefreshListener(refresfListener listener){
this.mListener = listener;
}

public void initView(Context context){

header = LayoutInflater.from(context).inflate(R.layout.header, null);
notifyView(header);
headerHeight = header.getMeasuredHeight();//获取header的高度

//        headerHeight = header.getHeight();
paddingTop(-headerHeight);
//将头布局加进去
this.addHeaderView(header);

this.setOnScrollListener(this);
}

/**
* 该方法为通知父布局,子布局view的宽度和高度
* @param view:子布局
*/
private void notifyView(View view){

ViewGroup.LayoutParams p = view.getLayoutParams();

if(p == null){
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

}

//spec表示当前子view左右边距,padding表示子view的左右内边距
//childDimension:子view的宽度
int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);

int height;
int tempHeight = p.height;
if(tempHeight>0){
//子布局高度不为空,需要填充这个布局
height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
}else{
//高度为0,则不需要填充
height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}

//然后告诉父布局,子布局的高度和宽度
view.measure(width, height);
}

//该方法设定header的paddingTop
private void paddingTop(int pt){
header.setPadding(header.getPaddingLeft(), pt, header.getPaddingRight(), header.getPaddingBottom());
header.invalidate();
}

/***
* 监听当前滚动状态
* scrollState:当前滚动状态
*/
public void onScrollStateChanged(AbsListView view, int scrollState) {
//记录当前的滚动状态
this.scrollState = scrollState;

}

/***
* 监听当前滚动的item
* firstVisibleItem:当前可见的第一个item
* visibleItemCount:当前共有多少个item可见
* totalItemCount:总共有多少个item
*
*/
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {

this.firstVisibleItem = firstVisibleItem;

}

//触屏事件
public boolean onTouchEvent(MotionEvent ev) {

switch(ev.getAction()){
//手指落到屏幕上时
case MotionEvent.ACTION_DOWN:
//如果当前可见的第一个item为第0号,说明ListView位于顶端,可以执行下拉刷新
if(firstVisibleItem == 0){
canPull = true;
startY = (int) ev.getY();
}

break;
//手指在屏幕上拖动时
case MotionEvent.ACTION_MOVE:
if(canPull){
touchMove(ev);
}
break;
//手指离开屏幕时
case MotionEvent.ACTION_UP:
canPull = false;
if(curState == RELEASE){
curState = RELEASING;
refreshHeaderByState();
//这里添加刷新数据的逻辑
mListener.refresh();
}else{
curState = NORMAL;
refreshHeaderByState();
paddingTop(-headerHeight);
}

break;
}

return super.onTouchEvent(ev);
}

/**
* 该方法根据触摸屏幕滑动来改变STATE,即改变当前状态
* @param ev
*/
private void touchMove(MotionEvent ev) {

int tempY = (int) ev.getY();
int space = tempY -startY;//移动的距离
int topdding = space-headerHeight;
paddingTop(topdding);//即时设定头布局的隐藏高度
if(space>headerHeight&&space<headerHeight+50&&scrollState == SCROLL_STATE_TOUCH_SCROLL){
curState = PULL;//设定为下拉状态
refreshHeaderByState();
}
if(space>headerHeight+50){
curState = RELEASE;//设定为提示刷新状态
refreshHeaderByState();
}

if(space<headerHeight){
curState = NORMAL;//设定为正常状态
refreshHeaderByState();
}

}

/**
* 根据当前状态更改header的显示界面
*
*/
private void refreshHeaderByState( ){
ProgressBar pb = (ProgressBar) header.findViewById(R.id.progress_bar);
ImageView img = (ImageView) header.findViewById(R.id.img_arrow);
TextView tv = (TextView) header.findViewById(R.id.textinfo);

switch(curState){

case NORMAL:
pb.setVisibility(View.GONE);
img.setVisibility(View.VISIBLE);
img.setImageResource(R.drawable.down_arrow);
tv.setText("下拉刷新");
break;
case PULL:
pb.setVisibility(View.GONE);
img.setVisibility(View.VISIBLE);
img.setImageResource(R.drawable.down_arrow);
tv.setText("下拉刷新");
break;
case RELEASE:
pb.setVisibility(View.GONE);
img.setVisibility(View.VISIBLE);
img.setImageResource(R.drawable.up_arrow);
tv.setText("松开刷新");
break;
case RELEASING:
pb.setVisibility(View.VISIBLE);
img.setVisibility(View.GONE);
tv.setText("正在刷新");
break;

}

}

//数据刷新完成后的操作
public void refreshFinish(){

curState = NORMAL;
paddingTop(-headerHeight);
refreshHeaderByState();
}

}


接下来就是MainActivity中的代码了。如下:

package com.fuly.load;

import java.util.ArrayList;
import java.util.List;

import com.fuly.load.MyListView.refresfListener;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;

public class MainActivity extends Activity implements refresfListener{

private MyListView lv;
private List<MyData>  mDatas = new ArrayList<MyData>();
private MyAdapter mAdapter;

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initData();//该方法初始化数据
lv = (MyListView) findViewById(R.id.list_view);
lv.setOnRefreshListener(this);//设定回调接口
mAdapter = new MyAdapter(this, mDatas);
lv.setAdapter(mAdapter);

}

/**
* 该方法初始化数据,即提供初始的素材
*/
private void initData() {
for(int i = 0;i<12;i++){
MyData md = new MyData("你好,我是提前设定的");
mDatas.add(md);
}

}
/**
* 提供刷新数据
*/
private void getRefreshData() {
for(int i = 0;i<3;i++){
MyData md = new MyData("你好,我是刷新进来的");
mDatas.add(i, md);
}

}

//重写回调方法
public void refresh() {

//在这里之所以使用Handler,是想让操作延迟,这样子效果看起来更
//清晰,实际项目中,是 不需要的
Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable(){

@Override
public void run() {
//获得刷新数据
getRefreshData();
//刷新ListView
mAdapter.notifyDataSetChanged();
//lv.setSelection(mDatas.size()-1);

//刷新后
lv.refreshFinish();

}

}, 5000    );

}
}


好了,快快运行下程序,体验下拉刷新的效果吧。至此,ListView实现下拉刷新,我们讲解完毕了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: