RefreshListView

public class RefreshListView extends ListView {
	private HeaderHelper mHeaderHelper;
	private float lastY;
	private float lastX;
	private FooterHelper mFooterHelper;
	private Transform currentHelper;

	public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	public RefreshListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public RefreshListView(Context context) {
		super(context);
		init();
	}

	public void setLoadMore(boolean b) {
		mFooterHelper.setEnabled(b);
	}

	public boolean isFree() {
		return !mHeaderHelper.isRefresh() && !mFooterHelper.isLoadingMore();
	}

	private void init() {
		initValueAnimator();
		mHeaderHelper = new HeaderHelper();
		mFooterHelper = new FooterHelper();
		mHandler = new Handler();
		setOverScrollMode(OVER_SCROLL_NEVER);
	}

	private void startAnimator(Transform helper, int current, int target) {
		this.currentHelper = helper;
		mAnim.setIntValues(current, target);
		mAnim.start();
	}

	private void initValueAnimator() {
		mAnim = new ValueAnimator();
		mAnim.addUpdateListener(new AnimatorUpdateListener() { // 监听值的变化
			public void onAnimationUpdate(ValueAnimator animator) {
				int value = (Integer) animator.getAnimatedValue();// 运行当前时间点的一个值
				if (currentHelper != null) {
					currentHelper.setPaddingTop(value);
				}
			}
		});
		mAnim.addListener(new AnimatorListener() {
			public void onAnimationStart(Animator animation) {
			}

			public void onAnimationRepeat(Animator animation) {
			}

			public void onAnimationEnd(Animator animation) {
				if (currentHelper != null) {
					currentHelper.finish();
					currentHelper = null;
				}
			}

			public void onAnimationCancel(Animator animation) {
			}
		});
		mAnim.setDuration(250);
	}

	boolean mRefreshVisable = false;

