/** * Create a {@code LoadingLayout} instance matched by <b>{@code clazz} token</b> * * @param layoutCode Loading layout code, which must be defined in pulltorefresh.xml * @param context * @param mode * @return {@code LoadingLayout} instance if the class matched by {@code layoutCode} exists, or * {@code RotateLoadingLayout} instance if not */ public static LoadingLayout createLoadingLayout( Class<? extends LoadingLayout> clazz, Context context, Mode mode, Orientation orientation, TypedArray attrs) { LoadingLayout layout = null; // Prevent NullPointerException if (clazz == null) { Log.i( LOG_TAG, "The Class token of the Loading Layout is missing. Default Loading Layout will be used."); clazz = DefaultLoadingLayoutFactory.createLoadingLayoutClazz(""); } layout = tryNewInstance(clazz, context, mode, orientation, attrs); // If trying to create new instance has failed, if (layout == null) { layout = DefaultLoadingLayoutFactory.createLoadingLayout(clazz, context, mode, orientation, attrs); } layout.setVisibility(View.INVISIBLE); return layout; }
@Override protected void handleStyledAttributes(TypedArray a) { super.handleStyledAttributes(a); mListViewExtrasEnabled = a.getBoolean(R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true); if (mListViewExtrasEnabled) { final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL); // Create Loading Views ready for use later FrameLayout frame = new FrameLayout(getContext()); mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a); mHeaderLoadingView.setVisibility(View.GONE); frame.addView(mHeaderLoadingView, lp); mRefreshableView.addHeaderView(frame, null, false); mLvFooterLoadingFrame = new FrameLayout(getContext()); mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, a); mFooterLoadingView.setVisibility(View.GONE); mLvFooterLoadingFrame.addView(mFooterLoadingView, lp); /** * If the value for Scrolling While Refreshing hasn't been explicitly set via XML, enable * Scrolling While Refreshing. */ if (!a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) { setScrollingWhileRefreshingEnabled(true); } } }
protected LoadingLayout createLoadingLayout(Context context, Mode mode, TypedArray attrs) { LoadingLayout layout = mLoadingAnimationStyle.createLoadingLayout( context, mode, getPullToRefreshScrollDirection(), attrs); layout.setVisibility(View.INVISIBLE); return layout; }
/** * Updates the View State when the mode has been set. This does not do any checking that the mode * is different to current state so always updates. */ protected void updateUIForMode() { // We need to use the correct LayoutParam values, based on scroll // direction final LayoutParams lp = getLoadingLayoutLayoutParams(); // Remove Header, and then add Header Loading View again if needed if (this == mHeaderLayout.getParent()) { removeView(mHeaderLayout); } if (mMode.showHeaderLoadingLayout()) { addViewInternal(mHeaderLayout, 0, lp); } // Remove Footer, and then add Footer Loading View again if needed if (this == mFooterLayout.getParent()) { removeView(mFooterLayout); } if (mMode.showFooterLoadingLayout()) { addViewInternal(mFooterLayout, lp); } // Hide Loading Views refreshLoadingViewsSize(); // If we're not using Mode.BOTH, set mCurrentMode to mMode, otherwise // set it to pull down mCurrentMode = (mMode != Mode.BOTH) ? mMode : Mode.PULL_FROM_START; }
/** * Updates the View State when the mode has been set. This does not do any checking that the mode * is different to current state so always updates. */ protected void updateUIForMode() { // Remove Header, and then add Header Loading View again if needed if (this == mHeaderLayout.getParent()) { removeView(mHeaderLayout); } if (mMode.canPullDown()) { LinearLayout.LayoutParams llp = new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); llp.setMargins(mMargin, 0, mMargin, 0); addViewInternal(mHeaderLayout, 0, llp); } // Remove Footer, and then add Footer Loading View again if needed if (this == mFooterLayout.getParent()) { removeView(mFooterLayout); } if (mMode.canPullUp()) { LinearLayout.LayoutParams llp = new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); llp.setMargins(mMargin, 0, mMargin, 0); addViewInternal(mFooterLayout, 0, llp); } // Hide Loading Views refreshLoadingViewsHeight(); // If we're not using Mode.BOTH, set mCurrentMode to mMode, otherwise // set it to pull down mCurrentMode = (mMode != Mode.BOTH) ? mMode : Mode.PULL_DOWN_TO_REFRESH; }
/** Re-measure the Loading Views height, and adjust internal padding as necessary */ private void refreshLoadingViewsHeight() { if (mMode.canPullDown()) { measureView(mHeaderLayout); mHeaderHeight = mHeaderLayout.getMeasuredHeight(); } else if (mMode.canPullUp()) { measureView(mFooterLayout); mHeaderHeight = mFooterLayout.getMeasuredHeight(); } else { mHeaderHeight = 0; } // Hide Loading Views switch (mMode) { case DISABLED: setPadding(0, 0, 0, 0); case BOTH: setPadding(0, -mHeaderHeight, 0, -mHeaderHeight); break; case PULL_UP_TO_REFRESH: setPadding(0, 0, 0, -mHeaderHeight); break; case PULL_DOWN_TO_REFRESH: default: setPadding(0, -mHeaderHeight, 0, 0); break; } }
/** * Set Text to show when the Widget is being pulled, and will refresh when released * * @param releaseLabel - String to display * @param mode - Controls which Header/Footer Views will be updated. <code>Mode.BOTH</code> will * update all available, other values will update the relevant View. */ public void setReleaseLabel(String releaseLabel, Mode mode) { if (null != mHeaderLayout && mode.canPullDown()) { mHeaderLayout.setReleaseLabel(releaseLabel); } if (null != mFooterLayout && mode.canPullUp()) { mFooterLayout.setReleaseLabel(releaseLabel); } }
@Override public void setRefreshingLabel(String refreshingLabel, Mode mode) { if (null != mHeaderLayout && mode.canPullDown()) { mHeaderLayout.setRefreshingLabel(refreshingLabel); } if (null != mFooterLayout && mode.canPullUp()) { mFooterLayout.setRefreshingLabel(refreshingLabel); } }
public void setPullLabel(String pullLabel) { super.setPullLabel(pullLabel); if (null != mHeaderLoadingView) { mHeaderLoadingView.setPullLabel(pullLabel); } if (null != mFooterLoadingView) { mFooterLoadingView.setPullLabel(pullLabel); } }
public void setRefreshingLabel(String refreshingLabel) { super.setRefreshingLabel(refreshingLabel); if (null != mHeaderLoadingView) { mHeaderLoadingView.setRefreshingLabel(refreshingLabel); } if (null != mFooterLoadingView) { mFooterLoadingView.setRefreshingLabel(refreshingLabel); } }
/** Called when the UI needs to be updated to the 'Release to Refresh' state */ protected void onReleaseToRefresh() { switch (mCurrentMode) { case PULL_UP_TO_REFRESH: mFooterLayout.releaseToRefresh(); break; case PULL_DOWN_TO_REFRESH: mHeaderLayout.releaseToRefresh(); break; } }
/** * Called when the UI has been to be updated to be in the {@link * com.handmark.pulltorefresh.library.PullToRefreshBase.State#RESET} state. */ protected void onReset() { mIsBeingDragged = false; mLayoutVisibilityChangesEnabled = true; // Always reset both layouts, just in case... mHeaderLayout.reset(); mFooterLayout.reset(); smoothScrollTo(0); }
/** * Set the drawable used in the loading layout. * * @param drawable - Drawable to display * @param mode - Controls which Header/Footer Views will be updated. <code>Mode.BOTH</code> will * update all available, other values will update the relevant View. */ public void setLoadingDrawable(Drawable drawable, Mode mode) { if (null != mHeaderLayout && mode.canPullDown()) { mHeaderLayout.setLoadingDrawable(drawable); } if (null != mFooterLayout && mode.canPullUp()) { mFooterLayout.setLoadingDrawable(drawable); } // The Loading Height may have changed, so refresh refreshLoadingViewsHeight(); }
@Override protected void onReset() { /** If the extras are not enabled, just call up to super and return. */ if (!mListViewExtrasEnabled) { super.onReset(); return; } final LoadingLayout originalLoadingLayout, listViewLoadingLayout; final int scrollToHeight, selection; final boolean scrollLvToEdge; switch (getCurrentMode()) { case MANUAL_REFRESH_ONLY: case PULL_FROM_END: originalLoadingLayout = getFooterLayout(); listViewLoadingLayout = mFooterLoadingView; selection = mRefreshableView.getCount() - 1; scrollToHeight = getFooterSize(); scrollLvToEdge = Math.abs(mRefreshableView.getLastVisiblePosition() - selection) <= 1; break; case PULL_FROM_START: default: originalLoadingLayout = getHeaderLayout(); listViewLoadingLayout = mHeaderLoadingView; scrollToHeight = -getHeaderSize(); selection = 0; scrollLvToEdge = Math.abs(mRefreshableView.getFirstVisiblePosition() - selection) <= 1; break; } // If the ListView header loading layout is showing, then we need to // flip so that the original one is showing instead if (listViewLoadingLayout.getVisibility() == View.VISIBLE) { // Set our Original View to Visible originalLoadingLayout.showInvisibleViews(); // Hide the ListView Header/Footer listViewLoadingLayout.setVisibility(View.GONE); /** * Scroll so the View is at the same Y as the ListView header/footer, but only scroll if: * we've pulled to refresh, it's positioned correctly */ if (scrollLvToEdge && getState() != State.MANUAL_REFRESHING) { mRefreshableView.setSelection(selection); setHeaderScroll(scrollToHeight); } } // Finally, call up to super super.onReset(); }
@Override protected void setRefreshingInternal(boolean doScroll) { // If we're empty, then the header/footer views won't show so we use the // normal method ListAdapter adapter = mRefreshableView.getAdapter(); if (null == adapter || adapter.isEmpty()) { super.setRefreshingInternal(doScroll); return; } super.setRefreshingInternal(false); final LoadingLayout originalLoadingLayout, listViewLoadingLayout; final int selection, scrollToY; switch (getCurrentMode()) { case MODE_PULL_UP_TO_REFRESH: originalLoadingLayout = getFooterLayout(); listViewLoadingLayout = mFooterLoadingView; selection = mRefreshableView.getCount() - 1; scrollToY = getScrollY() - getHeaderHeight(); break; case MODE_PULL_DOWN_TO_REFRESH: default: originalLoadingLayout = getHeaderLayout(); listViewLoadingLayout = mHeaderLoadingView; selection = 0; scrollToY = getScrollY() + getHeaderHeight(); break; } if (doScroll) { // We scroll slightly so that the ListView's header/footer is at the // same Y position as our normal header/footer setHeaderScroll(scrollToY); } // Hide our original Loading View originalLoadingLayout.setVisibility(View.INVISIBLE); // Show the ListView Loading View and set it to refresh listViewLoadingLayout.setVisibility(View.VISIBLE); listViewLoadingLayout.refreshing(); if (doScroll) { // Make sure the ListView is scrolled to show the loading // header/footer mRefreshableView.setSelection(selection); // Smooth scroll as normal smoothScrollTo(0); } }
/** * Set the Last Updated Text. This displayed under the main label when Pulling * * @param label - Label to set */ public void setLastUpdatedLabel(CharSequence label) { if (null != mHeaderLayout) { mHeaderLayout.setSubHeaderText(label); } if (null != mFooterLayout) { mFooterLayout.setSubHeaderText(label); } // Refresh Height as it may have changed refreshLoadingViewsHeight(); }
protected void resetHeader() { mState = PULL_TO_REFRESH; mIsBeingDragged = false; if (mMode.canPullDown()) { mHeaderLayout.reset(); } if (mMode.canPullUp()) { mFooterLayout.reset(); } smoothScrollTo(0); }
/** * Called when the UI has been to be updated to be in the {@link * com.handmark.pulltorefresh.library.PullToRefreshBase.State#RELEASE_TO_REFRESH} state. */ protected void onReleaseToRefresh() { switch (mCurrentMode) { case PULL_FROM_END: mFooterLayout.releaseToRefresh(); break; case PULL_FROM_START: mHeaderLayout.releaseToRefresh(); break; default: // NO-OP break; } }
/** * Actions a Pull Event * * @return true if the Event has been handled, false if there has been no change */ private void pullEvent() { final int newScrollValue; final int itemDimension; final float initialMotionValue, lastMotionValue; switch (getPullToRefreshScrollDirection()) { case HORIZONTAL: initialMotionValue = mInitialMotionX; lastMotionValue = mLastMotionX; break; case VERTICAL: default: initialMotionValue = mInitialMotionY; lastMotionValue = mLastMotionY; break; } switch (mCurrentMode) { case PULL_FROM_END: newScrollValue = Math.round(Math.max(initialMotionValue - lastMotionValue, 0) / FRICTION); itemDimension = getFooterSize(); break; case PULL_FROM_START: default: newScrollValue = Math.round(Math.min(initialMotionValue - lastMotionValue, 0) / FRICTION); itemDimension = getHeaderSize(); break; } setHeaderScroll(newScrollValue); if (newScrollValue != 0 && !isRefreshing()) { float scale = Math.abs(newScrollValue) / (float) itemDimension; switch (mCurrentMode) { case PULL_FROM_END: mFooterLayout.onPull(scale); break; case PULL_FROM_START: default: mHeaderLayout.onPull(scale); break; } if (mState != State.PULL_TO_REFRESH && itemDimension >= Math.abs(newScrollValue)) { setState(State.PULL_TO_REFRESH); } else if (mState == State.PULL_TO_REFRESH && itemDimension < Math.abs(newScrollValue)) { setState(State.RELEASE_TO_REFRESH); } } }
/** Re-measure the Loading Views height, and adjust internal padding as necessary */ protected final void refreshLoadingViewsSize() { final int maximumPullScroll = (int) (getMaximumPullScroll() * 1.2f); int pLeft = getPaddingLeft(); int pTop = getPaddingTop(); int pRight = getPaddingRight(); int pBottom = getPaddingBottom(); switch (getPullToRefreshScrollDirection()) { case HORIZONTAL: if (mMode.showHeaderLoadingLayout()) { mHeaderLayout.setWidth(maximumPullScroll); pLeft = -maximumPullScroll; } else { pLeft = 0; } if (mMode.showFooterLoadingLayout()) { mFooterLayout.setWidth(maximumPullScroll); pRight = -maximumPullScroll; } else { pRight = 0; } break; case VERTICAL: if (mMode.showHeaderLoadingLayout()) { mHeaderLayout.setHeight(maximumPullScroll); pTop = -maximumPullScroll; } else { pTop = 0; } if (mMode.showFooterLoadingLayout()) { mFooterLayout.setHeight(maximumPullScroll); pBottom = -maximumPullScroll; } else { pBottom = 0; } break; } if (DEBUG) { Log.d( LOG_TAG, String.format( "Setting Padding. L: %d, T: %d, R: %d, B: %d", pLeft, pTop, pRight, pBottom)); } setPadding(pLeft, pTop, pRight, pBottom); }
@Override protected void resetHeader() { // If we're empty, then the header/footer views won't show so we use the // normal method ListAdapter adapter = mRefreshableView.getAdapter(); if (null == adapter || adapter.isEmpty()) { super.resetHeader(); return; } LoadingLayout originalLoadingLayout; LoadingLayout listViewLoadingLayout; int scrollToHeight = getHeaderHeight(); final boolean doScroll; switch (getCurrentMode()) { case MODE_PULL_UP_TO_REFRESH: originalLoadingLayout = getFooterLayout(); listViewLoadingLayout = mFooterLoadingView; doScroll = isReadyForPullUp(); break; case MODE_PULL_DOWN_TO_REFRESH: default: originalLoadingLayout = getHeaderLayout(); listViewLoadingLayout = mHeaderLoadingView; scrollToHeight *= -1; doScroll = isReadyForPullDown(); break; } // Set our Original View to Visible originalLoadingLayout.setVisibility(View.VISIBLE); // Scroll so our View is at the same Y as the ListView header/footer, // but only scroll if the ListView is at the top/bottom if (doScroll) { setHeaderScroll(scrollToHeight); } // Hide the ListView Header/Footer listViewLoadingLayout.setVisibility(View.GONE); super.resetHeader(); }
protected void setRefreshingInternal(boolean doScroll) { mState = REFRESHING; if (mMode.canPullDown()) { mHeaderLayout.refreshing(); } if (mMode.canPullUp()) { mFooterLayout.refreshing(); } if (doScroll) { if (mShowViewWhileRefreshing) { smoothScrollTo(mCurrentMode == Mode.PULL_DOWN_TO_REFRESH ? -mHeaderHeight : mHeaderHeight); } else { smoothScrollTo(0); } } }
/** * Actions a Pull Event * * @return true if the Event has been handled, false if there has been no change */ private boolean pullEvent() { final int newHeight; final int oldHeight = getScrollY(); switch (mCurrentMode) { case PULL_UP_TO_REFRESH: newHeight = Math.round(Math.max(mInitialMotionY - mLastMotionY, 0) / FRICTION); break; case PULL_DOWN_TO_REFRESH: default: newHeight = Math.round(Math.min(mInitialMotionY - mLastMotionY, 0) / FRICTION); break; } setHeaderScroll(newHeight); if (newHeight != 0) { float scale = Math.abs(newHeight) / (float) mHeaderHeight; switch (mCurrentMode) { case PULL_UP_TO_REFRESH: mFooterLayout.onPullY(scale); break; case PULL_DOWN_TO_REFRESH: mHeaderLayout.onPullY(scale); break; } if (mState == PULL_TO_REFRESH && mHeaderHeight < Math.abs(newHeight)) { mState = RELEASE_TO_REFRESH; onReleaseToRefresh(); return true; } else if (mState == RELEASE_TO_REFRESH && mHeaderHeight >= Math.abs(newHeight)) { mState = PULL_TO_REFRESH; onPullToRefresh(); return true; } } return oldHeight != newHeight; }
/** * Helper method which just calls scrollTo() in the correct scrolling direction. * * @param value - New Scroll value */ protected final void setHeaderScroll(int value) { if (DEBUG) { Log.d(LOG_TAG, "setHeaderScroll: " + value); } // Clamp value to with pull scroll range final int maximumPullScroll = getMaximumPullScroll(); value = Math.min(maximumPullScroll, Math.max(-maximumPullScroll, value)); if (mLayoutVisibilityChangesEnabled) { if (value < 0) { mHeaderLayout.setVisibility(View.VISIBLE); } else if (value > 0) { mFooterLayout.setVisibility(View.VISIBLE); } else { mHeaderLayout.setVisibility(View.INVISIBLE); mFooterLayout.setVisibility(View.INVISIBLE); } } if (USE_HW_LAYERS) { /** * Use a Hardware Layer on the Refreshable View if we've scrolled at all. We don't use them on * the Header/Footer Views as they change often, which would negate any HW layer performance * boost. */ ViewCompat.setLayerType( mRefreshableViewWrapper, value != 0 ? 2 /* * View. * LAYER_TYPE_HARDWARE */ : 0 /* View.LAYER_TYPE_NONE */); } switch (getPullToRefreshScrollDirection()) { case VERTICAL: scrollTo(0, value); break; case HORIZONTAL: scrollTo(value, 0); break; } }
@Override protected final ListView createRefreshableView(Context context, AttributeSet attrs) { ListView lv = new InternalListView(context, attrs); final int mode = getMode(); // Loading View Strings String pullLabel = context.getString(R.string.pull_to_refresh_pull_label); String refreshingLabel = context.getString(R.string.pull_to_refresh_refreshing_label); String releaseLabel = context.getString(R.string.pull_to_refresh_release_label); // Add Loading Views if (mode == MODE_PULL_DOWN_TO_REFRESH || mode == MODE_BOTH) { FrameLayout frame = new FrameLayout(context); mHeaderLoadingView = new LoadingLayout( context, MODE_PULL_DOWN_TO_REFRESH, releaseLabel, pullLabel, refreshingLabel); frame.addView( mHeaderLoadingView, FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); mHeaderLoadingView.setVisibility(View.GONE); lv.addHeaderView(frame, null, false); } if (mode == MODE_PULL_UP_TO_REFRESH || mode == MODE_BOTH) { mLvFooterLoadingFrame = new FrameLayout(context); mFooterLoadingView = new LoadingLayout( context, MODE_PULL_UP_TO_REFRESH, releaseLabel, pullLabel, refreshingLabel); mLvFooterLoadingFrame.addView( mFooterLoadingView, FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); mFooterLoadingView.setVisibility(View.GONE); } // Set it to this so it can be used in ListActivity/ListFragment lv.setId(android.R.id.list); return lv; }
protected void handleStyledAttributes(TypedArray typedarray) { super.handleStyledAttributes(typedarray); p = typedarray.getBoolean(14, true); if (p) { android.widget.FrameLayout.LayoutParams layoutparams = new android.widget.FrameLayout.LayoutParams(-1, -2, 1); FrameLayout framelayout = new FrameLayout(getContext()); m = createLoadingLayout(getContext(), PullToRefreshBase.Mode.PULL_FROM_START, typedarray); m.setVisibility(8); framelayout.addView(m, layoutparams); ((ListView)l).addHeaderView(framelayout, null, false); o = new FrameLayout(getContext()); n = createLoadingLayout(getContext(), PullToRefreshBase.Mode.PULL_FROM_END, typedarray); n.setVisibility(8); o.addView(n, layoutparams); if (!typedarray.hasValue(13)) { setScrollingWhileRefreshingEnabled(true); } } }
/** * Called when the UI has been to be updated to be in the {@link * com.handmark.pulltorefresh.library.PullToRefreshBase.State#REFRESHING} or {@link * com.handmark.pulltorefresh.library.PullToRefreshBase.State#MANUAL_REFRESHING} state. * * @param doScroll - Whether the UI should scroll for this event. */ protected void onRefreshing(final boolean doScroll) { if (mMode.showHeaderLoadingLayout()) { mHeaderLayout.refreshing(); } if (mMode.showFooterLoadingLayout()) { mFooterLayout.refreshing(); } if (doScroll) { if (mShowViewWhileRefreshing) { // Call Refresh Listener when the Scroll has finished OnSmoothScrollFinishedListener listener = new OnSmoothScrollFinishedListener() { @Override public void onSmoothScrollFinished() { callRefreshListener(); } }; switch (mCurrentMode) { case MANUAL_REFRESH_ONLY: case PULL_FROM_END: smoothScrollTo(getFooterSize(), listener); break; default: case PULL_FROM_START: smoothScrollTo(-getHeaderSize(), listener); break; } } else { smoothScrollTo(0); } } else { // We're not scrolling, so just call Refresh Listener now callRefreshListener(); } }
protected final int getFooterSize() { return mFooterLayout.getContentSize(); }
protected final int getHeaderSize() { return mHeaderLayout.getContentSize(); }
@Override protected void onRefreshing(final boolean doScroll) { /** * If we're not showing the Refreshing view, or the list is empty, the the header/footer views * won't show so we use the normal method. */ ListAdapter adapter = mRefreshableView.getAdapter(); if (!mListViewExtrasEnabled || !getShowViewWhileRefreshing() || null == adapter || adapter.isEmpty()) { super.onRefreshing(doScroll); return; } super.onRefreshing(false); final LoadingLayout origLoadingView, listViewLoadingView, oppositeListViewLoadingView; final int selection, scrollToY; switch (getCurrentMode()) { case MANUAL_REFRESH_ONLY: case PULL_FROM_END: origLoadingView = getFooterLayout(); listViewLoadingView = mFooterLoadingView; oppositeListViewLoadingView = mHeaderLoadingView; selection = mRefreshableView.getCount() - 1; scrollToY = getScrollY() - getFooterSize(); break; case PULL_FROM_START: default: origLoadingView = getHeaderLayout(); listViewLoadingView = mHeaderLoadingView; oppositeListViewLoadingView = mFooterLoadingView; selection = 0; scrollToY = getScrollY() + getHeaderSize(); break; } // Hide our original Loading View origLoadingView.reset(); origLoadingView.hideAllViews(); // Make sure the opposite end is hidden too oppositeListViewLoadingView.setVisibility(View.GONE); // Show the ListView Loading View and set it to refresh. listViewLoadingView.setVisibility(View.VISIBLE); listViewLoadingView.refreshing(); if (doScroll) { // We need to disable the automatic visibility changes for now disableLoadingLayoutVisibilityChanges(); // We scroll slightly so that the ListView's header/footer is at the // same Y position as our normal header/footer setHeaderScroll(scrollToY); // Make sure the ListView is scrolled to show the loading // header/footer mRefreshableView.setSelection(selection); // Smooth scroll as normal smoothScrollTo(0); } }