Pull to refresh in Android without popular library

前端 未结 1 631
生来不讨喜
生来不讨喜 2021-01-31 22:59

I want to implement pull-to-refresh in Android app, but I don\'t want to use pull-to-refresh library which is available on the internet because it is too slow for the gridView I

相关标签:
1条回答
  • 2021-01-31 23:40

    PullRefreshContainerView.java

    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.LinearLayout;
    import android.widget.ListView;
    import android.widget.TextView;
    
    /**
     * A container for a ListView that can be pulled to refresh.
     * This will create a ListView and refresh header automatically, but you can
     * customize them by using {@link #setList(ListView)} and {@link #setRefreshHeader(View, int)}
     * <p>
     * To use, put this where you would normally put your ListView. Since this does not extend
     * ListView, you must use {@link #getList()} to modify the list or provide your own.
     * <p>
     * To get the actions of the list, use a {@link OnChangeStateListener} with {@link #setOnChangeStateListener(OnChangeStateListener)}.
     * If you want to change how the refresh header looks, you should do it during these state changes.   
     */
    public class PullRefreshContainerView extends LinearLayout {    
        /**
         * Interface for listening to when the refresh container changes state.
         */
        public interface OnChangeStateListener {
            /**
             * Notifies a listener when the refresh view's state changes.
             * @param container The container that contains the header
             * @param state The state of the header. May be STATE_IDLE, STATE_READY,
             *      or STATE_REFRESHING.
             */
            public void onChangeState(PullRefreshContainerView container, int state);
        }
    
        /**
         * State of the refresh header when it is doing nothing or being pulled down slightly.
         */
        public static final int STATE_IDLE = 0;
    
        /**
         * State of the refresh header when it has been pulled down but not enough to start refreshing, and
         * has not yet been released.
         */
        public static final int STATE_PULL = 1;
    
        /**
         * State of the refresh header when it has been pulled down enough to start refreshing, but
         * has not yet been released.
         */
        public static final int STATE_RELEASE = 2;
    
        /**
         * State of the refresh header when the list should be refreshing.
         */
        public static final int STATE_LOADING = 3;
    
        private LinearLayout mHeaderContainer;
        private View mHeaderView;
        private ListView mList;
        private int mState;
        private OnChangeStateListener mOnChangeStateListener;
    
        private int REFRESH_VIEW_HEIGHT = 60;
    
        /**
         * Creates a new pull to refresh container.
         * 
         * @param context the application context
         */
        public PullRefreshContainerView(Context context) {
            super(context);
            init(context);
        }
    
        /**
         * Creates a new pull to refresh container.
         * 
         * @param context the application context
         * @param attrs the XML attribute set
         */
        public PullRefreshContainerView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        /**
         * Creates a new pull to refresh container.
         * 
         * @param context the application context
         * @param attrs the XML attribute set
         * @param defStyle the style for this view
         */
        public PullRefreshContainerView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs);
            init(context);
        }
    
        private void init(Context context) {
            mState = STATE_IDLE; // Start out as idle.
    
            float densityFactor = context.getResources().getDisplayMetrics().density;
            REFRESH_VIEW_HEIGHT *= densityFactor;
    
            // We don't want to see the fading edge on the container.
            setVerticalFadingEdgeEnabled(false);
            setVerticalScrollBarEnabled(false);
    
            setOrientation(LinearLayout.VERTICAL);
    
            // Set the default list and header.
            mHeaderContainer = new LinearLayout(context);
            addView(mHeaderContainer);
            setRefreshViewHeight(1);
    
            TextView headerView = new TextView(context);
            headerView.setText("Default refresh header.");
            setRefreshHeader(headerView);
    
            ListView list = new ListView(context);
            setList(list);
        }
    
        private boolean mScrollingList = true;
        private float mInterceptY;
        private int mLastMotionY;
    
        @Override
        public boolean dispatchTouchEvent (MotionEvent ev) {
            float oldLastY = mInterceptY;
            mInterceptY = ev.getY();
    
            if (mState == STATE_LOADING) {
                return super.dispatchTouchEvent(ev);
            }
    
            switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastMotionY = (int) ev.getY();
                mScrollingList = true;
                return super.dispatchTouchEvent(ev);
    
            case MotionEvent.ACTION_MOVE:
                if (mList.getFirstVisiblePosition() == 0
                        && (mList.getChildCount() == 0 || mList.getChildAt(0).getTop() == 0)) {
                    if ((mInterceptY - oldLastY > 5) || (mState == STATE_PULL) || (mState == STATE_RELEASE)) {
                        mScrollingList = false;
                        applyHeaderHeight(ev);
                        return true;
                    } else {
                        mScrollingList = true;
                        return super.dispatchTouchEvent(ev);
                    }
                } else if (mScrollingList) {
                    return super.dispatchTouchEvent(ev);
                } else {
                    return super.dispatchTouchEvent(ev);
                }
    
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (mState == STATE_RELEASE) {
                    refresh();
                } else {
                    changeState(STATE_IDLE);
                }
    
                if (mScrollingList) {
                    return super.dispatchTouchEvent(ev);
                } else {
                    return true;
                }
    
            default:
                return super.dispatchTouchEvent(ev);
            }
        }
    
        private void applyHeaderHeight(MotionEvent ev) {
            final int historySize = ev.getHistorySize();
    
            if (historySize > 0) {
                for (int h = 0; h < historySize; h++) {
                    int historicalY = (int) (ev.getHistoricalY(h));
                    updateRefreshView(historicalY - mLastMotionY);
                }
            } else {
                int historicalY = (int) ev.getY();
                updateRefreshView(historicalY - mLastMotionY);
            }
        }
    
        private void updateRefreshView(int height) {
            if (height <= 0) {
                return;
            }
    
            if ((REFRESH_VIEW_HEIGHT/4 <= mCurRefreshViewHeight) && (mCurRefreshViewHeight < REFRESH_VIEW_HEIGHT)) {
                setRefreshViewHeight(height);
                changeState(STATE_PULL);
            } else if (mCurRefreshViewHeight >= REFRESH_VIEW_HEIGHT) {
                if (height > REFRESH_VIEW_HEIGHT) {
                    height = (int) (REFRESH_VIEW_HEIGHT + (height - REFRESH_VIEW_HEIGHT) *  REFRESH_VIEW_HEIGHT * 1.0f/height);
                }
    
                setRefreshViewHeight(height);
                changeState(STATE_RELEASE);
            } else {
                setRefreshViewHeight(height);
            }
        }
    
        private int mCurRefreshViewHeight = 60;
        private void setRefreshViewHeight(int height) {
            if (mCurRefreshViewHeight == height) {
                return;
            }
    
            if (height == 1) {
                mHeaderContainer.setLayoutParams(new LayoutParams(1, 1));
            } else {
                mHeaderContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, height));
            }
            mCurRefreshViewHeight = height;
        }
    
        private void changeState(int state) {
            switch (state) {
            case STATE_IDLE:
                setRefreshViewHeight(1);
                break;
            case STATE_PULL:
                break;
            case STATE_RELEASE:
                break;
            case STATE_LOADING:
                setRefreshViewHeight(REFRESH_VIEW_HEIGHT);
                break;
            }
    
            mState = state;
    
            notifyStateChanged();
        }
    
        /**
         * Sets the list to be used in this pull to refresh container.
         * @param list the list to use
         */
        public void setList(ListView list) {
            if (mList != null) {
                removeView(mList);
            }
            mList = list;
            if (mList.getParent() != null) {
                ViewGroup parent = (ViewGroup) mList.getParent();
                parent.removeView(mList);
            }
    
            mList.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
            addView(mList);
        }
    
        /**
         * @return the list inside this pull to refresh container
         */
        public ListView getList() {
            return mList;
        }
    
        /**
         * Sets the view to use as the refresh header. 
         * <p />
         * The header view is the view at the top that will show while the list
         * is refreshing. Usually, this will be a simple rectangle that says "refreshing" and the like.
         * <p />
         * 
         * @param headerView the view to use as the whole header.
         */
        public void setRefreshHeader(View header) {
            if (mHeaderView != null) {
                mHeaderContainer.removeView(mHeaderView);
            }       
    
            if (header == null) {
                throw new RuntimeException("Please supply a non-null header container.");
            }
    
            mHeaderContainer.addView(header, 0);
            mHeaderView = header;
        }
    
        public void refresh() { 
            changeState(STATE_LOADING);         
        }
    
        /**
         * Notifies the pull-to-refresh view that the refreshing is complete.
         * This will hide the refreshing header.
         */
        public void completeRefresh() {
            changeState(STATE_IDLE);
        }
    
        /**
         * Notifies the listener that the state has changed.
         */
        private void notifyStateChanged() {
            if (mOnChangeStateListener != null) {
                mOnChangeStateListener.onChangeState(this, mState);
            }
        }
    
        /**
         * @param listener the listener to be notified when the header state should change
         */
        public void setOnChangeStateListener(OnChangeStateListener listener) {
            mOnChangeStateListener = listener;
        }
    }
    

    How To use UsageDemoActivity.java

    import java.util.ArrayList;
    import java.util.Timer;
    import java.util.TimerTask;
    
    import com.dmobile.pulltorefresh.PullRefreshContainerView.OnChangeStateListener;
    import com.dmobile.pulltorefresh.R;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.Gravity;
    import android.view.ViewGroup.LayoutParams;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    import android.widget.TextView;
    
    public class UsageDemoActivity extends Activity {
    
        private PullRefreshContainerView mContainerView;
        private TextView mRefreshHeader;
        private ListView mList;
    
        private ArrayList<String> mStrings = new ArrayList<String>();
        private ArrayAdapter<String> mAdapter;
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            mRefreshHeader = new TextView(this);
            mRefreshHeader.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
            mRefreshHeader.setGravity(Gravity.CENTER);
            mRefreshHeader.setText("Pull to refresh...");
    
            mContainerView = (PullRefreshContainerView) findViewById(R.id.container);
            mContainerView.setRefreshHeader(mRefreshHeader);
    
            mContainerView.setOnChangeStateListener(new OnChangeStateListener() {
                @Override
                public void onChangeState(PullRefreshContainerView container, int state) {
                    switch (state) {
                    case PullRefreshContainerView.STATE_IDLE:
                    case PullRefreshContainerView.STATE_PULL:
                        mRefreshHeader.setText("Pull to refresh...");
                        break;
                    case PullRefreshContainerView.STATE_RELEASE:
                        mRefreshHeader.setText("Release to refresh...");
                        break;
                    case PullRefreshContainerView.STATE_LOADING:
                        mRefreshHeader.setText("Loading...");
    
                        final Timer t = new Timer();
                        t.schedule(new TimerTask() {
    
                            @Override
                            public void run() {
                                UsageDemoActivity.this.runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
    
                                        addStrings(1);
                                        mContainerView.completeRefresh();
                                        t.cancel();
                                    }
                                });
                            }
                        }, 5000, 5000);
    
                        break;
                    }
                }
            });
    
            mList = mContainerView.getList();
            mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings);
            mList.setAdapter(mAdapter);
    
            addStrings(3);
        }
    
        private void addStrings(int count) {
            int curSize = mStrings.size();
            for (int i = 0; i < count; ++i) {
                mStrings.add("String " + (curSize + i));
            }
    
            mAdapter.notifyDataSetChanged();
        }
    }
    

    main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
    
        <com.dmobile.pulltorefresh.PullRefreshContainerView
            android:id="@+id/container"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"/>
    
    </LinearLayout>
    

    UPDATE TO WORK WITH GRIDVIEW PullRefreshContainerView.java

    private void init(Context context) {
            mState = STATE_IDLE; // Start out as idle.
    
        float densityFactor = context.getResources().getDisplayMetrics().density;
        REFRESH_VIEW_HEIGHT *= densityFactor;
    
        // We don't want to see the fading edge on the container.
        setVerticalFadingEdgeEnabled(false);
        setVerticalScrollBarEnabled(false);
    
        setOrientation(LinearLayout.VERTICAL);
    
        // Set the default list and header.
        mHeaderContainer = new LinearLayout(context);
        addView(mHeaderContainer);
        setRefreshViewHeight(1);
    
        TextView headerView = new TextView(context);
        headerView.setText("Default refresh header.");
        setRefreshHeader(headerView);
    
        GridView grid = new GridView(context);
        setList(grid);
    }
    

    And also make related change in setListMethod();

    0 讨论(0)
提交回复
热议问题