	@SuppressLint("ClickableViewAccessibility")
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction() & MotionEvent.ACTION_MASK) {
			case MotionEvent.ACTION_DOWN:
				mRefreshVisable = false;
				lastY = ev.getRawY();
				lastX = ev.getRawX();
				break;
			case MotionEvent.ACTION_MOVE:
				if (Math.abs(ev.getRawY() - lastY) > Math.abs(ev.getRawX() - lastX)
						&& mHeaderHelper.offset(ev.getRawY() - lastY)) {
					mRefreshVisable = true;
					lastY = ev.getRawY();
					lastX = ev.getRawX();
					return true;
				} else if (mRefreshVisable) {
					mRefreshVisable = false;
					ev.setAction(MotionEvent.ACTION_CANCEL);
				}
				lastY = ev.getRawY();
				lastX = ev.getRawX();
				break;
			case MotionEvent.ACTION_UP:
				mHeaderHelper.offsetComplete();
				if (mRefreshVisable) {
					mRefreshVisable = false;
					ev.setAction(MotionEvent.ACTION_CANCEL);
				}
				break;
			case MotionEvent.ACTION_CANCEL:
				mHeaderHelper.offsetComplete();
				break;
		}
		try {
			return super.onTouchEvent(ev);
		} catch (Exception e) {
		}
		return false;
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
			case MotionEvent.ACTION_DOWN:
				lastY = ev.getRawY();
				lastX = ev.getRawX();
				break;
		}
		return super.onInterceptTouchEvent(ev);
	}

	private OnRefreshListener listener;
	private Handler mHandler;
	private ValueAnimator mAnim;

	public void setOnRefreshListener(OnRefreshListener listener) {
		this.listener = listener;
	}

	public static interface OnRefreshListener {
		void onPullRefresh();

		void onLoadingMore();
	}

	public void complete() {
		boolean isChange = false;
		if (mHeaderHelper.isRefresh()) {
			mHeaderHelper.completeRefresh();
			isChange = true;
		}
		if (mFooterHelper.isLoadingMore()) {
			mFooterHelper.completeLoadingMore();
			isChange = true;
		}
		if (isChange)
			invalidateViews();
	}

	private class HeaderHelper implements Transform {
		/**
		 * 下拉刷新的状态
		 */
		final int PULL_REFRESH = 0;
		/**
		 * 松开刷新的状态
		 */
		final int RELEASE_REFRESH = 1;
		/**
		 * 正在刷新的状态
		 */
		final int REFRESHING = 2;
		int currentState;
		private View header;
		private int headerHeight;
		private RotateAnimation upAnimation;
		private RotateAnimation downAnimation;
		private int currentPaddingTop;
		private View arrow;
		private View progress;
		private TextView hint;
		private TextView time;
		Runnable r;
		private long pullRefreshTimeMillis;

		HeaderHelper() {
			r = new Runnable() {
				public void run() {
					currentState = PULL_REFRESH;
					// setPaddingTop(-headerHeight);
					startAnimator(HeaderHelper.this, currentPaddingTop,
							-headerHeight);
				}
			};
			header = View.inflate(getContext(), R.layout.refreshable_header,
					null);
			header.measure(0, 0);
			headerHeight = header.getMeasuredHeight();
			setPaddingTop(-headerHeight);
			addHeaderView(header);
			currentState = PULL_REFRESH;
			initRotateAnimation();

			arrow = header.findViewById(R.id.arrow);
			progress = header.findViewById(R.id.progress);
			hint = (TextView) header.findViewById(R.id.hint);
			time = (TextView) header.findViewById(R.id.data);

		}

		public void setPaddingTop(int top) {
			if(top<-headerHeight)top = -headerHeight;
			this.currentPaddingTop = top;
			header.setPadding(0, top, 0, 0);
		}

		/**
		 * 返回true 时表示将要消耗此次事件
		 *
		 * @param dy
		 * @return
		 */
		boolean offset(float dy) {
			if (isOffsetable()) {
				setPaddingTop((int) (currentPaddingTop+dy*0.5f));
				if (currentPaddingTop > 0 && currentState != RELEASE_REFRESH) {
					currentState = RELEASE_REFRESH;
					refreshViewForState();
				} else if (currentPaddingTop <= 0
						&& currentState != PULL_REFRESH) {
					currentState = PULL_REFRESH;
					refreshViewForState();
				}
				return true;
			}
			return false;
		}

		/**
		 * 在onTouchUp时调用
		 */
		void offsetComplete() {
			if (isOffsetable()) {
				if (currentPaddingTop > 0) {
					currentState = REFRESHING;
					// setPaddingTop(0);
					startAnimator(this, currentPaddingTop, 0);
					if (listener != null) {
						listener.onPullRefresh();
						pullRefreshTimeMillis = System.currentTimeMillis();
					}
				} else {
					// setPaddingTop(-headerHeight);
					startAnimator(this, currentPaddingTop, -headerHeight);
				}
				refreshViewForState();
			}
		}

		void completeRefresh() {
			mHandler.postDelayed(new Runnable() {
				public void run() {
					hint.setText("刷新完成");
					time.setText("最后更新时间:" + getCurrentTime());
					progress.setVisibility(View.INVISIBLE);
					mHandler.postDelayed(r, 1000);
				}
			}, getDelayed());
		}

		long getDelayed() {
			return Math
					.max(0,
							1500 - (System.currentTimeMillis() - pullRefreshTimeMillis));
		}

		private CharSequence getCurrentTime() {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",
					Locale.CHINA);
			return sdf.format(new Date());
		}

		/**
		 * 是否可以调整headerView
		 *
		 * @param dy
		 * @return
		 */
		boolean isOffsetable() {
			return isFree() && currentState != REFRESHING
					&& !canScrollVertically(-1);
		}

		void refreshViewForState() {
			switch (currentState) {
				case PULL_REFRESH:
					hint.setText("下拉刷新");
					arrow.setVisibility(View.VISIBLE);
					arrow.startAnimation(downAnimation);
					break;
				case RELEASE_REFRESH:
					arrow.setVisibility(View.VISIBLE);
					hint.setText("释放刷新");
					arrow.startAnimation(upAnimation);
					break;
				case REFRESHING:
					hint.setText("正在刷新");
					arrow.clearAnimation();
					arrow.setVisibility(View.INVISIBLE);
					progress.setVisibility(View.VISIBLE);
					break;
			}
		}

		boolean isRefresh() {
			return currentState == REFRESHING;
		}

		void initRotateAnimation() {
			upAnimation = new RotateAnimation(0, -180,
					Animation.RELATIVE_TO_SELF, 0.5f,
					Animation.RELATIVE_TO_SELF, 0.5f);
			upAnimation.setDuration(100);
			upAnimation.setFillAfter(true);
			downAnimation = new RotateAnimation(-180, -360,
					Animation.RELATIVE_TO_SELF, 0.5f,
					Animation.RELATIVE_TO_SELF, 0.5f);
			downAnimation.setDuration(100);
			downAnimation.setFillAfter(true);
		}

		@Override
		public void finish() {
			refreshViewForState();
		}
	}

	private class FooterHelper implements OnScrollListener, Transform,
			OnClickListener {
		boolean mLoading;
		private View footer;
		private int footerHeight;
		Runnable r;
		private TextView tv;
		private View progress;
		private long loadingMoreTimeMillis;
		private boolean mEnabled = false;

		FooterHelper() {
			r = new Runnable() {
				public void run() {
					mLoading = false;
					// setPaddingTop(-footerHeight);
					startAnimator(FooterHelper.this, 0, -footerHeight);

				}
			};

			mLoading = false;
			footer = View.inflate(getContext(), R.layout.refreshable_footer,
					null);
			footer.setOnClickListener(this);
			tv = (TextView) footer.findViewById(R.id.tv);
			progress = footer.findViewById(R.id.progress);
			progress.setVisibility(View.INVISIBLE);
			footer.measure(0, 0);
			footerHeight = footer.getMeasuredHeight();
			addFooterView(footer);
			if (!mEnabled)
				setPaddingTop(-footerHeight);
			setOnScrollListener(this);
		}

		public void setEnabled(boolean b) {
			if (mEnabled == b)
				return;
			mEnabled = b;
			if (mEnabled) {
				setPaddingTop(0);
			} else {
				setPaddingTop(-footerHeight);
			}
		}

		boolean isLoadingMore() {
			return mLoading;
		}

		public void setPaddingTop(int top) {
			footer.setPadding(0, top, 0, 0);
		}

		void completeLoadingMore() {
			mHandler.postDelayed(new Runnable() {

				@Override
				public void run() {
					tv.setText("加载完成");
					progress.setVisibility(View.INVISIBLE);
					mHandler.postDelayed(r, 1000);
				}
			}, getDelayed());
		}

		long getDelayed() {
			return Math
					.max(0,
							1500 - (System.currentTimeMillis() - loadingMoreTimeMillis));
		}

		public void onScrollStateChanged(AbsListView view, int scrollState) {
			if (scrollState == OnScrollListener.SCROLL_STATE_IDLE
					&& getLastVisiblePosition() == (getCount() - 1)) {
				loadMore();
			}
		}

		public void onScroll(AbsListView view, int firstVisibleItem,
							 int visibleItemCount, int totalItemCount) {
		}

		@Override
		public void finish() {
			setPaddingTop(0);
			if (!mLoading) {
				tv.setText("加载更多...");
			}
		}

		@Override
		public void onClick(View v) {
			loadMore();
		}

		private void loadMore() {
			if (mLoading || !isFree() || !mEnabled)
				return;
			mLoading = true;
			// startAnimator(this, -footerHeight, 0);
			// postDelayed(r2, 50);
			setSelection(getCount());
			if (listener != null) {
				listener.onLoadingMore();
				progress.setVisibility(View.VISIBLE);
				tv.setText("正在加载……");
				loadingMoreTimeMillis = System.currentTimeMillis();
			}
		}
	}

	private interface Transform {
		void setPaddingTop(int top);

		void finish();
	}

}

转载于:https://my.oschina.net/SSS555/blog/838545

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值