指令汇B新闻客户端开发(三) 下拉刷新

现在我们继续这个新闻客户端的开发,今天分享的是下拉刷新的实现,我们都知道下拉刷新是一个应用很常见也很实用的功能。我这个应用是通过拉ListView来实现刷新的,先看一张刷新的原理图

从图中可知,手指移动的距离就是dy。

刷新分为三种状态:下拉刷新、正在刷新、松开刷新;

定义这三种状态为:

private static final int STATE_PULL_REFRESH = 0;// 下拉刷新
private static final int STATE_RELEASE_REFRESH = 1;// 松开刷新
private static final int STATE_REFRESHING = 2;// 正在刷新

接下来开始写我们的代码了

初始化头布局:

private void initHeaderView() {
		mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);
		this.addHeaderView(mHeaderView);

		tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
		tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);
		ivArrow = (ImageView) mHeaderView.findViewById(R.id.iv_arr);
		pbProgress = (ProgressBar) mHeaderView.findViewById(R.id.pb_progress);

		mHeaderView.measure(0, 0);
		mHeaderViewHeight = mHeaderView.getMeasuredHeight();

		mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏头布局

		initArrowAnim();

		tvTime.setText("最后刷新时间:" + getCurrentTime());
	}

初始化脚布局

 * 初始化脚布局
	 */
	private void initFooterView() {
		mFooterView = View.inflate(getContext(),
				R.layout.refresh_listview_footer, null);
		this.addFooterView(mFooterView);

		mFooterView.measure(0, 0);
		mFooterViewHeight = mFooterView.getMeasuredHeight();

		mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏

		this.setOnScrollListener(this);
	}

初始化箭头的动画:

/**
	 * 初始化箭头动画
	 */
	private void initArrowAnim() {
		// 箭头向上动画
		animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
				Animation.RELATIVE_TO_SELF, 0.5f);
		animUp.setDuration(200);
		animUp.setFillAfter(true);

		// 箭头向下动画
		animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF,
				0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		animDown.setDuration(200);
		animDown.setFillAfter(true);

	}

接下来是实现触摸的方法及偏移量的计算:

@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			startY = (int) ev.getRawY();
			break;
		case MotionEvent.ACTION_MOVE:
			if (startY == -1) {// 确保startY有效
				startY = (int) ev.getRawY();
			}

			if (mCurrrentState == STATE_REFRESHING) {// 正在刷新时不做处理
				break;
			}

			int endY = (int) ev.getRawY();
			int dy = endY - startY;// 移动偏移量

			if (dy > 0 && getFirstVisiblePosition() == 0) {// 只有下拉并且当前是第一个item,才允许下拉
				int padding = dy - mHeaderViewHeight;// 计算padding
				mHeaderView.setPadding(0, padding, 0, 0);// 设置当前padding

				if (padding > 0 && mCurrrentState != STATE_RELEASE_REFRESH) {// 状态改为松开刷新
					mCurrrentState = STATE_RELEASE_REFRESH;
					refreshState();
				} else if (padding < 0 && mCurrrentState != STATE_PULL_REFRESH) {// 改为下拉刷新状态
					mCurrrentState = STATE_PULL_REFRESH;
					refreshState();
				}

				return true;
			}

			break;
		case MotionEvent.ACTION_UP:
			startY = -1;// 重置

			if (mCurrrentState == STATE_RELEASE_REFRESH) {
				mCurrrentState = STATE_REFRESHING;// 正在刷新
				mHeaderView.setPadding(0, 0, 0, 0);// 显示
				refreshState();
			} else if (mCurrrentState == STATE_PULL_REFRESH) {
				mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
			}

			break;

		default:
			break;
		}
		return super.onTouchEvent(ev);
	}

刷新下拉控件的布局:

private void refreshState() {
		switch (mCurrrentState) {
		case STATE_PULL_REFRESH:
			tvTitle.setText("下拉刷新");
			ivArrow.setVisibility(View.VISIBLE);
			pbProgress.setVisibility(View.INVISIBLE);
			ivArrow.startAnimation(animDown);
			break;
		case STATE_RELEASE_REFRESH:
			tvTitle.setText("松开刷新");
			ivArrow.setVisibility(View.VISIBLE);
			pbProgress.setVisibility(View.INVISIBLE);
			ivArrow.startAnimation(animUp);
			break;
		case STATE_REFRESHING:
			tvTitle.setText("正在刷新...");
			ivArrow.clearAnimation();// 必须先清除动画,才能隐藏
			ivArrow.setVisibility(View.INVISIBLE);
			pbProgress.setVisibility(View.VISIBLE);

			if (mListener != null) {
				mListener.onRefresh();
			}
			break;

		default:
			break;
		}
	}

刷新完成之后我们需要收起这个下拉刷新的按钮,额,好吧,总的来说比较复杂了:

/*
	 * 收起下拉刷新的控件
	 */
	public void onRefreshComplete(boolean success) {
		if (isLoadingMore) {// 正在加载更多...
			mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏脚布局
			isLoadingMore = false;
		} else {
			mCurrrentState = STATE_PULL_REFRESH;
			tvTitle.setText("下拉刷新");
			ivArrow.setVisibility(View.VISIBLE);
			pbProgress.setVisibility(View.INVISIBLE);

			mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏

			if (success) {
				tvTime.setText("最后刷新时间:" + getCurrentTime());
			}
		}
	}

我们还可以看到上面有一个实时的时间,获取当前系统时间:

/**
	 * 获取当前时间
	 */
	public String getCurrentTime() {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return format.format(new Date());
	}

	private boolean isLoadingMore;

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		if (scrollState == SCROLL_STATE_IDLE
				|| scrollState == SCROLL_STATE_FLING) {

			if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {// 滑动到最后
			//	System.out.println("到底了.....");
				mFooterView.setPadding(0, 0, 0, 0);// 显示
				setSelection(getCount() - 1);// 改变listview显示位置

				isLoadingMore = true;

				if (mListener != null) {
					mListener.onLoadMore();
				}
			}
		}
	}

