@Override public boolean isScrollableChildUnscrolled() { final AbsListView listView = getCurrentListView(); return listView != null && (listView.getChildCount() == 0 || listView.getChildAt(0).getTop() == listView.getPaddingTop()); }
public void onScrollStateChanged(AbsListView view, int scrollState) { switch (scrollState) { case OnScrollListener.SCROLL_STATE_IDLE: mBusy = false; int first = view.getFirstVisiblePosition(); int count = view.getChildCount(); for (int i = 0; i < count; i++) { TextView t = (TextView) view.getChildAt(i); if (t.getTag() != null) { t.setText(mStrings[first + i]); t.setTag(null); } } mStatus.setText("Idle"); break; case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: mBusy = true; mStatus.setText("Touch scroll"); break; case OnScrollListener.SCROLL_STATE_FLING: mBusy = true; mStatus.setText("Fling"); break; } }
/** * 指针下移,请求下一个图片 * * @return */ private boolean nextRequest() { // 指针下移 mCurrentPosition++; if (mCurrentPosition >= mHostView.getChildCount()) { mCurrentPosition = 0; return false; } return true; }
public boolean shouldHandleAbsListViewLoadingMore(AbsListView absListView) { if (mIsLoadingMore || mCurrentRefreshStatus == RefreshStatus.REFRESHING || mLoadMoreFooterView == null || mDelegate == null || absListView == null || absListView.getAdapter() == null || absListView.getAdapter().getCount() == 0) { return false; } int lastChildBottom = 0; if (absListView.getChildCount() > 0) { // 如果AdapterView的子控件数量不为0,获取最后一个子控件的bottom lastChildBottom = absListView.getChildAt(absListView.getChildCount() - 1).getBottom(); } return absListView.getLastVisiblePosition() == absListView.getAdapter().getCount() - 1 && lastChildBottom <= absListView.getMeasuredHeight(); }
public boolean canChildScrollUp() { if (Build.VERSION.SDK_INT < 14) { if ((this.mTarget instanceof AbsListView)) { AbsListView absListView = (AbsListView) this.mTarget; return (absListView.getChildCount() > 0) && ((absListView.getFirstVisiblePosition() > 0) || (absListView.getChildAt(0).getTop() < absListView.getPaddingTop())); } return (ViewCompat.canScrollVertically(this.mTarget, -1)) || (this.mTarget.getScrollY() > 0); } return ViewCompat.canScrollVertically(this.mTarget, -1); }
/** * @return Whether it is possible for the child view of this layout to scroll up. Override this if * the child view is a custom view. */ public boolean canChildScrollUp() { if (android.os.Build.VERSION.SDK_INT < 14) { if (mTarget instanceof AbsListView) { final AbsListView absListView = (AbsListView) mTarget; return absListView.getChildCount() > 0 && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0).getTop() < absListView.getPaddingTop()); } else { return mTarget.getScrollY() > 0; } } else { return ViewCompat.canScrollVertically(mTarget, -1); } }
public static boolean canChildScrollUp(View view) { if (android.os.Build.VERSION.SDK_INT < 14) { if (view instanceof AbsListView) { final AbsListView absListView = (AbsListView) view; return absListView.getChildCount() > 0 && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0).getTop() < absListView.getPaddingTop()); } else { return view.getScrollY() > 0; } } else { return view.canScrollVertically(-1); } }
@Override public void onScroll( AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (onLoadMoreListener != null && loadMore) for (int i = 0; i < view.getChildCount(); ++i) { View child = view.getChildAt(i); if (loadMore && child instanceof FooterLoadMoreViewGroup) { if (onLoadMoreListener != null) { loadMore = false; onLoadMoreListener.onLoadMore(); } } } }
/** * Copy From AbsListView (API Level >= 19) * * @param absListView AbsListView * @param direction Negative to check scrolling up, positive to check scrolling down. * @return true if the list can be scrolled in the specified direction, false otherwise */ private boolean absListViewCanScrollList(AbsListView absListView, int direction) { final int childCount = absListView.getChildCount(); if (childCount == 0) { return false; } final int firstPosition = absListView.getFirstVisiblePosition(); if (direction > 0) { // can scroll down final int lastBottom = absListView.getChildAt(childCount - 1).getBottom(); final int lastPosition = firstPosition + childCount; return lastPosition < absListView.getCount() || lastBottom > absListView.getHeight() - absListView.getPaddingTop(); } else { // can scroll up final int firstTop = absListView.getChildAt(0).getTop(); return firstPosition > 0 || firstTop < absListView.getPaddingTop(); } }
public boolean canChildScrollDown() { if (android.os.Build.VERSION.SDK_INT < 14) { if (mTarget instanceof AbsListView) { final AbsListView absListView = (AbsListView) mTarget; View lastChild = absListView.getChildAt(absListView.getChildCount() - 1); if (lastChild != null) { return (absListView.getLastVisiblePosition() == (absListView.getCount() - 1)) && lastChild.getBottom() > absListView.getPaddingBottom(); } else { return false; } } else { return mTarget.getHeight() - mTarget.getScrollY() > 0; } } else { return ViewCompat.canScrollVertically(mTarget, 1); } }
public static boolean canViewScrollUp(View view) { if (view == null) { return false; } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { if (view instanceof AbsListView) { final AbsListView absListView = (AbsListView) view; if (absListView.getChildCount() == 0) { return false; } return absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0).getTop() < absListView.getPaddingTop(); } else { return view.getScrollY() > 0; } } else { return ViewCompat.canScrollVertically(view, -1); } }
/* * (non-Javadoc) * @see android.widget.AbsListView.OnScrollListener#onScroll(android.widget.AbsListView, int, int, int) */ @Override public void onScroll( AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (visibleItemCount == 0) { return; } // Fade MonthView Title/DayLabels as they're farther from the top of the View. for (int i = 0; i < view.getChildCount(); i++) { MonthView child = (MonthView) view.getChildAt(i); int top = child.getTop(); int height = child.getHeight(); int thresh = height / 2; // Fade out MonthViews that aren't in the most screen-dominate month. float percent; // Has fully faded out above the screen. if (top <= -thresh) { percent = MIN_MONTH_OPACITY; // Is fading out above the screen. } else if (top < 0 && top > -thresh) { percent = 1f - Math.abs(((float) top) / ((float) (-thresh))); if (percent < MIN_MONTH_OPACITY) { percent = MIN_MONTH_OPACITY; } // Has fully appeared on screen. } else if (top < thresh) { percent = 1f; // Is appearing on the screen. } else { percent = 1f - Math.abs(((float) top - thresh) / ((float) (height - thresh))); if (percent < MIN_MONTH_OPACITY) { percent = MIN_MONTH_OPACITY; } } child.setAlpha(percent); } }
@Override public boolean onTouch(final View view, final MotionEvent motionEvent) { if (mViewWidth < 2) { mViewWidth = mListView.getWidth(); } switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: { if (mPaused) { return false; } // Find the child view that was touched (perform a hit test) final Rect rect = new Rect(); final int childCount = mListView.getChildCount(); final int[] listViewCoords = new int[2]; mListView.getLocationOnScreen(listViewCoords); final int x = (int) motionEvent.getRawX() - listViewCoords[0]; final int y = (int) motionEvent.getRawY() - listViewCoords[1]; View child; for (int i = 0; i < childCount; i++) { child = mListView.getChildAt(i); child.getHitRect(rect); if (rect.contains(x, y)) { mDownView = child; break; } } if (mDownView != null) { mDownX = motionEvent.getRawX(); mDownPosition = mListView.getPositionForView(mDownView); mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(motionEvent); } view.onTouchEvent(motionEvent); return true; } case MotionEvent.ACTION_UP: { if (mVelocityTracker == null) { break; } final float deltaX = motionEvent.getRawX() - mDownX; mVelocityTracker.addMovement(motionEvent); mVelocityTracker.computeCurrentVelocity(1000); final float velocityX = Math.abs(mVelocityTracker.getXVelocity()); final float velocityY = Math.abs(mVelocityTracker.getYVelocity()); boolean dismiss = false; boolean dismissRight = false; if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) { dismiss = true; dismissRight = deltaX > 0; } else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity && velocityY < velocityX && mSwiping && isDirectionValid(mVelocityTracker.getXVelocity()) && deltaX >= mViewWidth * 0.2f) { dismiss = true; dismissRight = mVelocityTracker.getXVelocity() > 0; } if (dismiss) { // dismiss final View downView = mDownView; // mDownView gets null'd before animation ends final int downPosition = mDownPosition; ++mDismissAnimationRefCount; animate(mDownView) .translationX(dismissRight ? mViewWidth : -mViewWidth) .alpha(0) .setDuration(mAnimationTime) .setListener( new AnimatorListenerAdapter() { @Override public void onAnimationEnd(final Animator animation) { performDismiss(downView, downPosition); } }); } else { // cancel animate(mDownView) .translationX(0) .alpha(1) .setDuration(mAnimationTime) .setListener(null); } mVelocityTracker = null; mDownX = 0; mDownView = null; mDownPosition = AdapterView.INVALID_POSITION; mSwiping = false; break; } case MotionEvent.ACTION_MOVE: { if (mUndoPopup.isShowing()) { // Send a delayed message to hide popup mHandler.sendMessageDelayed(mHandler.obtainMessage(mDelayedMsgId), mAutoHideDelay); } if (mVelocityTracker == null || mPaused) { break; } mVelocityTracker.addMovement(motionEvent); float deltaX = motionEvent.getRawX() - mDownX; // Only start swipe in correct direction if (isDirectionValid(deltaX)) { if (Math.abs(deltaX) > mSlop) { mSwiping = true; mListView.requestDisallowInterceptTouchEvent(true); // Cancel ListView's touch (un-highlighting the item) final MotionEvent cancelEvent = MotionEvent.obtain(motionEvent); cancelEvent.setAction( MotionEvent.ACTION_CANCEL | (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); mListView.onTouchEvent(cancelEvent); } } else { // If we swiped into wrong direction, act like this was the new // touch down point mDownX = motionEvent.getRawX(); deltaX = 0; } if (mSwiping) { setTranslationX(mDownView, deltaX); setAlpha( mDownView, Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX) / mViewWidth))); return true; } break; } } return false; }
/** * 子控件为ListView等时,ACTION_MOVE执行几次后this.disallowIntercept=true; * 造成的影响:用户体验不好!(如果从中间滑到顶部或底部是不会进入onInterceptTouchEvent方法的,拦截不到事件,不能执行刷新加载相关功能) * 解决办法:重写requestDisallowInterceptTouchEvent,过滤disallowIntercept=true。 * 缺点:这样会导致子控件调用parent.requestDisallowInterceptTouchEvent(true)失效。 * * <p>ViewGroup类dispatchTouchEvent方法关键代码: final boolean disallowIntercept = (mGroupFlags & * FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { intercepted = * onInterceptTouchEvent(ev); } * * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { printLog("parent onInterceptTouchEvent:" + ev.getAction()); int action = ev.getAction(); if (pullView.doMainType == pullView.NONE && action == MotionEvent.ACTION_DOWN) { reset(); } if (pullView.doMainType == pullView.REFRESHING || pullView.doMainType == pullView.LOADING) { printLog("parent onInterceptTouchEvent result:" + !refreshingOrLoadingOverScrollEnabled); return !refreshingOrLoadingOverScrollEnabled; } printLog("parent onInterceptTouchEvent result:" + isGetFinalDirection); if (isGetFinalDirection) { // getParent().requestDisallowInterceptTouchEvent(true); return true; } // 得到可能的方向 if (this.direction.type == Direction.NONE && this.directionEnable.type != Direction.NONE) { this.startY = ev.getY(); printLog("startY:" + startY); for (View view : conditionChildViews) { printLog(view.getClass().getSimpleName()); if (view instanceof AbsListView) { AbsListView absListView = (AbsListView) view; Direction direction = new Direction(); View firstView = absListView.getChildAt(0); View lastView = absListView.getChildAt(absListView.getChildCount() - 1); if (firstView == null || (absListView.getFirstVisiblePosition() == 0 && firstView.getTop() >= view.getTop())) { printLog("顶部"); direction.addDirection(Direction.DOWN_PULL); } if (lastView == null || (absListView.getLastVisiblePosition() == (absListView.getCount() - 1) && lastView.getBottom() <= view.getBottom())) { printLog("底部"); direction.addDirection(Direction.UP_PULL); } if (direction.type == Direction.NONE) { this.direction.type = Direction.NONE; printLog("NONE"); break; } this.direction.configDirection(direction.type); } else if (view instanceof ScrollView) { ScrollView scrollView = (ScrollView) view; Direction direction = new Direction(); int scrollY = view.getScrollY(); int height = view.getHeight(); int scrollViewMeasuredHeight = scrollView.getChildAt(0).getMeasuredHeight(); if (scrollY == 0) { printLog("顶部"); direction.addDirection(Direction.DOWN_PULL); } if ((scrollY + height) == scrollViewMeasuredHeight) { printLog("底部"); direction.addDirection(Direction.UP_PULL); } if (direction.type == Direction.NONE) { this.direction.type = Direction.NONE; printLog("NONE"); break; } this.direction.configDirection(direction.type); } else { if (view.getScrollY() == 0) { printLog("顶部"); direction.addDirection(Direction.DOWN_PULL); } if (true) { // TODO 哈哈(待修改) printLog("底部"); direction.addDirection(Direction.UP_PULL); } if (direction.type == Direction.NONE) { this.direction.type = Direction.NONE; printLog("NONE"); break; } this.direction.configDirection(direction.type); } } this.direction.takeIntersection(this.directionEnable); } // 得到最终方向 else if (this.direction.type != Direction.NONE) { findFinalDirection(ev); } return false; }
@Override public void onScrollStateChanged(final AbsListView view, int scrollState) { super.onScrollStateChanged(view, scrollState); if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) { int currentFirstVisiblePosition = view.getFirstVisiblePosition(); if (currentFirstVisiblePosition == 0) { // 滚动到顶部 View v = (View) view.getChildAt(0); int[] location = new int[2]; // 获取在整个屏幕内的绝对坐标 v.getLocationOnScreen(location); int y = location[1]; if (currentFirstVisiblePosition != firstVisiblePosition && firstLocationY != y) { // 第一次拖至顶部 firstVisiblePosition = currentFirstVisiblePosition; firstLocationY = y; return; } else if (currentFirstVisiblePosition == firstVisiblePosition && firstLocationY == y) { User firstUser = personList.get(0); // 第二次拖至顶部 logic.queryUser( queryType, queryValue, ORDER_BY_NEWEST, firstUser.getLastLoginTime(), 8, createUIEventListener( new EventListener() { @Override public void onEvent(EventId id, EventArgs args) { stopLoading(); UserEventArgs result = (UserEventArgs) args; OperErrorCode errCode = result.getErrCode(); if (errCode == OperErrorCode.Success) { List<User> userList = result.getUserList(); if (userList != null && userList.size() > 0) { personList.addAll(0, userList); imageAdapter.notifyDataSetChanged(); personsGridView.smoothScrollToPosition(0); } } } })); startLoading(); } } else { int currentLastVisiblePosition = view.getLastVisiblePosition(); if (currentLastVisiblePosition == (view.getCount() - 1)) { // 滚动到底部 View v = (View) view.getChildAt(view.getChildCount() - 1); int[] location = new int[2]; // 获取在整个屏幕内的绝对坐标 v.getLocationOnScreen(location); int y = location[1]; if (currentLastVisiblePosition != lastVisiblePosition && lastLocationY != y) { // 第一次拖至底部 lastVisiblePosition = currentLastVisiblePosition; lastLocationY = y; return; } else if (currentLastVisiblePosition == lastVisiblePosition && lastLocationY == y) { // 第二次拖至底部 User lastUser = personList.get(personList.size() - 1); // 第二次拖至顶部 logic.queryUser( queryType, queryValue, ORDER_BY_EARLIEST, lastUser.getLastLoginTime(), 8, createUIEventListener( new EventListener() { @Override public void onEvent(EventId id, EventArgs args) { stopLoading(); UserEventArgs result = (UserEventArgs) args; OperErrorCode errCode = result.getErrCode(); if (errCode == OperErrorCode.Success) { List<User> userList = result.getUserList(); if (userList != null && userList.size() > 0) { personList.addAll(userList); imageAdapter.notifyDataSetChanged(); personsGridView.smoothScrollToPosition(view.getCount()); } } } })); startLoading(); } } } // 未滚动到顶部 firstVisiblePosition = -1; firstLocationY = 0; // 未滚动到底部 lastVisiblePosition = 0; lastLocationY = 0; } }