首页 > 代码库 > 下拉刷新功能的实现。

下拉刷新功能的实现。

下拉刷新的在android程序中很常见,自己也耐着性子完成了对它的具体实现。

首先你得知道刷新控件也是一个ListView,你用自己的方式实现了一个自定义ListView,

这个ListView具有下拉刷新功能。创建自己的ListView:

public class RefreshListView extends ListView implements OnScrollListener{
public RefreshListView(Context context) {
		super(context);
		initView(context);
	}
	public RefreshListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView(context);
	}
	public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		initView(context);
	}
}
包括了几个不同的构造方法。下拉时能显示“下拉刷新”是因为ListView能够设置一个头部View,initView(context)

初始化headerView。

private void initView(Context context){
		//LayoutInflater作用是加载布局
		LayoutInflater inflater = LayoutInflater.from(context);
		header = inflater.inflate(R.layout.header_layout, null);
	        measureView(header);
		headerHeight = header.getMeasuredHeight();
		Log.i("headerHeight", ""+headerHeight);
	        topPadding(-headerHeight);
		this.addHeaderView(header);
		this.setOnScrollListener(this);
		
		Time t = new Time();
		t.setToNow();
		updateTime = t.hour*60+t.minute;
		Log.i(TAG, "init--->"+updateTime);
	}
把headerView放入布局中,总得告诉父布局你所占用的宽和高啊!调用measuerView()方法进行初始化。

private void measureView(View view){
		//LayoutParams are used by views to tell their parents 
		//how they want to be laid out.
		//LayoutParams被view用来告诉它们的父布局它们应该被怎样安排
		ViewGroup.LayoutParams p = view.getLayoutParams();
		if(p==null){
			//两个参数:width,height
			p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
					ViewGroup.LayoutParams.WRAP_CONTENT);
		}
		//getChildMeasureSpec:获取子View的widthMeasureSpec、heightMeasureSpec值,
        //之所以widthMeasureSpec和heightMeasureSpec的获取方法不一样是因为listview中不限定高度
        // 但是限定了宽度
		int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
		int height;
		int tempHeight = p.height;
		if(tempHeight>0){
			height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
		}else{
			height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
		}
		view.measure(width, height);
	}
toPadding ()方法用于设定headerView的头边距,用于进行隐藏和显示以及拖动,初始化为隐藏。

private void topPadding(int topPadding){
		//设置顶部提示的边距
		//除了顶部用参数值topPadding外,其他三个用header默认的值
		header.setPadding(header.getPaddingLeft(), topPadding, 
				header.getPaddingRight(), header.getPaddingBottom());
		//使header无效,将来调用onDraw()重绘View
	    <span style="white-space:pre">	</span>header.invalidate();
	}
实现OnScrollListener接口主要是为了监听手指是否在屏幕上面,还有就是当前界面上的的第一个

ListItem是否是的第一个item。(当在ListView顶部的时候才能下拉刷新)

@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		// TODO Auto-generated method stub
		this.scrollState = scrollState;
	}
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		// TODO Auto-generated method stub
		this.firstVisibleItem = firstVisibleItem;
	}
重载onTouchEvent 监听用户手势状态包括按下,滑动,以及放开状态。

@Override
	public boolean onTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			if(firstVisibleItem == 0){
				isFlag = true;//ListView最顶端按下,标志值设为真
				startY = (int)ev.getY();
			}
			break;
		case MotionEvent.ACTION_MOVE:
            Time t = new Time();
            t.setToNow();
            System.out.println(t.hour + "时" + t.minute + "分" + t.second + "秒");
            onMove(ev);
			break;
		case MotionEvent.ACTION_UP:
			if(state == RELEASE){
				state = REFRESH;
				//加载数据
				refreshViewByState();
				iRefreshlistener.onRefresh();
			}else if(state == PULL){
				state = NONE;
				isFlag = false;
				refreshViewByState();
			}
			break;
		}
		return super.onTouchEvent(ev);
	}
