@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 initWithContext(Context context) { mLayout = (LinearLayout) View.inflate(context, R.layout.vw_xscrollview_layout, null); mContentLayout = (LinearLayout) mLayout.findViewById(R.id.content_layout); mScroller = new Scroller(context, new DecelerateInterpolator()); // XScrollView need the scroll event, and it will dispatch the event to user's listener (as a // proxy). this.setOnScrollListener(this); // init header view mHeader = new XHeaderView(context); mHeaderContent = (RelativeLayout) mHeader.findViewById(R.id.header_content); mHeaderTime = (TextView) mHeader.findViewById(R.id.header_hint_time); LinearLayout headerLayout = (LinearLayout) mLayout.findViewById(R.id.header_layout); headerLayout.addView(mHeader); // init footer view mFooterView = new XFooterView(context); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); params.gravity = Gravity.CENTER; LinearLayout footLayout = (LinearLayout) mLayout.findViewById(R.id.footer_layout); footLayout.addView(mFooterView, params); // init header height ViewTreeObserver observer = mHeader.getViewTreeObserver(); if (null != observer) { observer.addOnGlobalLayoutListener( new OnGlobalLayoutListener() { @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @SuppressWarnings("deprecation") @Override public void onGlobalLayout() { mHeaderHeight = mHeaderContent.getHeight(); ViewTreeObserver observer = getViewTreeObserver(); if (null != observer) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { observer.removeGlobalOnLayoutListener(this); } else { observer.removeOnGlobalLayoutListener(this); } } } }); } this.addView(mLayout); }
private void updateHeaderHeight(float delta) { mHeader.setVisibleHeight((int) delta + mHeader.getVisibleHeight()); if (mEnablePullRefresh && !mPullRefreshing) { // update the arrow image unrefreshing if (mHeader.getVisibleHeight() > mHeaderHeight) { mHeader.setState(XHeaderView.STATE_READY); } else { mHeader.setState(XHeaderView.STATE_NORMAL); } } // scroll to top each time setSelection(0); }
/** Auto call back refresh. */ public void autoRefresh() { mHeader.setVisibleHeight(mHeaderHeight); if (mEnablePullRefresh && !mPullRefreshing) { // update the arrow image not refreshing if (mHeader.getVisibleHeight() > mHeaderHeight) { mHeader.setState(XHeaderView.STATE_READY); } else { mHeader.setState(XHeaderView.STATE_NORMAL); } } mPullRefreshing = true; mHeader.setState(XHeaderView.STATE_REFRESHING); refresh(); }
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(); } }
private void initWithContext(Context context) { mScroller = new Scroller(context, new DecelerateInterpolator()); super.setOnScrollListener(this); // init header view mHeader = new XHeaderView(context); mHeaderContent = (RelativeLayout) mHeader.findViewById(R.id.header_content); mHeaderTime = (TextView) mHeader.findViewById(R.id.header_hint_time); addHeaderView(mHeader); // init footer view mFooterView = new XFooterView(context); mFooterLayout = new LinearLayout(context); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); params.gravity = Gravity.CENTER; mFooterLayout.addView(mFooterView, params); // init header height ViewTreeObserver observer = mHeader.getViewTreeObserver(); if (null != observer) { observer.addOnGlobalLayoutListener( new OnGlobalLayoutListener() { @SuppressWarnings("deprecation") @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public void onGlobalLayout() { mHeaderHeight = mHeaderContent.getHeight(); ViewTreeObserver observer = getViewTreeObserver(); if (null != observer) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { observer.removeGlobalOnLayoutListener(this); } else { observer.removeOnGlobalLayoutListener(this); } } } }); } }
private void updateHeaderHeight(float delta) { mHeader.setVisibleHeight((int) delta + mHeader.getVisibleHeight()); if (mEnablePullRefresh && !mPullRefreshing) { // update the arrow image unrefreshing if (mHeader.getVisibleHeight() > mHeaderHeight) { mHeader.setState(XHeaderView.STATE_READY); } else { mHeader.setState(XHeaderView.STATE_NORMAL); } } // scroll to top each time post( new Runnable() { @Override public void run() { XScrollView.this.fullScroll(ScrollView.FOCUS_UP); } }); }
@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 resetHeaderHeight() { int height = mHeader.getVisibleHeight(); if (height == 0) return; // refreshing and header isn't shown fully. do nothing. if (mPullRefreshing && height <= mHeaderHeight) return; // default: scroll back to dismiss header. int finalHeight = 0; // is refreshing, just scroll back to show all the header. if (mPullRefreshing && height > mHeaderHeight) { finalHeight = mHeaderHeight; } mScrollBack = SCROLL_BACK_HEADER; mScroller.startScroll(0, height, 0, finalHeight - height, SCROLL_DURATION); // trigger computeScroll invalidate(); }
@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); }
private boolean isTop() { return getScrollY() <= 0 || mHeader.getVisibleHeight() > mHeaderHeight || mContentLayout.getTop() > 0; }