@Override public boolean onTouchEvent(MotionEvent ev) { if (mLastY == -1) { mLastY = ev.getRawY(); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); if (getFirstVisiblePosition() == 0 && (mHeader.getVisibleHeight() > 0 || deltaY > 0)) { // the first item is showing, header has shown or pull down. updateHeaderHeight(deltaY / OFFSET_RADIO); invokeOnScrolling(); } else if (getLastVisiblePosition() == mTotalItemCount - 1 && (mFooterView.getBottomMargin() > 0 || deltaY < 0)) { // last item, already pulled up or want to pull up. updateFooterHeight(-deltaY / OFFSET_RADIO); } break; default: // reset mLastY = -1; if (getFirstVisiblePosition() == 0) { // invoke refresh if (mEnablePullRefresh && mHeader.getVisibleHeight() > mHeaderHeight) { mPullRefreshing = true; mHeader.setState(XHeaderView.STATE_REFRESHING); refresh(); } resetHeaderHeight(); } else if (getLastVisiblePosition() == mTotalItemCount - 1) { // invoke load more. if (mEnablePullLoad && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA) { startLoadMore(); } resetFooterHeight(); } break; } return super.onTouchEvent(ev); }
private void startLoadMore() { if (!mPullLoading) { mPullLoading = true; mFooterView.setState(XFooterView.STATE_LOADING); loadMore(); } }
private void updateFooterHeight(float delta) { int height = mFooterView.getBottomMargin() + (int) delta; if (mEnablePullLoad && !mPullLoading) { if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load more. mFooterView.setState(XFooterView.STATE_READY); } else { mFooterView.setState(XFooterView.STATE_NORMAL); } } mFooterView.setBottomMargin(height); // scroll to bottom // setSelection(mTotalItemCount - 1); }
private void resetFooterHeight() { int bottomMargin = mFooterView.getBottomMargin(); if (bottomMargin > 0) { mScrollBack = SCROLL_BACK_FOOTER; mScroller.startScroll(0, bottomMargin, 0, -bottomMargin, SCROLL_DURATION); invalidate(); } }
@Override public void computeScroll() { if (mScroller.computeScrollOffset()) { if (mScrollBack == SCROLL_BACK_HEADER) { mHeader.setVisibleHeight(mScroller.getCurrY()); } else { mFooterView.setBottomMargin(mScroller.getCurrY()); } postInvalidate(); invokeOnScrolling(); } super.computeScroll(); }
private void updateFooterHeight(float delta) { int height = mFooterView.getBottomMargin() + (int) delta; if (mEnablePullLoad && !mPullLoading) { if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load more. mFooterView.setState(XFooterView.STATE_READY); } else { mFooterView.setState(XFooterView.STATE_NORMAL); } } mFooterView.setBottomMargin(height); // scroll to bottom post( new Runnable() { @Override public void run() { XScrollView.this.fullScroll(ScrollView.FOCUS_DOWN); } }); }
private void resetHeaderOrBottom() { if (isTop()) { // invoke refresh if (mEnablePullRefresh && mHeader.getVisibleHeight() > mHeaderHeight) { mPullRefreshing = true; mHeader.setState(XHeaderView.STATE_REFRESHING); refresh(); } resetHeaderHeight(); } else if (isBottom()) { // invoke load more. if (mEnablePullLoad && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA) { startLoadMore(); } resetFooterHeight(); } }
/** * Enable or disable pull up load more feature. * * @param enable */ public void setPullLoadEnable(boolean enable) { mEnablePullLoad = enable; if (!mEnablePullLoad) { mFooterView.setBottomMargin(0); mFooterView.hide(); mFooterView.setPadding(0, 0, 0, mFooterView.getHeight() * (-1)); mFooterView.setOnClickListener(null); } else { mPullLoading = false; mFooterView.setPadding(0, 0, 0, 0); mFooterView.show(); mFooterView.setState(XFooterView.STATE_NORMAL); // both "pull up" and "click" will invoke load more. mFooterView.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { startLoadMore(); } }); } }
@Override public boolean onTouchEvent(MotionEvent ev) { if (mLastY == -1) { mLastY = ev.getRawY(); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); if (isTop() && (mHeader.getVisibleHeight() > 0 || deltaY > 0)) { // the first item is showing, header has shown or pull down. updateHeaderHeight(deltaY / OFFSET_RADIO); invokeOnScrolling(); } else if (isBottom() && (mFooterView.getBottomMargin() > 0 || deltaY < 0)) { // last item, already pulled up or want to pull up. updateFooterHeight(-deltaY / OFFSET_RADIO); } break; default: // reset mLastY = -1; resetHeaderOrBottom(); break; } return super.onTouchEvent(ev); }
/** Stop load more, reset footer view. */ public void stopLoadMore() { if (mPullLoading) { mPullLoading = false; mFooterView.setState(XFooterView.STATE_NORMAL); } }
private boolean isBottom() { return Math.abs(getScrollY() + getHeight() - computeVerticalScrollRange()) <= 5 || (getScrollY() > 0 && null != mFooterView && mFooterView.getBottomMargin() > 0); }