Android修炼之道—可回弹的ListView

。。
添加HeadView和FootView

/**
	 * 初始化
	 */
	@SuppressWarnings("deprecation")
	private void init(boolean isHeadViewNeed, boolean isTailViewNeed) {
		Log.d(TAG, "isHeadViewNeed=" + isHeadViewNeed);
		Log.d(TAG, "isTailViewNeed=" + isTailViewNeed);
		if(isHeadViewNeed) {
			// 监听滚动状态
			setOnScrollListener(this);
			// 创建PullListView的HeadView
			mHeadView = new View(this.getContext());
			// 默认白色背景,可以改变颜色, 也可以设置背景图片
			mHeadView.setBackgroundColor(Color.parseColor("#4F9D9D"));
			// 默认高度为0
			mHeadView.setLayoutParams(new AbsListView.LayoutParams(
					LayoutParams.FILL_PARENT, 0));
			this.addHeaderView(mHeadView);
		} 
		
		if(isTailViewNeed) {
			// 监听滚动状态
			setOnScrollListener(this);
			// 创建PullListView的HeadView
			mTailView = new View(this.getContext());
			// 默认白色背景,可以改变颜色, 也可以设置背景图片
			mTailView.setBackgroundColor(Color.parseColor("#4F9D9D"));
			// 默认高度为0
			mTailView.setLayoutParams(new AbsListView.LayoutParams(
					LayoutParams.FILL_PARENT, 0));
			this.addFooterView(mTailView);
		}
	}

重写ListView的onTouchEvent事件

/**
	 * 覆盖onTouchEvent方法,实现下拉回弹效果
	 */
	@SuppressWarnings("deprecation")
	@Override
	public boolean onTouchEvent(MotionEvent event) {

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			break;
		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP:
			if (!isRecordPullDown && !isRecordPullUp) {
				// it's not in pull down state or pull up state, break
				Log.d(TAG, "ACTION_UP it's not in pull down state or pull up state, break");
				break;
			}
			if(isPullDownState()) {
				Log.d(TAG, "isRecordPullDown=" + isRecordPullDown);
				// 以一定的频率递减HeadView的高度,实现平滑回弹
				schedulor = Executors.newScheduledThreadPool(1);
				schedulor.scheduleAtFixedRate(new Runnable() {
	
					@Override
					public void run() {
						mHandler.sendEmptyMessage(PULL_DOWN_BACK_ACTION);
	
					}
				}, 0, PULL_BACK_TASK_PERIOD, TimeUnit.NANOSECONDS);
	
				setPullDownState(!isRecordPullDown);
			} else if(isPullUpState()) {
				Log.d(TAG, "isRecordPullUp=" + isRecordPullUp);
				// 以一定的频率递减HeadView的高度,实现平滑回弹
				schedulor = Executors.newScheduledThreadPool(1);
				schedulor.scheduleAtFixedRate(new Runnable() {
	
					@Override
					public void run() {
						mHandler.sendEmptyMessage(PULL_UP_BACK_ACTION);
	
					}
				}, 0, PULL_BACK_TASK_PERIOD, TimeUnit.NANOSECONDS);
	
				setPullUpState(!isRecordPullUp);
			}

			break;

		case MotionEvent.ACTION_MOVE:
			Log.d(TAG, "firstItemIndex=" + firstItemIndex);
			if (!isRecordPullDown && firstItemIndex == 0) {
				Log.d(TAG, "firstItemIndex=" + firstItemIndex + " set isRecordPullDown=true");
				startPullDownY = (int) event.getY();
				setPullType(PULL_DOWN_BACK_ACTION);
			}else if (!isRecordPullUp && lastItemIndex == getCount()) {
				Log.d(TAG, "lastItemIndex == getCount()" + " set isRecordPullUp=true");
				startPullUpY = (int) event.getY();
				setPullType(PULL_UP_BACK_ACTION);
			}

			if (!isRecordPullDown && !isRecordPullUp) {
				// it's not in pull down state or pull up state, break
				Log.d(TAG, "ACTION_MOVE it's not in pull down state or pull up state, break");
				break;
			}

			if(isRecordPullDown) {
				int tempY = (int) event.getY();
				int moveY = tempY - startPullDownY;
				if (moveY < 0) {
					setPullDownState(false);
					break;
				}
	
				Log.d(TAG, "tempY=" + tempY);
				Log.d(TAG, "startPullDownY=" + startPullDownY);
				Log.d(TAG, "moveY=" + moveY);
				mHeadView.setLayoutParams(new AbsListView.LayoutParams(
						LayoutParams.FILL_PARENT, (int) (moveY * PULL_FACTOR)));
				mHeadView.invalidate();
			} else if(isRecordPullUp) {
				int tempY = (int) event.getY();
				int moveY = startPullUpY - tempY;
				if (moveY < 0) {
					setPullUpState(false);
					break;
				}
	
				Log.d(TAG, "tempY=" + tempY);
				Log.d(TAG, "startPullUpY=" + startPullUpY);
				Log.d(TAG, "moveY=" + moveY);
				mTailView.setLayoutParams(new AbsListView.LayoutParams(
						LayoutParams.FILL_PARENT, (int) (moveY * PULL_FACTOR)));
				mTailView.invalidate();
			}

			break;
		}
		return super.onTouchEvent(event);
	}

使用Handler完成HeadView和FootView的回弹效果

/**
	 * 实现回弹效果的handler,用于递减HeadView的高度并请求重绘
	 */
	@SuppressLint("HandlerLeak")
	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			switch(msg.what) {
			case PULL_DOWN_BACK_ACTION:
				AbsListView.LayoutParams headerParams = (LayoutParams) mHeadView
						.getLayoutParams();
				// 递减高度
				headerParams.height -= PULL_BACK_REDUCE_STEP;
				mHeadView.setLayoutParams(headerParams);
				// 重绘
				mHeadView.invalidate();
				// 停止回弹时递减headView高度的任务
				if (headerParams.height <= 0) {
					schedulor.shutdownNow();
				}
				
				break;
			case PULL_UP_BACK_ACTION:
				AbsListView.LayoutParams footerParams = (LayoutParams) mTailView
				.getLayoutParams();
				// 递减高度
				footerParams.height -= PULL_BACK_REDUCE_STEP;
				mTailView.setLayoutParams(footerParams);
				// 重绘
				mTailView.invalidate();
				// 停止回弹时递减headView高度的任务
				if (footerParams.height <= 0) {
					schedulor.shutdownNow();
				}
				
				break;
			}
		}
	};

重写ListView的onScroll方法和onScrollStateChanged方法

@Override
	public void onScroll(AbsListView view, int firstVisiableItem,
			int visibleItemCount, int totalItemCount) {
		this.firstItemIndex = firstVisiableItem;
		this.lastItemIndex = firstVisiableItem + visibleItemCount;
	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		currentScrollState = scrollState;
		Log.d(TAG, "scrollState: " + getScrollStateString(currentScrollState));
	}

	private String getScrollStateString(int flag) {
		String str = "";
		switch(flag) {
		case OnScrollListener.SCROLL_STATE_IDLE:
			str = "SCROLL_STATE_IDLE";
			break;
		case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
			str = "SCROLL_STATE_TOUCH_SCROLL";
			break;
		case OnScrollListener.SCROLL_STATE_FLING:
			str = "SCROLL_STATE_FLING";
			break;
		default:
			str = "wrong state";
		}
		
		return str;
	}

你可能感兴趣的:(Android修炼之道—可回弹的ListView)