在新闻详情页里面要设置一下下拉刷新监听:

// 设置下拉刷新监听
		lvList.setOnRefreshListener(new OnRefreshListener() {

			@Override
			public void onRefresh() {
				getDataFromServer();
			}

			@Override
			public void onLoadMore() {
				if (mMoreUrl != null) {
					getMoreDataFromServer();
				} else {
					Toast.makeText(mActivity, "最后一页了", Toast.LENGTH_SHORT)
							.show();
					lvList.onRefreshComplete(false);// 收起加载更多的布局
				}
			}
		});

这里刷新功能基本上实现了,这里只写出了关键代码。

时间: 2024-09-24 04:26:15

指令汇B新闻客户端开发(三) 下拉刷新的相关文章

指令汇B新闻客户端开发(四) 自动轮播条

    在这个新闻客户端,我们可以看到有一个轮播页面,在这个项目中,用Handler和一个定时器来做更容易一些, 我们定义一个Handler: private Handler mHandler; 定时器的代码如下: // 自动轮播条显示 if (mHandler == null) { mHandler = new Handler() { public void handleMessage(android.os.Message msg) { int currentItem = mViewPager

指令汇B新闻客户端开发(一) 新手引导页开发

首先做开发的时候应该有一个闪屏页面和新手引导页, 我相信闪屏页面大家应该都会了,那么先看到新手引导页了. 我们可以看到这其实是一个ViewPager,我们也可以看到这是3个引导页,那么首先来看一下布局文件 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

指令汇B新闻客户端开发(六) 浅谈屏幕适配解决方案

     屏幕适配的问题,我相信很多大牛的经验远比我丰富,在此就简单的分享一下我所做的的屏幕适配方案,当然我说的是安卓方面的啦,嘿嘿,屏幕适配我们一般用1280*720的屏幕作为我们的主流开发屏,当然现在AndroidStudio上面可以直接看到所有种类的屏幕,大大方便了我们的开发.     我们遵循的原则是不用AbsoluteLayout(绝对布局),多用相对布局&线性布局(权重), 要用dp,不用px.     开发后期, 在不同分辨率屏幕上测试(480*800,1920*1080), 如果

指令汇B新闻客户端开发(五) ShareSdk的使用

ShareSdk是一个分享按钮的开源框架,我们首先可以去mob的官网下载这个控件.mob官网,然后找到sdk下载那一栏, 下载下来之后点击这个.jar文件就会有一个弹窗,填写自己的应用包名和要哪些分享,就会自动生成一个你包名相同的文件,我的是zhilinghiuB,然后去覆盖原来的那个文件就可以了. 我们需要在清单文件中添加必要的权限,具体权限可以去看mob官网开发者文档,然后再代码中添加如下代码: /** * 分享, 注意在sdcard根目录放test.jpg */ private void

开源中国iOS客户端学习 (二) 下拉刷新特效EGOTableViewPullRefresh

打开开源中国iOS客户端应用程序第一步就是加载数据,经常我们在第二次以后打开的时候,我们界面显示的是上一次更新的数据,此时我们想看最新内容就需要去刷新数据加载这些内容,加载需要一个等待过程,如何能让用户在等待过程中不焦急,能够等待这个过程完成,这就需要给用户一个心里安慰,让用户知道该软件正在很努力很努力的执行自己命令,这就需要我们为自己应用程序添加一些特效: 开源中国iOS客户端用到了不少特效,这些特效在当前很多应用软件中都比较流行,基本上这些特效都属于第三方类库,本次想说的是下拉刷新特效,EG

iOS开发-ios7下拉刷新,上提加载快速集成

在ios7之前,一直在使用开源的EGO库.但是,在使用过程中发现,普遍封装得过于复杂.耦合性强,不利于集成到自己的项目中. 另外,在ios7之后,一些原有的下拉刷新,上提加载控件表现的就不是那么出色了.除了可能出错外,也不符合扁平化的风格. 后来,在code4App上发现了一个大牛上传了一个开源代码, 仅需几行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能.可以自定义上下拉刷新的文字说明. 下载下来自己试了下,发现不错.  mark下. 下载链接:

安卓开发-自定义下拉刷新和图片轮播放到同一个布局里

问题描述 自定义下拉刷新和图片轮播放到同一个布局里 自定义下拉刷新和图片轮播放到同一个布局view_header里,直接加载这个布局,可以加载出来么? 解决方案 不清楚,感觉不可以.

安卓应用开发-安卓下拉刷新scroll view

问题描述 安卓下拉刷新scroll view 做一款安卓小应用 需要利用scrollview控件下拉刷新列表显示加载数据的代码. 解决方案 参考:http://blog.csdn.net/a6920502/article/details/8759244http://blog.csdn.net/a6920502/article/details/8779456 解决方案二: 可以试一下, PullToRefresh下拉刷新库http://blog.csdn.net/hantangsongming/a

android-Android下拉刷新控件如何进行开发

问题描述 Android下拉刷新控件如何进行开发 如何开发一个下拉刷新控件,怎么用,需要哪些技术,现在回一些基本的自定义控件技术 想自己开发一个 解决方案 可以参照一些有名的开发者,比如廖虎秋.去github上看一些著名的库 解决方案二: 可以参照一些有名的开发者,比如廖虎秋.去github上看一些著名的库 解决方案三: 可以参照一些有名的开发者,比如廖虎秋.去github上看一些著名的库 解决方案四: Android中的通用下拉刷新控件Android 下拉刷新控件之ScrollView版本实现