private void onMove(MotionEvent ev){
		//如果不是最顶端按下,则直接返回
		if(!isFlag){
			return;
		}
		int currentY = (int)ev.getY();//当前的Y值
		int space = currentY - startY;//用户向下拉的距离
		int topPadding = space - headerHeight;//顶部提示View距顶部的距离值
		switch (state) {
		//正常状态
		case NONE:
			if(space>0){
				state = PULL;//下拉的距离大于0,则将状态改为PULL(提示下拉更新)
				refreshViewByState();//根据状态的不同更新View
			}
			break;
        case PULL:
        	topPadding(topPadding);
			if(space>headerHeight+30//下拉的距离大于header的高度加30且用户滚动屏幕,手指仍在屏幕上
					&&scrollState == SCROLL_STATE_TOUCH_SCROLL ){
				state = RELEASE;//将状态改为RELEASE(提示松开更新)
				refreshViewByState();
			}
			break;
        case RELEASE:
            if(topPadding > headerHeight + 50){
                topPadding = headerHeight + 50;
            }
        	topPadding(topPadding);
        	if(space<headerHeight+30){//用户下拉的距离不够
				state = PULL;         //将状态改为PULL
				refreshViewByState();
			}else if(space<=0){  //用户下拉的距离为非正值
				state = NONE;    //将状态改为NONE
				isFlag = false;  //标志改为false
				refreshViewByState();
			}
			break;
		}
根据用户的滑动距离改变state的值,并调用refreshViewByState()方法根据state更新控件的显示方式。

private void refreshViewByState(){
		//提示
		TextView tips = (TextView)header.findViewById(R.id.tips);
		//箭头
		ImageView arrow = (ImageView)header.findViewById(R.id.arrow);
		//进度条
		ProgressBar progress = (ProgressBar)header.findViewById(R.id.progress);
		//箭头的动画效果1,由0度转向180度,即箭头由朝下转为朝上
		RotateAnimation animation1 = new RotateAnimation(0, 180,
				RotateAnimation.RELATIVE_TO_SELF,0.5f,
				RotateAnimation.RELATIVE_TO_SELF,0.5f);
		animation1.setDuration(500);
		animation1.setFillAfter(true);
		//箭头的动画效果2,由180度转向0度,即箭头由朝上转为朝下
		RotateAnimation animation2 = new RotateAnimation(180, 0,
				RotateAnimation.RELATIVE_TO_SELF,0.5f,
				RotateAnimation.RELATIVE_TO_SELF,0.5f);
		animation2.setDuration(500);
		animation2.setFillAfter(true);
		
		switch (state) {
		case NONE:                     //正常状态
			arrow.clearAnimation();    //清除箭头动画效果
			topPadding(-headerHeight); //设置header距离顶部的距离
			break;

		case PULL:                                //下拉状态
			arrow.setVisibility(View.VISIBLE);    //箭头设为可见
			progress.setVisibility(View.GONE);    //进度条设为不可见
			tips.setText("下拉可以刷新");              //提示文字设为"下拉可以刷新"
			arrow.clearAnimation();               //清除之前的动画效果,并将其设置为动画效果2
			arrow.setAnimation(animation2);
			break;
 
		case RELEASE:                            //释放状态
			arrow.setVisibility(View.VISIBLE);   //箭头设为可见
			progress.setVisibility(View.GONE);   //进度条设为不可见
			tips.setText("松开可以刷新");             //提示文字设为"松开可以刷新"
			arrow.clearAnimation();              //清除之前的动画效果,并将其设置为动画效果2
			arrow.setAnimation(animation1);
			break;

		case REFRESH:                             //更新状态
			topPadding(50);                       //距离顶部的距离设置为50
			arrow.setVisibility(View.GONE);       //箭头设为不可见
			progress.setVisibility(View.VISIBLE); //进度条设为可见
			tips.setText("正在刷新...");          //提示文字设为""正在刷新..."
			arrow.clearAnimation();               //清除动画效果
			break;

		}
这就是下拉刷新实现的流程了。








下拉刷新功能的实现。