public class PullToRefreshListView extends ListView implements OnScrollListener {    private static final int TAP_TO_REFRESH = 1;    private static final int PULL_TO_REFRESH = 2;    private static final int RELEASE_TO_REFRESH = 3;    private static final int REFRESHING = 4;    private static final String TAG = "PullToRefreshListView";    private OnRefreshListener mOnRefreshListener;    /**     * Listener that will receive notifications every time the list scrolls.     */    private OnScrollListener mOnScrollListener;    private LayoutInflater mInflater;    private LinearLayout mRefreshView;    private TextView mRefreshViewText;    private ImageView mRefreshViewImage;    private ProgressBar mRefreshViewProgress;    private TextView mRefreshViewLastUpdated;    private int mCurrentScrollState;    private int mRefreshState;    private RotateAnimation mFlipAnimation;    private RotateAnimation mReverseFlipAnimation;    private int mRefreshViewHeight;    private int mRefreshOriginalTopPadding;    private int mLastMotionY;    public PullToRefreshListView(Context context) {        super(context);        init(context);    }    public PullToRefreshListView(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init(context);    }    private void init(Context context) {        // Load all of the animations we need in code rather than through XML        mFlipAnimation = new RotateAnimation(0, -180,                RotateAnimation.RELATIVE_TO_SELF, 0.5f,                RotateAnimation.RELATIVE_TO_SELF, 0.5f);        mFlipAnimation.setInterpolator(new LinearInterpolator());        mFlipAnimation.setDuration(250);        mFlipAnimation.setFillAfter(true);        mReverseFlipAnimation = new RotateAnimation(-180, 0,                RotateAnimation.RELATIVE_TO_SELF, 0.5f,                RotateAnimation.RELATIVE_TO_SELF, 0.5f);        mReverseFlipAnimation.setInterpolator(new LinearInterpolator());        mReverseFlipAnimation.setDuration(250);        mReverseFlipAnimation.setFillAfter(true);        mInflater = (LayoutInflater) context.getSystemService(                Context.LAYOUT_INFLATER_SERVICE);        mRefreshView = (LinearLayout) mInflater.inflate(                R.layout.pull_to_refresh_header, null);        mRefreshViewText =            (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);        mRefreshViewImage =            (ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);        mRefreshViewProgress =            (ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);        mRefreshViewLastUpdated =            (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);        mRefreshViewImage.setMinimumHeight(50);        mRefreshView.setOnClickListener(new OnClickRefreshListener());        mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();        mRefreshState = TAP_TO_REFRESH;        addHeaderView(mRefreshView);        super.setOnScrollListener(this);        measureView(mRefreshView);        mRefreshViewHeight = mRefreshView.getMeasuredHeight();    }    @Override    protected void onAttachedToWindow() {        setSelection(1);    }    @Override    public void setAdapter(ListAdapter adapter) {        super.setAdapter(adapter);        setSelection(1);    }    /**     * Set the listener that will receive notifications every time the list     * scrolls.     *      * @param l The scroll listener.      */    @Override    public void setOnScrollListener(AbsListView.OnScrollListener l) {        mOnScrollListener = l;    }    /**     * Register a callback to be invoked when this list should be refreshed.     *      * @param onRefreshListener The callback to run.     */    public void setOnRefreshListener(OnRefreshListener onRefreshListener) {        mOnRefreshListener = onRefreshListener;    }    /**     * Set a text to represent when the list was last updated.      * @param lastUpdated Last updated at.     */    public void setLastUpdated(CharSequence lastUpdated) {        if (lastUpdated != null) {            mRefreshViewLastUpdated.setVisibility(View.VISIBLE);            mRefreshViewLastUpdated.setText(lastUpdated);        } else {            mRefreshViewLastUpdated.setVisibility(View.GONE);        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        final int y = (int) event.getY();        switch (event.getAction()) {            case MotionEvent.ACTION_UP:                if (!isVerticalScrollBarEnabled()) {                    setVerticalScrollBarEnabled(true);                }                if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {                    if ((mRefreshView.getBottom() > mRefreshViewHeight                            || mRefreshView.getTop() >= 0)                            && mRefreshState == RELEASE_TO_REFRESH) {                        // Initiate the refresh                        mRefreshState = REFRESHING;                        prepareForRefresh();                        onRefresh();                    } else if (mRefreshView.getBottom() < mRefreshViewHeight                            || mRefreshView.getTop() < 0) {                        // Abort refresh and scroll down below the refresh view                        resetHeader();                        setSelection(1);                    }                }                break;            case MotionEvent.ACTION_DOWN:                mLastMotionY = y;                break;            case MotionEvent.ACTION_MOVE:                applyHeaderPadding(event);                break;        }        return super.onTouchEvent(event);    }    private void applyHeaderPadding(MotionEvent ev) {        final int historySize = ev.getHistorySize();        // Workaround for getPointerCount() which is unavailable in 1.5        // (it's always 1 in 1.5)        int pointerCount = 1;        try {            Method method = MotionEvent.class.getMethod("getPointerCount");            pointerCount = (Integer)method.invoke(ev);        } catch (NoSuchMethodException e) {            pointerCount = 1;        } catch (IllegalArgumentException e) {            throw e;        } catch (IllegalAccessException e) {            System.err.println("unexpected " + e);        } catch (InvocationTargetException e) {            System.err.println("unexpected " + e);        }        for (int h = 0; h < historySize; h++) {            for (int p = 0; p < pointerCount; p++) {                if (mRefreshState == RELEASE_TO_REFRESH) {                    if (isVerticalFadingEdgeEnabled()) {                        setVerticalScrollBarEnabled(false);                    }                    int historicalY = 0;                    try {                        // For Android > 2.0                        Method method = MotionEvent.class.getMethod(                                "getHistoricalY", Integer.TYPE, Integer.TYPE);                        historicalY = ((Float) method.invoke(ev, p, h)).intValue();                    } catch (NoSuchMethodException e) {                        // For Android < 2.0                        historicalY = (int) (ev.getHistoricalY(h));                    } catch (IllegalArgumentException e) {                        throw e;                    } catch (IllegalAccessException e) {                        System.err.println("unexpected " + e);                    } catch (InvocationTargetException e) {                        System.err.println("unexpected " + e);                    }                    // Calculate the padding to apply, we divide by 1.7 to                    // simulate a more resistant effect during pull.                    int topPadding = (int) (((historicalY - mLastMotionY)                            - mRefreshViewHeight) / 1.7);                    mRefreshView.setPadding(                            mRefreshView.getPaddingLeft(),                            topPadding,                            mRefreshView.getPaddingRight(),                            mRefreshView.getPaddingBottom());                }            }        }    }    /**     * Sets the header padding back to original size.     */    private void resetHeaderPadding() {        mRefreshView.setPadding(                mRefreshView.getPaddingLeft(),                mRefreshOriginalTopPadding,                mRefreshView.getPaddingRight(),                mRefreshView.getPaddingBottom());    }    /**     * Resets the header to the original state.     */    private void resetHeader() {        if (mRefreshState != TAP_TO_REFRESH) {            mRefreshState = TAP_TO_REFRESH;            resetHeaderPadding();            // Set refresh view text to the pull label            mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);            // Replace refresh drawable with arrow drawable            mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);            // Clear the full rotation animation            mRefreshViewImage.clearAnimation();            // Hide progress bar and arrow.            mRefreshViewImage.setVisibility(View.GONE);            mRefreshViewProgress.setVisibility(View.GONE);        }    }    private void measureView(View child) {        ViewGroup.LayoutParams p = child.getLayoutParams();        if (p == null) {            p = new ViewGroup.LayoutParams(                    ViewGroup.LayoutParams.FILL_PARENT,                    ViewGroup.LayoutParams.WRAP_CONTENT);        }        int childWidthSpec = ViewGroup.getChildMeasureSpec(0,                0 + 0, p.width);        int lpHeight = p.height;        int childHeightSpec;        if (lpHeight > 0) {            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);        } else {            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);        }        child.measure(childWidthSpec, childHeightSpec);    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem,            int visibleItemCount, int totalItemCount) {        // When the refresh view is completely visible, change the text to say        // "Release to refresh..." and flip the arrow drawable.        if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL                && mRefreshState != REFRESHING) {            if (firstVisibleItem == 0) {                mRefreshViewImage.setVisibility(View.VISIBLE);                if ((mRefreshView.getBottom() > mRefreshViewHeight + 20                        || mRefreshView.getTop() >= 0)                        && mRefreshState != RELEASE_TO_REFRESH) {                    mRefreshViewText.setText(R.string.pull_to_refresh_release_label);                    mRefreshViewImage.clearAnimation();                    mRefreshViewImage.startAnimation(mFlipAnimation);                    mRefreshState = RELEASE_TO_REFRESH;                } else if (mRefreshView.getBottom() < mRefreshViewHeight + 20                        && mRefreshState != PULL_TO_REFRESH) {                    mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);                    if (mRefreshState != TAP_TO_REFRESH) {                        mRefreshViewImage.clearAnimation();                        mRefreshViewImage.startAnimation(mReverseFlipAnimation);                    }                    mRefreshState = PULL_TO_REFRESH;                }            } else {                mRefreshViewImage.setVisibility(View.GONE);                resetHeader();            }        } else if (mCurrentScrollState == SCROLL_STATE_FLING                && firstVisibleItem == 0                && mRefreshState != REFRESHING) {            setSelection(1);        }        if (mOnScrollListener != null) {            mOnScrollListener.onScroll(view, firstVisibleItem,                    visibleItemCount, totalItemCount);        }    }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        mCurrentScrollState = scrollState;        if (mOnScrollListener != null) {            mOnScrollListener.onScrollStateChanged(view, scrollState);        }    }    public void prepareForRefresh() {        resetHeaderPadding();        mRefreshViewImage.setVisibility(View.GONE);        // We need this hack, otherwise it will keep the previous drawable.        mRefreshViewImage.setImageDrawable(null);        mRefreshViewProgress.setVisibility(View.VISIBLE);        // Set refresh view text to the refreshing label        mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);        mRefreshState = REFRESHING;    }    public void onRefresh() {        Log.d(TAG, "onRefresh");        if (mOnRefreshListener != null) {            mOnRefreshListener.onRefresh();        }    }    /**     * Resets the list to a normal state after a refresh.     * @param lastUpdated Last updated at.     */    public void onRefreshComplete(CharSequence lastUpdated) {        setLastUpdated(lastUpdated);        onRefreshComplete();    }    /**     * Resets the list to a normal state after a refresh.     */    public void onRefreshComplete() {                Log.d(TAG, "onRefreshComplete");        resetHeader();        // If refresh view is visible when loading completes, scroll down to        // the next item.        if (mRefreshView.getBottom() > 0) {            invalidateViews();            setSelection(1);        }    }    /**     * Invoked when the refresh view is clicked on. This is mainly used when     * there's only a few items in the list and it's not possible to drag the     * list.     */    private class OnClickRefreshListener implements OnClickListener {        @Override        public void onClick(View v) {            if (mRefreshState != REFRESHING) {                prepareForRefresh();                onRefresh();            }        }    }    /**     * Interface definition for a callback to be invoked when list should be     * refreshed.     */    public interface OnRefreshListener {        /**         * Called when the list should be refreshed.         * <p>         * A call to {@link PullToRefreshListView #onRefreshComplete()} is         * expected to indicate that the refresh has completed.         */        public void onRefresh();    }}

更多相关文章

  1. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. android随笔06——单元测试
  2. android的Http请求组件
  3. android常用类
  4. Android监听摇一摇
  5. Android Lazy listview
  6. Programmatically Injecting Events on A
  7. Pull To Refresh for Android
  8. C++开发安卓、windows下搭建Android(安卓
  9. Android 学习笔记(四):安卓开发权限速查
  10. 一个讲的很好的android SDK 入门网站