pulltorefresh微调

来源:互联网 发布:宁波软件编程工资多少 编辑:程序博客网 时间:2024/04/30 07:50


1.隐藏右边的下拉引导显示



需要修改如下两个类(避免破坏源代码,我只是注释代码):

(1).PullToRefreshAdapterViewBase.java


/******************************************************************************* * Copyright 2011, 2012 Chris Banes. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/package com.handmark.pulltorefresh.library;import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.View;import android.view.ViewGroup;import android.view.ViewParent;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.Adapter;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.FrameLayout;import android.widget.LinearLayout;import android.widget.ListAdapter;import com.handmark.pulltorefresh.library.internal.EmptyViewMethodAccessor;import com.handmark.pulltorefresh.library.internal.IndicatorLayout;import com.ishangbin.user.R;public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extends PullToRefreshBase<T> implementsOnScrollListener {private static FrameLayout.LayoutParams convertEmptyViewLayoutParams(ViewGroup.LayoutParams lp) {FrameLayout.LayoutParams newLp = null;if (null != lp) {newLp = new FrameLayout.LayoutParams(lp);if (lp instanceof LinearLayout.LayoutParams) {newLp.gravity = ((LinearLayout.LayoutParams) lp).gravity;} else {newLp.gravity = Gravity.CENTER;}}return newLp;}private boolean mLastItemVisible;private OnScrollListener mOnScrollListener;private OnLastItemVisibleListener mOnLastItemVisibleListener;private View mEmptyView;//private IndicatorLayout mIndicatorIvTop;//private IndicatorLayout mIndicatorIvBottom;private boolean mShowIndicator;private boolean mScrollEmptyView = true;public PullToRefreshAdapterViewBase(Context context) {super(context);mRefreshableView.setOnScrollListener(this);}public PullToRefreshAdapterViewBase(Context context, AttributeSet attrs) {super(context, attrs);mRefreshableView.setOnScrollListener(this);}public PullToRefreshAdapterViewBase(Context context, Mode mode) {super(context, mode);mRefreshableView.setOnScrollListener(this);}public PullToRefreshAdapterViewBase(Context context, Mode mode, AnimationStyle animStyle) {super(context, mode, animStyle);mRefreshableView.setOnScrollListener(this);}/** * Gets whether an indicator graphic should be displayed when the View is in * a state where a Pull-to-Refresh can happen. An example of this state is * when the Adapter View is scrolled to the top and the mode is set to * {@link Mode#PULL_FROM_START}. The default value is <var>true</var> if * {@link PullToRefreshBase#isPullToRefreshOverScrollEnabled() * isPullToRefreshOverScrollEnabled()} returns false. *  * @return true if the indicators will be shown */public boolean getShowIndicator() {return mShowIndicator;}public final void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,final int totalItemCount) {if (DEBUG) {Log.d(LOG_TAG, "First Visible: " + firstVisibleItem + ". Visible Count: " + visibleItemCount+ ". Total Items:" + totalItemCount);}/** * Set whether the Last Item is Visible. lastVisibleItemIndex is a * zero-based index, so we minus one totalItemCount to check */if (null != mOnLastItemVisibleListener) {mLastItemVisible = (totalItemCount > 0) && (firstVisibleItem + visibleItemCount >= totalItemCount - 1);}// If we're showing the indicator, check positions...if (getShowIndicatorInternal()) {//updateIndicatorViewsVisibility();}// Finally call OnScrollListener if we have oneif (null != mOnScrollListener) {mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);}}public final void onScrollStateChanged(final AbsListView view, final int state) {/** * Check that the scrolling has stopped, and that the last item is * visible. */if (state == OnScrollListener.SCROLL_STATE_IDLE && null != mOnLastItemVisibleListener && mLastItemVisible) {mOnLastItemVisibleListener.onLastItemVisible();}if (null != mOnScrollListener) {mOnScrollListener.onScrollStateChanged(view, state);}}/** * Pass-through method for {@link PullToRefreshBase#getRefreshableView() * getRefreshableView()}. * {@link AdapterView#setAdapter(android.widget.Adapter)} * setAdapter(adapter)}. This is just for convenience! *  * @param adapter - Adapter to set */public void setAdapter(ListAdapter adapter) {((AdapterView<ListAdapter>) mRefreshableView).setAdapter(adapter);}/** * Sets the Empty View to be used by the Adapter View. * <p/> * We need it handle it ourselves so that we can Pull-to-Refresh when the * Empty View is shown. * <p/> * Please note, you do <strong>not</strong> usually need to call this method * yourself. Calling setEmptyView on the AdapterView will automatically call * this method and set everything up. This includes when the Android * Framework automatically sets the Empty View based on it's ID. *  * @param newEmptyView - Empty View to be used */public final void setEmptyView(View newEmptyView) {FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();if (null != newEmptyView) {// New view needs to be clickable so that Android recognizes it as a// target for Touch EventsnewEmptyView.setClickable(true);ViewParent newEmptyViewParent = newEmptyView.getParent();if (null != newEmptyViewParent && newEmptyViewParent instanceof ViewGroup) {((ViewGroup) newEmptyViewParent).removeView(newEmptyView);}// We need to convert any LayoutParams so that it works in our// FrameLayoutFrameLayout.LayoutParams lp = convertEmptyViewLayoutParams(newEmptyView.getLayoutParams());if (null != lp) {refreshableViewWrapper.addView(newEmptyView, lp);} else {refreshableViewWrapper.addView(newEmptyView);}}if (mRefreshableView instanceof EmptyViewMethodAccessor) {((EmptyViewMethodAccessor) mRefreshableView).setEmptyViewInternal(newEmptyView);} else {mRefreshableView.setEmptyView(newEmptyView);}mEmptyView = newEmptyView;}/** * Pass-through method for {@link PullToRefreshBase#getRefreshableView() * getRefreshableView()}. * {@link AdapterView#setOnItemClickListener(OnItemClickListener) * setOnItemClickListener(listener)}. This is just for convenience! *  * @param listener - OnItemClickListener to use */public void setOnItemClickListener(OnItemClickListener listener) {mRefreshableView.setOnItemClickListener(listener);}public final void setOnLastItemVisibleListener(OnLastItemVisibleListener listener) {mOnLastItemVisibleListener = listener;}public final void setOnScrollListener(OnScrollListener listener) {mOnScrollListener = listener;}public final void setScrollEmptyView(boolean doScroll) {mScrollEmptyView = doScroll;}/** * Sets whether an indicator graphic should be displayed when the View is in * a state where a Pull-to-Refresh can happen. An example of this state is * when the Adapter View is scrolled to the top and the mode is set to * {@link Mode#PULL_FROM_START} *  * @param showIndicator - true if the indicators should be shown. */public void setShowIndicator(boolean showIndicator) {mShowIndicator = showIndicator;if (getShowIndicatorInternal()) {// If we're set to Show Indicator, add/update them//addIndicatorViews();} else {// If not, then remove then//removeIndicatorViews();}};@Overrideprotected void onPullToRefresh() {super.onPullToRefresh();if (getShowIndicatorInternal()) {switch (getCurrentMode()) {case PULL_FROM_END://mIndicatorIvBottom.pullToRefresh();break;case PULL_FROM_START://mIndicatorIvTop.pullToRefresh();break;default:// NO-OPbreak;}}}protected void onRefreshing(boolean doScroll) {super.onRefreshing(doScroll);if (getShowIndicatorInternal()) {//updateIndicatorViewsVisibility();}}@Overrideprotected void onReleaseToRefresh() {super.onReleaseToRefresh();if (getShowIndicatorInternal()) {switch (getCurrentMode()) {case PULL_FROM_END://mIndicatorIvBottom.releaseToRefresh();break;case PULL_FROM_START://mIndicatorIvTop.releaseToRefresh();break;default:// NO-OPbreak;}}}@Overrideprotected void onReset() {super.onReset();if (getShowIndicatorInternal()) {//updateIndicatorViewsVisibility();}}@Overrideprotected void handleStyledAttributes(TypedArray a) {// Set Show Indicator to the XML value, or default valuemShowIndicator = a.getBoolean(R.styleable.PullToRefresh_ptrShowIndicator, !isPullToRefreshOverScrollEnabled());}protected boolean isReadyForPullStart() {return isFirstItemVisible();}protected boolean isReadyForPullEnd() {return isLastItemVisible();}@Overrideprotected void onScrollChanged(int l, int t, int oldl, int oldt) {super.onScrollChanged(l, t, oldl, oldt);if (null != mEmptyView && !mScrollEmptyView) {mEmptyView.scrollTo(-l, -t);}}@Overrideprotected void updateUIForMode() {super.updateUIForMode();// Check Indicator Views consistent with new Modeif (getShowIndicatorInternal()) {//addIndicatorViews();} else {//removeIndicatorViews();}}//private void addIndicatorViews() {//Mode mode = getMode();//FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();////if (mode.showHeaderLoadingLayout() && null == mIndicatorIvTop) {//// If the mode can pull down, and we don't have one set already//mIndicatorIvTop = new IndicatorLayout(getContext(), Mode.PULL_FROM_START);//FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,//ViewGroup.LayoutParams.WRAP_CONTENT);//params.rightMargin = getResources().getDimensionPixelSize(R.dimen.indicator_right_padding);//params.gravity = Gravity.TOP | Gravity.RIGHT;//refreshableViewWrapper.addView(mIndicatorIvTop, params);////} else if (!mode.showHeaderLoadingLayout() && null != mIndicatorIvTop) {//// If we can't pull down, but have a View then remove it//refreshableViewWrapper.removeView(mIndicatorIvTop);//mIndicatorIvTop = null;//}////if (mode.showFooterLoadingLayout() && null == mIndicatorIvBottom) {//// If the mode can pull down, and we don't have one set already//mIndicatorIvBottom = new IndicatorLayout(getContext(), Mode.PULL_FROM_END);//FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,//ViewGroup.LayoutParams.WRAP_CONTENT);//params.rightMargin = getResources().getDimensionPixelSize(R.dimen.indicator_right_padding);//params.gravity = Gravity.BOTTOM | Gravity.RIGHT;//refreshableViewWrapper.addView(mIndicatorIvBottom, params);////} else if (!mode.showFooterLoadingLayout() && null != mIndicatorIvBottom) {//// If we can't pull down, but have a View then remove it//refreshableViewWrapper.removeView(mIndicatorIvBottom);//mIndicatorIvBottom = null;//}//}private boolean getShowIndicatorInternal() {return mShowIndicator && isPullToRefreshEnabled();}private boolean isFirstItemVisible() {final Adapter adapter = mRefreshableView.getAdapter();if (null == adapter || adapter.isEmpty()) {if (DEBUG) {Log.d(LOG_TAG, "isFirstItemVisible. Empty View.");}return true;} else {/** * This check should really just be: * mRefreshableView.getFirstVisiblePosition() == 0, but PtRListView * internally use a HeaderView which messes the positions up. For * now we'll just add one to account for it and rely on the inner * condition which checks getTop(). */if (mRefreshableView.getFirstVisiblePosition() <= 1) {final View firstVisibleChild = mRefreshableView.getChildAt(0);if (firstVisibleChild != null) {return firstVisibleChild.getTop() >= mRefreshableView.getTop();}}}return false;}private boolean isLastItemVisible() {final Adapter adapter = mRefreshableView.getAdapter();if (null == adapter || adapter.isEmpty()) {if (DEBUG) {Log.d(LOG_TAG, "isLastItemVisible. Empty View.");}return true;} else {final int lastItemPosition = mRefreshableView.getCount() - 1;final int lastVisiblePosition = mRefreshableView.getLastVisiblePosition();if (DEBUG) {Log.d(LOG_TAG, "isLastItemVisible. Last Item Position: " + lastItemPosition + " Last Visible Pos: "+ lastVisiblePosition);}/** * This check should really just be: lastVisiblePosition == * lastItemPosition, but PtRListView internally uses a FooterView * which messes the positions up. For me we'll just subtract one to * account for it and rely on the inner condition which checks * getBottom(). */if (lastVisiblePosition >= lastItemPosition - 1) {final int childIndex = lastVisiblePosition - mRefreshableView.getFirstVisiblePosition();final View lastVisibleChild = mRefreshableView.getChildAt(childIndex);if (lastVisibleChild != null) {return lastVisibleChild.getBottom() <= mRefreshableView.getBottom();}}}return false;}//private void removeIndicatorViews() {//if (null != mIndicatorIvTop) {//getRefreshableViewWrapper().removeView(mIndicatorIvTop);//mIndicatorIvTop = null;//}////if (null != mIndicatorIvBottom) {//getRefreshableViewWrapper().removeView(mIndicatorIvBottom);//mIndicatorIvBottom = null;//}//}////private void updateIndicatorViewsVisibility() {//if (null != mIndicatorIvTop) {//if (!isRefreshing() && isReadyForPullStart()) {//if (!mIndicatorIvTop.isVisible()) {//mIndicatorIvTop.show();//}//} else {//if (mIndicatorIvTop.isVisible()) {//mIndicatorIvTop.hide();//}//}//}////if (null != mIndicatorIvBottom) {//if (!isRefreshing() && isReadyForPullEnd()) {//if (!mIndicatorIvBottom.isVisible()) {//mIndicatorIvBottom.show();//}//} else {//if (mIndicatorIvBottom.isVisible()) {//mIndicatorIvBottom.hide();//}//}//}//}}




(2).PullToRefreshBase.java


/******************************************************************************* * Copyright 2011, 2012 Chris Banes. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/package com.handmark.pulltorefresh.library;import android.content.Context;import android.content.res.TypedArray;import android.graphics.drawable.Drawable;import android.os.Build.VERSION;import android.os.Build.VERSION_CODES;import android.os.Bundle;import android.os.Parcelable;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.view.animation.DecelerateInterpolator;import android.view.animation.Interpolator;import android.widget.FrameLayout;import android.widget.LinearLayout;import com.handmark.pulltorefresh.library.internal.FlipLoadingLayout;import com.handmark.pulltorefresh.library.internal.LoadingLayout;import com.handmark.pulltorefresh.library.internal.RotateLoadingLayout;import com.handmark.pulltorefresh.library.internal.Utils;import com.handmark.pulltorefresh.library.internal.ViewCompat;import com.ishangbin.user.R;public abstract class PullToRefreshBase<T extends View> extends LinearLayout implements IPullToRefresh<T> {    // ===========================================================    // Constants    // ===========================================================    static final boolean DEBUG = true;    static final boolean USE_HW_LAYERS = false;    static final String LOG_TAG = "PullToRefresh";    static final float FRICTION = 2.0f;    public static final int SMOOTH_SCROLL_DURATION_MS = 200;    public static final int SMOOTH_SCROLL_LONG_DURATION_MS = 325;    static final int DEMO_SCROLL_INTERVAL = 225;    static final String STATE_STATE = "ptr_state";    static final String STATE_MODE = "ptr_mode";    static final String STATE_CURRENT_MODE = "ptr_current_mode";    static final String STATE_SCROLLING_REFRESHING_ENABLED = "ptr_disable_scrolling";    static final String STATE_SHOW_REFRESHING_VIEW = "ptr_show_refreshing_view";    static final String STATE_SUPER = "ptr_super";    // ===========================================================    // Fields    // ===========================================================    private int mTouchSlop;    private float mLastMotionX, mLastMotionY;    private float mInitialMotionX, mInitialMotionY;    private boolean mIsBeingDragged = false;    private State mState = State.RESET;    private Mode mMode = Mode.getDefault();    private Mode mCurrentMode;    T mRefreshableView;    private FrameLayout mRefreshableViewWrapper;    private boolean mShowViewWhileRefreshing = true;    private boolean mScrollingWhileRefreshingEnabled = false;    private boolean mFilterTouchEvents = true;    private boolean mOverScrollEnabled = true;    private boolean mLayoutVisibilityChangesEnabled = true;    private Interpolator mScrollAnimationInterpolator;    private AnimationStyle mLoadingAnimationStyle = AnimationStyle.getDefault();    private LoadingLayout mHeaderLayout;    private LoadingLayout mFooterLayout;    private OnRefreshListener<T> mOnRefreshListener;    private OnRefreshListener2<T> mOnRefreshListener2;    private OnPullEventListener<T> mOnPullEventListener;    private SmoothScrollRunnable mCurrentSmoothScrollRunnable;    // ===========================================================    // Constructors    // ===========================================================    public PullToRefreshBase(Context context) {        super(context);        init(context, null);    }    public PullToRefreshBase(Context context, AttributeSet attrs) {        super(context, attrs);        init(context, attrs);    }    public PullToRefreshBase(Context context, Mode mode) {        super(context);        mMode = mode;        init(context, null);    }    public PullToRefreshBase(Context context, Mode mode, AnimationStyle animStyle) {        super(context);        mMode = mode;        mLoadingAnimationStyle = animStyle;        init(context, null);    }    @Override    public void addView(View child, int index, ViewGroup.LayoutParams params) {        if (DEBUG) {            Log.d(LOG_TAG, "addView: " + child.getClass().getSimpleName());        }        final T refreshableView = getRefreshableView();        if (refreshableView instanceof ViewGroup) {            ((ViewGroup) refreshableView).addView(child, index, params);        } else {            throw new UnsupportedOperationException("Refreshable View is not a ViewGroup so can't addView");        }    }    @Override    public final boolean demo() {        if (mMode.showHeaderLoadingLayout() && isReadyForPullStart()) {            smoothScrollToAndBack(-getHeaderSize() * 2);            return true;        } else if (mMode.showFooterLoadingLayout() && isReadyForPullEnd()) {            smoothScrollToAndBack(getFooterSize() * 2);            return true;        }        return false;    }    @Override    public final Mode getCurrentMode() {        return mCurrentMode;    }    @Override    public final boolean getFilterTouchEvents() {        return mFilterTouchEvents;    }    @Override    public final ILoadingLayout getLoadingLayoutProxy() {        return getLoadingLayoutProxy(true, true);    }    @Override    public final ILoadingLayout getLoadingLayoutProxy(boolean includeStart, boolean includeEnd) {        return createLoadingLayoutProxy(includeStart, includeEnd);    }    @Override    public final Mode getMode() {        return mMode;    }    @Override    public final T getRefreshableView() {        return mRefreshableView;    }    @Override    public final boolean getShowViewWhileRefreshing() {        return mShowViewWhileRefreshing;    }    @Override    public final State getState() {        return mState;    }    /**     * @deprecated See {@link #isScrollingWhileRefreshingEnabled()}.     */    public final boolean isDisableScrollingWhileRefreshing() {        return !isScrollingWhileRefreshingEnabled();    }    @Override    public final boolean isPullToRefreshEnabled() {        return mMode.permitsPullToRefresh();    }    @Override    public final boolean isPullToRefreshOverScrollEnabled() {        return VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD && mOverScrollEnabled                && OverscrollHelper.isAndroidOverScrollEnabled(mRefreshableView);    }    @Override    public final boolean isRefreshing() {        return mState == State.REFRESHING || mState == State.MANUAL_REFRESHING;    }    @Override    public final boolean isScrollingWhileRefreshingEnabled() {        return mScrollingWhileRefreshingEnabled;    }    @Override    public final boolean onInterceptTouchEvent(MotionEvent event) {        if (!isPullToRefreshEnabled()) {            return false;        }        final int action = event.getAction();        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {            mIsBeingDragged = false;            return false;        }        if (action != MotionEvent.ACTION_DOWN && mIsBeingDragged) {            return true;        }        switch (action) {        case MotionEvent.ACTION_MOVE: {            // If we're refreshing, and the flag is set. Eat all MOVE events            if (!mScrollingWhileRefreshingEnabled && isRefreshing()) {                return true;            }            if (isReadyForPull()) {                final float y = event.getY(), x = event.getX();                final float diff, oppositeDiff, absDiff;                // We need to use the correct values, based on scroll                // direction                switch (getPullToRefreshScrollDirection()) {                case HORIZONTAL:                    diff = x - mLastMotionX;                    oppositeDiff = y - mLastMotionY;                    break;                case VERTICAL:                default:                    diff = y - mLastMotionY;                    oppositeDiff = x - mLastMotionX;                    break;                }                absDiff = Math.abs(diff);                if (absDiff > mTouchSlop && (!mFilterTouchEvents || absDiff > Math.abs(oppositeDiff))) {                    if (mMode.showHeaderLoadingLayout() && diff >= 1f && isReadyForPullStart()) {                        mLastMotionY = y;                        mLastMotionX = x;                        mIsBeingDragged = true;                        if (mMode == Mode.BOTH) {                            mCurrentMode = Mode.PULL_FROM_START;                        }                    } else if (mMode.showFooterLoadingLayout() && diff <= -1f && isReadyForPullEnd()) {                        mLastMotionY = y;                        mLastMotionX = x;                        mIsBeingDragged = true;                        if (mMode == Mode.BOTH) {                            mCurrentMode = Mode.PULL_FROM_END;                        }                    }                }            }            break;        }        case MotionEvent.ACTION_DOWN: {            if (isReadyForPull()) {                mLastMotionY = mInitialMotionY = event.getY();                mLastMotionX = mInitialMotionX = event.getX();                mIsBeingDragged = false;            }            break;        }        }        return mIsBeingDragged;    }    @Override    public final void onRefreshComplete() {        if (isRefreshing()) {            setState(State.RESET);        }    }    @Override    public final boolean onTouchEvent(MotionEvent event) {        if (!isPullToRefreshEnabled()) {            return false;        }        // If we're refreshing, and the flag is set. Eat the event        if (!mScrollingWhileRefreshingEnabled && isRefreshing()) {            return true;        }        if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {            return false;        }        switch (event.getAction()) {        case MotionEvent.ACTION_MOVE: {            if (mIsBeingDragged) {                mLastMotionY = event.getY();                mLastMotionX = event.getX();                pullEvent();                return true;            }            break;        }        case MotionEvent.ACTION_DOWN: {            if (isReadyForPull()) {                mLastMotionY = mInitialMotionY = event.getY();                mLastMotionX = mInitialMotionX = event.getX();                return true;            }            break;        }        case MotionEvent.ACTION_CANCEL:        case MotionEvent.ACTION_UP: {            if (mIsBeingDragged) {                mIsBeingDragged = false;                if (mState == State.RELEASE_TO_REFRESH && (null != mOnRefreshListener || null != mOnRefreshListener2)) {                    setState(State.REFRESHING, true);                    return true;                }                // If we're already refreshing, just scroll back to the top                if (isRefreshing()) {                    smoothScrollTo(0);                    return true;                }                // If we haven't returned by here, then we're not in a state                // to pull, so just reset                setState(State.RESET);                return true;            }            break;        }        }        return false;    }    public final void setScrollingWhileRefreshingEnabled(boolean allowScrollingWhileRefreshing) {        mScrollingWhileRefreshingEnabled = allowScrollingWhileRefreshing;    }    /**     * @deprecated See {@link #setScrollingWhileRefreshingEnabled(boolean)}     */    public void setDisableScrollingWhileRefreshing(boolean disableScrollingWhileRefreshing) {        setScrollingWhileRefreshingEnabled(!disableScrollingWhileRefreshing);    }    @Override    public final void setFilterTouchEvents(boolean filterEvents) {        mFilterTouchEvents = filterEvents;    }    /**     * @deprecated You should now call this method on the result of     *             {@link #getLoadingLayoutProxy()}.     */    public void setLastUpdatedLabel(CharSequence label) {        getLoadingLayoutProxy().setLastUpdatedLabel(label);    }    /**     * @deprecated You should now call this method on the result of     *             {@link #getLoadingLayoutProxy()}.     */    public void setLoadingDrawable(Drawable drawable) {        getLoadingLayoutProxy().setLoadingDrawable(drawable);    }    /**     * @deprecated You should now call this method on the result of     *             {@link #getLoadingLayoutProxy(boolean, boolean)}.     */    public void setLoadingDrawable(Drawable drawable, Mode mode) {        getLoadingLayoutProxy(mode.showHeaderLoadingLayout(), mode.showFooterLoadingLayout()).setLoadingDrawable(                drawable);    }    @Override    public void setLongClickable(boolean longClickable) {        getRefreshableView().setLongClickable(longClickable);    }    @Override    public final void setMode(Mode mode) {        if (mode != mMode) {            if (DEBUG) {                Log.d(LOG_TAG, "Setting mode to: " + mode);            }            mMode = mode;            updateUIForMode();        }    }    public void setOnPullEventListener(OnPullEventListener<T> listener) {        mOnPullEventListener = listener;    }    @Override    public final void setOnRefreshListener(OnRefreshListener<T> listener) {        mOnRefreshListener = listener;        mOnRefreshListener2 = null;    }    @Override    public final void setOnRefreshListener(OnRefreshListener2<T> listener) {        mOnRefreshListener2 = listener;        mOnRefreshListener = null;    }    /**     * @deprecated You should now call this method on the result of     *             {@link #getLoadingLayoutProxy()}.     */    public void setPullLabel(CharSequence pullLabel) {        getLoadingLayoutProxy().setPullLabel(pullLabel);    }    /**     * @deprecated You should now call this method on the result of     *             {@link #getLoadingLayoutProxy(boolean, boolean)}.     */    public void setPullLabel(CharSequence pullLabel, Mode mode) {        getLoadingLayoutProxy(mode.showHeaderLoadingLayout(), mode.showFooterLoadingLayout()).setPullLabel(pullLabel);    }    /**     * @param enable     *            Whether Pull-To-Refresh should be used     * @deprecated This simple calls setMode with an appropriate mode based on     *             the passed value.     */    public final void setPullToRefreshEnabled(boolean enable) {        setMode(enable ? Mode.getDefault() : Mode.DISABLED);    }    @Override    public final void setPullToRefreshOverScrollEnabled(boolean enabled) {        mOverScrollEnabled = enabled;    }    @Override    public final void setRefreshing() {        setRefreshing(true);    }    @Override    public final void setRefreshing(boolean doScroll) {        if (!isRefreshing()) {            setState(State.MANUAL_REFRESHING, doScroll);        }    }    /**     * @deprecated You should now call this method on the result of     *             {@link #getLoadingLayoutProxy()}.     */    public void setRefreshingLabel(CharSequence refreshingLabel) {        getLoadingLayoutProxy().setRefreshingLabel(refreshingLabel);    }    /**     * @deprecated You should now call this method on the result of     *             {@link #getLoadingLayoutProxy(boolean, boolean)}.     */    public void setRefreshingLabel(CharSequence refreshingLabel, Mode mode) {        getLoadingLayoutProxy(mode.showHeaderLoadingLayout(), mode.showFooterLoadingLayout()).setRefreshingLabel(                refreshingLabel);    }    /**     * @deprecated You should now call this method on the result of     *             {@link #getLoadingLayoutProxy()}.     */    public void setReleaseLabel(CharSequence releaseLabel) {        setReleaseLabel(releaseLabel, Mode.BOTH);    }    /**     * @deprecated You should now call this method on the result of     *             {@link #getLoadingLayoutProxy(boolean, boolean)}.     */    public void setReleaseLabel(CharSequence releaseLabel, Mode mode) {        getLoadingLayoutProxy(mode.showHeaderLoadingLayout(), mode.showFooterLoadingLayout()).setReleaseLabel(                releaseLabel);    }    public void setScrollAnimationInterpolator(Interpolator interpolator) {        mScrollAnimationInterpolator = interpolator;    }    @Override    public final void setShowViewWhileRefreshing(boolean showView) {        mShowViewWhileRefreshing = showView;    }    /**     * @return Either {@link Orientation#VERTICAL} or     *         {@link Orientation#HORIZONTAL} depending on the scroll direction.     */    public abstract Orientation getPullToRefreshScrollDirection();    final void setState(State state, final boolean... params) {        mState = state;        if (DEBUG) {            Log.d(LOG_TAG, "State: " + mState.name());        }        switch (mState) {        case RESET:            onReset();            break;        case PULL_TO_REFRESH:            onPullToRefresh();            break;        case RELEASE_TO_REFRESH:            onReleaseToRefresh();            break;        case REFRESHING:        case MANUAL_REFRESHING:            onRefreshing(params[0]);            break;        case OVERSCROLLING:            // NO-OP            break;        }        // Call OnPullEventListener        if (null != mOnPullEventListener) {            mOnPullEventListener.onPullEvent(this, mState, mCurrentMode);        }    }    /**     * Used internally for adding view. Need because we override addView to     * pass-through to the Refreshable View     */    protected final void addViewInternal(View child, int index, ViewGroup.LayoutParams params) {        super.addView(child, index, params);    }    /**     * Used internally for adding view. Need because we override addView to     * pass-through to the Refreshable View     */    protected final void addViewInternal(View child, ViewGroup.LayoutParams params) {        super.addView(child, -1, params);    }    protected LoadingLayout createLoadingLayout(Context context, Mode mode, TypedArray attrs) {        LoadingLayout layout = mLoadingAnimationStyle.createLoadingLayout(context, mode,                getPullToRefreshScrollDirection(), attrs);        layout.setVisibility(View.INVISIBLE);        return layout;    }    /**     * Used internally for {@link #getLoadingLayoutProxy(boolean, boolean)}.     * Allows derivative classes to include any extra LoadingLayouts.     */    protected LoadingLayoutProxy createLoadingLayoutProxy(final boolean includeStart, final boolean includeEnd) {        LoadingLayoutProxy proxy = new LoadingLayoutProxy();        if (includeStart && mMode.showHeaderLoadingLayout()) {            proxy.addLayout(mHeaderLayout);        }        if (includeEnd && mMode.showFooterLoadingLayout()) {            proxy.addLayout(mFooterLayout);        }        return proxy;    }    /**     * This is implemented by derived classes to return the created View. If you     * need to use a custom View (such as a custom ListView), override this     * method and return an instance of your custom class.     * <p/>     * Be sure to set the ID of the view in this method, especially if you're     * using a ListActivity or ListFragment.     *      * @param context     *            Context to create view with     * @param attrs     *            AttributeSet from wrapped class. Means that anything you     *            include in the XML layout declaration will be routed to the     *            created View     * @return New instance of the Refreshable View     */    protected abstract T createRefreshableView(Context context, AttributeSet attrs);    protected final void disableLoadingLayoutVisibilityChanges() {        mLayoutVisibilityChangesEnabled = false;    }    protected final LoadingLayout getFooterLayout() {        return mFooterLayout;    }    protected final int getFooterSize() {        return mFooterLayout.getContentSize();    }    protected final LoadingLayout getHeaderLayout() {        return mHeaderLayout;    }    protected final int getHeaderSize() {        return mHeaderLayout.getContentSize();    }    protected int getPullToRefreshScrollDuration() {        return SMOOTH_SCROLL_DURATION_MS;    }    protected int getPullToRefreshScrollDurationLonger() {        return SMOOTH_SCROLL_LONG_DURATION_MS;    }    protected FrameLayout getRefreshableViewWrapper() {        return mRefreshableViewWrapper;    }    /**     * Allows Derivative classes to handle the XML Attrs without creating a     * TypedArray themsevles     *      * @param a     *            - TypedArray of PullToRefresh Attributes     */    protected void handleStyledAttributes(TypedArray a) {    }    /**     * Implemented by derived class to return whether the View is in a state     * where the user can Pull to Refresh by scrolling from the end.     *      * @return true if the View is currently in the correct state (for example,     *         bottom of a ListView)     */    protected abstract boolean isReadyForPullEnd();    /**     * Implemented by derived class to return whether the View is in a state     * where the user can Pull to Refresh by scrolling from the start.     *      * @return true if the View is currently the correct state (for example, top     *         of a ListView)     */    protected abstract boolean isReadyForPullStart();    /**     * Called by {@link #onRestoreInstanceState(Parcelable)} so that derivative     * classes can handle their saved instance state.     *      * @param savedInstanceState     *            - Bundle which contains saved instance state.     */    protected void onPtrRestoreInstanceState(Bundle savedInstanceState) {    }    /**     * Called by {@link #onSaveInstanceState()} so that derivative classes can     * save their instance state.     *      * @param saveState     *            - Bundle to be updated with saved state.     */    protected void onPtrSaveInstanceState(Bundle saveState) {    }    /**     * Called when the UI has been to be updated to be in the     * {@link State#PULL_TO_REFRESH} state.     */    protected void onPullToRefresh() {        switch (mCurrentMode) {        case PULL_FROM_END:            mFooterLayout.pullToRefresh();            break;        case PULL_FROM_START:            mHeaderLayout.pullToRefresh();            break;        default:            // NO-OP            break;        }    }    /**     * Called when the UI has been to be updated to be in the     * {@link State#REFRESHING} or {@link 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();        }    }    /**     * Called when the UI has been to be updated to be in the     * {@link 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;        }    }    /**     * Called when the UI has been to be updated to be in the     * {@link State#RESET} state.     */    protected void onReset() {        mIsBeingDragged = false;        mLayoutVisibilityChangesEnabled = true;        // Always reset both layouts, just in case...        mHeaderLayout.reset();        mFooterLayout.reset();        smoothScrollTo(0);    }    @Override    protected final void onRestoreInstanceState(Parcelable state) {        if (state instanceof Bundle) {            Bundle bundle = (Bundle) state;            setMode(Mode.mapIntToValue(bundle.getInt(STATE_MODE, 0)));            mCurrentMode = Mode.mapIntToValue(bundle.getInt(STATE_CURRENT_MODE, 0));            mScrollingWhileRefreshingEnabled = bundle.getBoolean(STATE_SCROLLING_REFRESHING_ENABLED, false);            mShowViewWhileRefreshing = bundle.getBoolean(STATE_SHOW_REFRESHING_VIEW, true);            // Let super Restore Itself            super.onRestoreInstanceState(bundle.getParcelable(STATE_SUPER));            State viewState = State.mapIntToValue(bundle.getInt(STATE_STATE, 0));            if (viewState == State.REFRESHING || viewState == State.MANUAL_REFRESHING) {                setState(viewState, true);            }            // Now let derivative classes restore their state            onPtrRestoreInstanceState(bundle);            return;        }        super.onRestoreInstanceState(state);    }    @Override    protected final Parcelable onSaveInstanceState() {        Bundle bundle = new Bundle();        // Let derivative classes get a chance to save state first, that way we        // can make sure they don't overrite any of our values        onPtrSaveInstanceState(bundle);        bundle.putInt(STATE_STATE, mState.getIntValue());        bundle.putInt(STATE_MODE, mMode.getIntValue());        bundle.putInt(STATE_CURRENT_MODE, mCurrentMode.getIntValue());        bundle.putBoolean(STATE_SCROLLING_REFRESHING_ENABLED, mScrollingWhileRefreshingEnabled);        bundle.putBoolean(STATE_SHOW_REFRESHING_VIEW, mShowViewWhileRefreshing);        bundle.putParcelable(STATE_SUPER, super.onSaveInstanceState());        return bundle;    }    @Override    protected final void onSizeChanged(int w, int h, int oldw, int oldh) {        if (DEBUG) {            Log.d(LOG_TAG, String.format("onSizeChanged. W: %d, H: %d", w, h));        }        super.onSizeChanged(w, h, oldw, oldh);        // We need to update the header/footer when our size changes        refreshLoadingViewsSize();        // Update the Refreshable View layout        refreshRefreshableViewSize(w, h);        /**         * As we're currently in a Layout Pass, we need to schedule another one         * to layout any changes we've made here         */        post(new Runnable() {            @Override            public void run() {                requestLayout();            }        });    }    /**     * 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);    }    protected final void refreshRefreshableViewSize(int width, int height) {        // We need to set the Height of the Refreshable View to the same as        // this layout        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mRefreshableViewWrapper.getLayoutParams();        switch (getPullToRefreshScrollDirection()) {        case HORIZONTAL:            if (lp.width != width) {                lp.width = width;                mRefreshableViewWrapper.requestLayout();            }            break;        case VERTICAL:            if (lp.height != height) {                lp.height = height;                mRefreshableViewWrapper.requestLayout();            }            break;        }    }    /**     * 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 ? View.LAYER_TYPE_HARDWARE                    : View.LAYER_TYPE_NONE);        }        switch (getPullToRefreshScrollDirection()) {        case VERTICAL:            scrollTo(0, value);            break;        case HORIZONTAL:            scrollTo(value, 0);            break;        }    }    /**     * Smooth Scroll to position using the default duration of     * {@value #SMOOTH_SCROLL_DURATION_MS} ms.     *      * @param scrollValue     *            - Position to scroll to     */    protected final void smoothScrollTo(int scrollValue) {        smoothScrollTo(scrollValue, getPullToRefreshScrollDuration());    }    /**     * Smooth Scroll to position using the default duration of     * {@value #SMOOTH_SCROLL_DURATION_MS} ms.     *      * @param scrollValue     *            - Position to scroll to     * @param listener     *            - Listener for scroll     */    protected final void smoothScrollTo(int scrollValue, OnSmoothScrollFinishedListener listener) {        smoothScrollTo(scrollValue, getPullToRefreshScrollDuration(), 0, listener);    }    /**     * Smooth Scroll to position using the longer default duration of     * {@value #SMOOTH_SCROLL_LONG_DURATION_MS} ms.     *      * @param scrollValue     *            - Position to scroll to     */    protected final void smoothScrollToLonger(int scrollValue) {        smoothScrollTo(scrollValue, getPullToRefreshScrollDurationLonger());    }    /**     * 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 LinearLayout.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;    }    private void addRefreshableView(Context context, T refreshableView) {        mRefreshableViewWrapper = new FrameLayout(context);        mRefreshableViewWrapper.addView(refreshableView, ViewGroup.LayoutParams.MATCH_PARENT,                ViewGroup.LayoutParams.MATCH_PARENT);        addViewInternal(mRefreshableViewWrapper, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,                LayoutParams.MATCH_PARENT));    }    private void callRefreshListener() {        if (null != mOnRefreshListener) {            mOnRefreshListener.onRefresh(this);        } else if (null != mOnRefreshListener2) {            if (mCurrentMode == Mode.PULL_FROM_START) {                mOnRefreshListener2.onPullDownToRefresh(this);            } else if (mCurrentMode == Mode.PULL_FROM_END) {                mOnRefreshListener2.onPullUpToRefresh(this);            }        }    }    @SuppressWarnings("deprecation")    private void init(Context context, AttributeSet attrs) {        switch (getPullToRefreshScrollDirection()) {        case HORIZONTAL:            setOrientation(LinearLayout.HORIZONTAL);            break;        case VERTICAL:        default:            setOrientation(LinearLayout.VERTICAL);            break;        }        setGravity(Gravity.CENTER);        ViewConfiguration config = ViewConfiguration.get(context);        mTouchSlop = config.getScaledTouchSlop();        // Styleables from XML        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PullToRefresh);        if (a.hasValue(R.styleable.PullToRefresh_ptrMode)) {            mMode = Mode.mapIntToValue(a.getInteger(R.styleable.PullToRefresh_ptrMode, 0));        }        if (a.hasValue(R.styleable.PullToRefresh_ptrAnimationStyle)) {            mLoadingAnimationStyle = AnimationStyle.mapIntToValue(a.getInteger(                    R.styleable.PullToRefresh_ptrAnimationStyle, 0));        }        // Refreshable View        // By passing the attrs, we can add ListView/GridView params via XML        mRefreshableView = createRefreshableView(context, attrs);        addRefreshableView(context, mRefreshableView);        // We need to create now layouts now        mHeaderLayout = createLoadingLayout(context, Mode.PULL_FROM_START, a);        mFooterLayout = createLoadingLayout(context, Mode.PULL_FROM_END, a);        /**         * Styleables from XML         */        if (a.hasValue(R.styleable.PullToRefresh_ptrRefreshableViewBackground)) {            Drawable background = a.getDrawable(R.styleable.PullToRefresh_ptrRefreshableViewBackground);            if (null != background) {                mRefreshableView.setBackgroundDrawable(background);            }        } else if (a.hasValue(R.styleable.PullToRefresh_ptrAdapterViewBackground)) {            Utils.warnDeprecation("ptrAdapterViewBackground", "ptrRefreshableViewBackground");            Drawable background = a.getDrawable(R.styleable.PullToRefresh_ptrAdapterViewBackground);            if (null != background) {                mRefreshableView.setBackgroundDrawable(background);            }        }        if (a.hasValue(R.styleable.PullToRefresh_ptrOverScroll)) {            mOverScrollEnabled = a.getBoolean(R.styleable.PullToRefresh_ptrOverScroll, true);        }        if (a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) {            mScrollingWhileRefreshingEnabled = a.getBoolean(                    R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled, false);        }        // Let the derivative classes have a go at handling attributes, then        // recycle them...        handleStyledAttributes(a);        a.recycle();        // Finally update the UI for the modes        updateUIForMode();    }    private boolean isReadyForPull() {        switch (mMode) {        case PULL_FROM_START:            return isReadyForPullStart();        case PULL_FROM_END:            return isReadyForPullEnd();        case BOTH:            return isReadyForPullEnd() || isReadyForPullStart();        default:            return false;        }    }    /**     * 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);            }        }    }    private LinearLayout.LayoutParams getLoadingLayoutLayoutParams() {        switch (getPullToRefreshScrollDirection()) {        case HORIZONTAL:            return new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,                    LinearLayout.LayoutParams.MATCH_PARENT);        case VERTICAL:        default:            return new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,                    LinearLayout.LayoutParams.WRAP_CONTENT);        }    }    private int getMaximumPullScroll() {        switch (getPullToRefreshScrollDirection()) {        case HORIZONTAL:            return Math.round(getWidth() / FRICTION);        case VERTICAL:        default:            return Math.round(getHeight() / FRICTION);        }    }    /**     * Smooth Scroll to position using the specific duration     *      * @param scrollValue     *            - Position to scroll to     * @param duration     *            - Duration of animation in milliseconds     */    private final void smoothScrollTo(int scrollValue, long duration) {        smoothScrollTo(scrollValue, duration, 0, null);    }    private final void smoothScrollTo(int newScrollValue, long duration, long delayMillis,            OnSmoothScrollFinishedListener listener) {        if (null != mCurrentSmoothScrollRunnable) {            mCurrentSmoothScrollRunnable.stop();        }        final int oldScrollValue;        switch (getPullToRefreshScrollDirection()) {        case HORIZONTAL:            oldScrollValue = getScrollX();            break;        case VERTICAL:        default:            oldScrollValue = getScrollY();            break;        }        if (oldScrollValue != newScrollValue) {            if (null == mScrollAnimationInterpolator) {                // Default interpolator is a Decelerate Interpolator                mScrollAnimationInterpolator = new DecelerateInterpolator();            }            mCurrentSmoothScrollRunnable = new SmoothScrollRunnable(oldScrollValue, newScrollValue, duration, listener);            if (delayMillis > 0) {                postDelayed(mCurrentSmoothScrollRunnable, delayMillis);            } else {                post(mCurrentSmoothScrollRunnable);            }        }    }    private final void smoothScrollToAndBack(int y) {        smoothScrollTo(y, SMOOTH_SCROLL_DURATION_MS, 0, new OnSmoothScrollFinishedListener() {            @Override            public void onSmoothScrollFinished() {                smoothScrollTo(0, SMOOTH_SCROLL_DURATION_MS, DEMO_SCROLL_INTERVAL, null);            }        });    }    public static enum AnimationStyle {        /**         * This is the default for Android-PullToRefresh. Allows you to use any         * drawable, which is automatically rotated and used as a Progress Bar.         */        ROTATE,        /**         * This is the old default, and what is commonly used on iOS. Uses an         * arrow image which flips depending on where the user has scrolled.         */        FLIP;        static AnimationStyle getDefault() {            return ROTATE;        }        /**         * Maps an int to a specific mode. This is needed when saving state, or         * inflating the view from XML where the mode is given through a attr         * int.         *          * @param modeInt         *            - int to map a Mode to         * @return Mode that modeInt maps to, or ROTATE by default.         */        static AnimationStyle mapIntToValue(int modeInt) {            switch (modeInt) {            case 0x0:            default:                return ROTATE;            case 0x1:                return FLIP;            }        }        LoadingLayout createLoadingLayout(Context context, Mode mode, Orientation scrollDirection, TypedArray attrs) {            switch (this) {            case ROTATE:            case FLIP:            default:                return new RotateLoadingLayout(context, mode, scrollDirection, attrs);//            case FLIP://                return new FlipLoadingLayout(context, mode, scrollDirection, attrs);            }        }    }    public static enum Mode {        /**         * Disable all Pull-to-Refresh gesture and Refreshing handling         */        DISABLED(0x0),        /**         * Only allow the user to Pull from the start of the Refreshable View to         * refresh. The start is either the Top or Left, depending on the         * scrolling direction.         */        PULL_FROM_START(0x1),        /**         * Only allow the user to Pull from the end of the Refreshable View to         * refresh. The start is either the Bottom or Right, depending on the         * scrolling direction.         */        PULL_FROM_END(0x2),        /**         * Allow the user to both Pull from the start, from the end to refresh.         */        BOTH(0x3),        /**         * Disables Pull-to-Refresh gesture handling, but allows manually         * setting the Refresh state via         * {@link PullToRefreshBase#setRefreshing() setRefreshing()}.         */        MANUAL_REFRESH_ONLY(0x4);        /**         * @deprecated Use {@link #PULL_FROM_START} from now on.         */        public static Mode PULL_DOWN_TO_REFRESH = Mode.PULL_FROM_START;        /**         * @deprecated Use {@link #PULL_FROM_END} from now on.         */        public static Mode PULL_UP_TO_REFRESH = Mode.PULL_FROM_END;        /**         * Maps an int to a specific mode. This is needed when saving state, or         * inflating the view from XML where the mode is given through a attr         * int.         *          * @param modeInt         *            - int to map a Mode to         * @return Mode that modeInt maps to, or PULL_FROM_START by default.         */        static Mode mapIntToValue(final int modeInt) {            for (Mode value : Mode.values()) {                if (modeInt == value.getIntValue()) {                    return value;                }            }            // If not, return default            return getDefault();        }        static Mode getDefault() {            return PULL_FROM_START;        }        private int mIntValue;        // The modeInt values need to match those from attrs.xml        Mode(int modeInt) {            mIntValue = modeInt;        }        /**         * @return true if the mode permits Pull-to-Refresh         */        boolean permitsPullToRefresh() {            return !(this == DISABLED || this == MANUAL_REFRESH_ONLY);        }        /**         * @return true if this mode wants the Loading Layout Header to be shown         */        public boolean showHeaderLoadingLayout() {            return this == PULL_FROM_START || this == BOTH;        }        /**         * @return true if this mode wants the Loading Layout Footer to be shown         */        public boolean showFooterLoadingLayout() {            return this == PULL_FROM_END || this == BOTH || this == MANUAL_REFRESH_ONLY;        }        int getIntValue() {            return mIntValue;        }    }    // ===========================================================    // Inner, Anonymous Classes, and Enumerations    // ===========================================================    /**     * Simple Listener that allows you to be notified when the user has scrolled     * to the end of the AdapterView. See (     * {@link PullToRefreshAdapterViewBase#setOnLastItemVisibleListener}.     *      * @author Chris Banes     */    public static interface OnLastItemVisibleListener {        /**         * Called when the user has scrolled to the end of the list         */        public void onLastItemVisible();    }    /**     * Listener that allows you to be notified when the user has started or     * finished a touch event. Useful when you want to append extra UI events     * (such as sounds). See (     * {@link PullToRefreshAdapterViewBase#setOnPullEventListener}.     *      * @author Chris Banes     */    public static interface OnPullEventListener<V extends View> {        /**         * Called when the internal state has been changed, usually by the user         * pulling.         *          * @param refreshView         *            - View which has had it's state change.         * @param state         *            - The new state of View.         * @param direction         *            - One of {@link Mode#PULL_FROM_START} or         *            {@link Mode#PULL_FROM_END} depending on which direction         *            the user is pulling. Only useful when <var>state</var> is         *            {@link State#PULL_TO_REFRESH} or         *            {@link State#RELEASE_TO_REFRESH}.         */        public void onPullEvent(final PullToRefreshBase<V> refreshView, State state, Mode direction);    }    /**     * Simple Listener to listen for any callbacks to Refresh.     *      * @author Chris Banes     */    public static interface OnRefreshListener<V extends View> {        /**         * onRefresh will be called for both a Pull from start, and Pull from         * end         */        public void onRefresh(final PullToRefreshBase<V> refreshView);    }    /**     * An advanced version of the Listener to listen for callbacks to Refresh.     * This listener is different as it allows you to differentiate between Pull     * Ups, and Pull Downs.     *      * @author Chris Banes     */    public static interface OnRefreshListener2<V extends View> {        // TODO These methods need renaming to START/END rather than DOWN/UP        /**         * onPullDownToRefresh will be called only when the user has Pulled from         * the start, and released.         */        public void onPullDownToRefresh(final PullToRefreshBase<V> refreshView);        /**         * onPullUpToRefresh will be called only when the user has Pulled from         * the end, and released.         */        public void onPullUpToRefresh(final PullToRefreshBase<V> refreshView);    }    public static enum Orientation {        VERTICAL, HORIZONTAL;    }    public static enum State {        /**         * When the UI is in a state which means that user is not interacting         * with the Pull-to-Refresh function.         */        RESET(0x0),        /**         * When the UI is being pulled by the user, but has not been pulled far         * enough so that it refreshes when released.         */        PULL_TO_REFRESH(0x1),        /**         * When the UI is being pulled by the user, and <strong>has</strong>         * been pulled far enough so that it will refresh when released.         */        RELEASE_TO_REFRESH(0x2),        /**         * When the UI is currently refreshing, caused by a pull gesture.         */        REFRESHING(0x8),        /**         * When the UI is currently refreshing, caused by a call to         * {@link PullToRefreshBase#setRefreshing() setRefreshing()}.         */        MANUAL_REFRESHING(0x9),        /**         * When the UI is currently overscrolling, caused by a fling on the         * Refreshable View.         */        OVERSCROLLING(0x10);        /**         * Maps an int to a specific state. This is needed when saving state.         *          * @param stateInt         *            - int to map a State to         * @return State that stateInt maps to         */        static State mapIntToValue(final int stateInt) {            for (State value : State.values()) {                if (stateInt == value.getIntValue()) {                    return value;                }            }            // If not, return default            return RESET;        }        private int mIntValue;        State(int intValue) {            mIntValue = intValue;        }        int getIntValue() {            return mIntValue;        }    }    final class SmoothScrollRunnable implements Runnable {        private final Interpolator mInterpolator;        private final int mScrollToY;        private final int mScrollFromY;        private final long mDuration;        private OnSmoothScrollFinishedListener mListener;        private boolean mContinueRunning = true;        private long mStartTime = -1;        private int mCurrentY = -1;        public SmoothScrollRunnable(int fromY, int toY, long duration, OnSmoothScrollFinishedListener listener) {            mScrollFromY = fromY;            mScrollToY = toY;            mInterpolator = mScrollAnimationInterpolator;            mDuration = duration;            mListener = listener;        }        @Override        public void run() {            /**             * Only set mStartTime if this is the first time we're starting,             * else actually calculate the Y delta             */            if (mStartTime == -1) {                mStartTime = System.currentTimeMillis();            } else {                /**                 * We do do all calculations in long to reduce software float                 * calculations. We use 1000 as it gives us good accuracy and                 * small rounding errors                 */                long normalizedTime = (1000 * (System.currentTimeMillis() - mStartTime)) / mDuration;                normalizedTime = Math.max(Math.min(normalizedTime, 1000), 0);                final int deltaY = Math.round((mScrollFromY - mScrollToY)                        * mInterpolator.getInterpolation(normalizedTime / 1000f));                mCurrentY = mScrollFromY - deltaY;                setHeaderScroll(mCurrentY);            }            // If we're not at the target Y, keep going...            if (mContinueRunning && mScrollToY != mCurrentY) {                ViewCompat.postOnAnimation(PullToRefreshBase.this, this);            } else {                if (null != mListener) {                    mListener.onSmoothScrollFinished();                }            }        }        public void stop() {            mContinueRunning = false;            removeCallbacks(this);        }    }    static interface OnSmoothScrollFinishedListener {        void onSmoothScrollFinished();    }    public boolean isHeaderShown() {        return getHeaderLayout().isShown();    }    public boolean isFooterShown() {        return getFooterLayout().isShown();    }}


2.正在刷新或者加载的时候,不隐藏时间内容(修改LoadingLayout.java)


public final void refreshing() {if (null != mHeaderText) {mHeaderText.setText(mRefreshingLabel);}if (mUseIntrinsicAnimation) {((AnimationDrawable) mHeaderImage.getDrawable()).start();} else {// Now call the callbackrefreshingImpl();}//if (null != mSubHeaderText) {//隐藏时间文本//mSubHeaderText.setVisibility(View.GONE);//}}


3.修改时间和刷新状态文字的字体颜色(pull_to_refresh_header_vertical.xml)

            <TextView                android:id="@+id/pull_to_refresh_text"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:singleLine="true"                android:textAppearance="?android:attr/textAppearance"                android:textColor="#696969"                android:textStyle="bold" />            <TextView                android:id="@+id/pull_to_refresh_sub_texts"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:singleLine="true"                android:textAppearance="?android:attr/textAppearanceSmall"                android:textColor="#696969"                android:visibility="gone" />


4.修改刷新的图片(替换drawable-hdpi目录下的如下文件)


default_ptr_rotate.png


5.修改刷新的文字


(1)xml设置(values或者values-zh目录下的pull_refresh_strings.xml)

  <!-- pull_down -->    <string name="pull_to_refresh_pull_label">下拉刷新</string>    <string name="pull_to_refresh_release_label">释放立即刷新</string>    <string name="pull_to_refresh_refreshing_label">正在刷新…</string>    <!-- pull_up -->    <string name="pull_to_refresh_from_bottom_pull_label">上拉加载</string>    <string name="pull_to_refresh_from_bottom_release_label">释放立即加载</string>    <string name="pull_to_refresh_from_bottom_refreshing_label">正在加载…</string>

(2)代码设置

<pre name="code" class="java">        String label = DateUtils.formatDateTime(getActivity(), System.currentTimeMillis(), DateUtils.FORMAT_SHOW_TIME                | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL);        // 下拉刷新时的提示文本设置        lvBranch.getLoadingLayoutProxy(true, false).setLastUpdatedLabel(label);        lvBranch.getLoadingLayoutProxy(true, false).setPullLabel("下拉刷新");        lvBranch.getLoadingLayoutProxy(true, false).setRefreshingLabel("正在刷新...");        lvBranch.getLoadingLayoutProxy(true, false).setReleaseLabel("释放立即刷新");        // 上拉加载更多时的提示文本设置        lvBranch.getLoadingLayoutProxy(false, true).setLastUpdatedLabel(label);        lvBranch.getLoadingLayoutProxy(false, true).setPullLabel("上拉加载");        lvBranch.getLoadingLayoutProxy(false, true).setRefreshingLabel("正在加载...");        lvBranch.getLoadingLayoutProxy(false, true).setReleaseLabel("释放立即加载");



0 0
原创粉丝点击