当前位置: 代码迷 >> Android >> Android ListView pull up to refresh 改建(转)
  详细解决方案

Android ListView pull up to refresh 改建(转)

热度:205   发布时间:2016-05-01 19:15:33.0
Android ListView pull up to refresh 改造(转)
转自: http://dengyin2000.iteye.com/blog/1187823
android的UI组件,其中就包括了一个android-pulltorefresh组件。

https://github.com/johannilsson/android-pulltorefresh

这个组件是用在twitter微博中的, 往下拉列表的话, 顶部会自动load, 而且有反弹的效果,非常cool。 但是它的自动load顶部的内部, 我现在需要拖拉listview到最后的时候load。这个组件不知道方向的选择, 所以自己就动手改了下,实现从底部load。 (今天发现新浪微博也实现了同样的功能。)  附件是源码。
com.markupartist.android.widget.PullToRefreshListView
package com.markupartist.android.widget;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.animation.LinearInterpolator;import android.view.animation.RotateAnimation;import android.widget.*;import android.widget.AbsListView.OnScrollListener;import com.markupartist.android.widget.pulltorefresh.R;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;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 RelativeLayout 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 mRefreshOriginalBottomPadding;    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 = (RelativeLayout) mInflater.inflate(                R.layout.pull_to_refresh_header, this, false);        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();        mRefreshOriginalBottomPadding = mRefreshView.getPaddingBottom();        mRefreshState = TAP_TO_REFRESH;//        addHeaderView(mRefreshView);        addFooterView(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(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 (getLastVisiblePosition() == getAdapter().getCount() - 1                        && mRefreshState != REFRESHING) {                    if ((                            mRefreshView.getTop() <= getMeasuredHeight() - mRefreshViewHeight)                            && mRefreshState == RELEASE_TO_REFRESH) {                        // Initiate the refresh                        mRefreshState = REFRESHING;                        prepareForRefresh();                        onRefresh();                    } else if (mRefreshView.getTop() > getMeasuredHeight() - mRefreshViewHeight) {                        // Abort refresh and scroll down below the refresh view                        resetHeader();                        //setSelection(1);                        if (getFooterViewsCount() > 0) {                            setSelectionFromTop(getAdapter().getCount() - 1, (this.getMeasuredHeight()));                        }//                        if (mRefreshState != RELEASE_TO_REFRESH){//                            scrollTo(0, mRefreshView.getScrollY() - mRefreshViewHeight);//                        }                    }                }                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);        }//        Log.i("PullToRefreshListView", "historySize:" + historySize);//        Log.i("PullToRefreshListView", "pointerCount:" + pointerCount);//        Log.i("PullToRefreshListView", "  ");//        Log.i("PullToRefreshListView", "  ");//        Log.i("PullToRefreshListView", "  ");        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(),                            mRefreshView.getPaddingTop(),                            mRefreshView.getPaddingRight(),                            topPadding);                }            }        }    }    /**     * Sets the header padding back to original size.     */    private void resetHeaderPadding() {        mRefreshView.setPadding(                mRefreshView.getPaddingLeft(),                mRefreshView.getPaddingTop(),                mRefreshView.getPaddingRight(),                mRefreshOriginalBottomPadding);    }    /**     * 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) {//        Log.i("PullToRefreshListView", "firstVisibleItem:" + firstVisibleItem);//        Log.i("PullToRefreshListView", "visibleItemCount:" + visibleItemCount);//        Log.i("PullToRefreshListView", "totalItemCount:" + totalItemCount);//        Log.i("PullToRefreshListView", "");//        Log.i("PullToRefreshListView", "");//        Log.i("PullToRefreshListView", "");        // 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 + visibleItemCount == totalItemCount) {                mRefreshViewImage.setVisibility(View.VISIBLE);                if ((                        mRefreshView.getTop() <= getMeasuredHeight() - mRefreshViewHeight)                        && 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.getTop() > getMeasuredHeight() - 20 - mRefreshViewHeight                                && 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                && getLastVisiblePosition() >= getAdapter().getCount() -1                && mRefreshState != REFRESHING) {                if (getFooterViewsCount() > 0) {                    setSelectionFromTop(getAdapter().getCount() - 1, (this.getMeasuredHeight()));                }        }        if (mOnScrollListener != null) {            mOnScrollListener.onScroll(view, firstVisibleItem,                    visibleItemCount, totalItemCount);        }    }    public View getLoadBarView() {        return mRefreshView;    }    @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 [email protected] com.itaoo.view.PullToRefreshListView #onRefreshComplete()} is         * expected to indicate that the refresh has completed.         */        public void onRefresh();    }}
1 楼 zhoujiamail 2011-12-02  
请问一下如果用这种方法实现头部刷新效果,当ListView里的列表项很少时是隐藏不掉的,有什么别的办法可以做到吗
  相关解决方案