Error in pull down to refresh list view android

半城伤御伤魂 提交于 2019-12-06 03:52:27

I would definitely take a look at Chris Banes' implementation of pull-to-refresh. His code does not only include this interaction style for ListView, but also GridView and WebView.

Especially the latter will be of interest in your case, since it's an example implementation of pull-to-refresh for a view that does not use an adapter for its content. If you look at the source code, you'll see that every concrete pull-to-refreh view in Banes' project extends from a generic PullToRefreshBase, which contains most of the logic for animation and refreshing. The benefit of having that base class is that doing the same thing for any other type of view, e.g. a TextView, should be pretty straightforward.

The only drawback of this approach is that the implementation is a wrapper for other views, meaning you'll have write a couple of extra lines to get the actual view. So it's not a full drop-in replacement. However, its functionality and features far exceed that little inconvenience.

EDITED :

Look at the Below Code i have implemented

in your Main JAVA File :

PullToRefreshListView listview;

listview = (PullToRefreshListView) findViewById(R.id.airpost_listView);

    listview.setOnRefreshListener(new OnRefreshListener() {
        public void onRefresh() {
            // TODO Auto-generated method stub
            new GetPost().execute(); // AsyncTask where you can put your  logic when to call the listview for getting new data or let it be same as before
        }
    });

Listview Defined in xml File:

 <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@drawable/bhavesh"
        android:padding="5dp" >

        <com.FlightMate.AirpostTab.PullToRefreshListView
            android:id="@+id/airpost_listView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="#ffffff"
            android:cacheColorHint="@android:color/transparent"
            android:divider="#00000000" />
    </LinearLayout>

Here is PullToRefreshListView :

    package com.FlightMate.AirpostTab;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;

public class PullToRefreshListView extends PullToRefreshBase<ListView> {

    public PullToRefreshListView(Context context) {
        super(context);
    }

    public PullToRefreshListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected final ListView createAdapterView(Context context,
            AttributeSet attrs) {
        ListView lv = new ListView(context, attrs);
        // Set it to this so it can be used in ListActivity/ListFragment

        lv.setId(android.R.id.list);
        return lv;
    }

}

here is PullToRefreshBase :

    package com.FlightMate.AirpostTab;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.LinearLayout;

import com.FlightMate.R;

public abstract class PullToRefreshBase<T extends AbsListView> extends
        LinearLayout implements OnTouchListener, OnScrollListener {

    private final class SmoothScrollRunnable implements Runnable {

        static final int ANIMATION_DURATION_MS = 190;
        static final int ANIMATION_FPS = 1000 / 60;

        private final Interpolator interpolator;
        private final int scrollToY;
        private final int scrollFromY;
        private final Handler handler;

        private boolean continueRunning = true;
        private long startTime = -1;
        private int currentY = -1;

        public SmoothScrollRunnable(Handler handler, int fromY, int toY) {
            this.handler = handler;
            this.scrollFromY = fromY;
            this.scrollToY = toY;
            this.interpolator = new AccelerateDecelerateInterpolator();
        }

        // @Override
        public void run() {

            /**
             * Only set startTime if this is the first time we're starting, else
             * actually calculate the Y delta
             */
            if (startTime == -1) {
                startTime = 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() - startTime))
                        / ANIMATION_DURATION_MS;
                normalizedTime = Math.max(Math.min(normalizedTime, 1000), 0);

                final int deltaY = Math
                        .round((scrollFromY - scrollToY)
                                * interpolator
                                        .getInterpolation(normalizedTime / 1000f));
                this.currentY = scrollFromY - deltaY;
                setHeaderScroll(currentY);
            }

            // If we're not at the target Y, keep going...
            if (continueRunning && scrollToY != currentY) {
                handler.postDelayed(this, ANIMATION_FPS);
            }
        }

        public void stop() {
            this.continueRunning = false;
            this.handler.removeCallbacks(this);
        }
    };

    // ===========================================================
    // Constants
    // ===========================================================

    static final int PULL_TO_REFRESH = 0;
    static final int RELEASE_TO_REFRESH = PULL_TO_REFRESH + 1;
    static final int REFRESHING = RELEASE_TO_REFRESH + 1;
    static final int EVENT_COUNT = 3;

    public static final int MODE_PULL_DOWN_TO_REFRESH = 0x1;
    public static final int MODE_PULL_UP_TO_REFRESH = 0x2;
    public static final int MODE_BOTH = 0x3;

    // ===========================================================
    // Fields
    // ===========================================================

    private int state = PULL_TO_REFRESH;
    private int mode = MODE_PULL_DOWN_TO_REFRESH;
    private int currentMode;
    private boolean disableScrollingWhileRefreshing = true;

    private T adapterView;
    private boolean isPullToRefreshEnabled = true;

    private LoadingLayout headerLayout;
    private LoadingLayout footerLayout;
    private int headerHeight;

    private final Handler handler = new Handler();

    private OnTouchListener onTouchListener;
    private OnRefreshListener onRefreshListener;
    private OnScrollListener onScrollListener;

    private OnLastItemVisibleListener onLastItemVisibleListener;
    private int lastSavedFirstVisibleItem = -1;

    private SmoothScrollRunnable currentSmoothScrollRunnable;

    private float startY = -1;
    private final float[] lastYs = new float[EVENT_COUNT];

    // ===========================================================
    // Constructors
    // ===========================================================

    public PullToRefreshBase(Context context) {
        this(context, null);
    }

    public PullToRefreshBase(Context context, int mode) {
        this(context);
        this.mode = mode;
    }

    public PullToRefreshBase(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    // ===========================================================
    // Getter & Setter
    // ===========================================================

    /**
     * Get the Wrapped AdapterView. Anything returned here has already been
     * added to the content view.
     * 
     * @return The AdapterView which is currently wrapped
     */
    public final T getAdapterView() {
        return adapterView;
    }

    /**
     * Whether Pull-to-Refresh is enabled
     * 
     * @return enabled
     */
    public final boolean isPullToRefreshEnabled() {
        return isPullToRefreshEnabled;
    }

    public void setDisableScrollingWhileRefreshing(
            boolean disableScrollingWhileRefreshing) {
        this.disableScrollingWhileRefreshing = disableScrollingWhileRefreshing;
    }

    /**
     * Mark the current Refresh as complete. Will Reset the UI and hide the
     * Refreshing View
     */
    public final void onRefreshComplete() {
        resetHeader();
    }

    public final void setOnLastItemVisibleListener(
            OnLastItemVisibleListener listener) {
        onLastItemVisibleListener = listener;
    }

    public final void setOnRefreshListener(OnRefreshListener listener) {
        onRefreshListener = listener;
    }

    /**
     * A mutator to enable/disable Pull-to-Refresh for the current AdapterView
     * 
     * @param enable
     *            Whether Pull-To-Refresh should be used
     */
    public final void setPullToRefreshEnabled(boolean enabled) {
        this.isPullToRefreshEnabled = enabled;
    }

    public final void setReleaseLabel(String releaseLabel) {
        if (null != headerLayout) {
            headerLayout.setReleaseLabel(releaseLabel);
        }
        if (null != footerLayout) {
            footerLayout.setReleaseLabel(releaseLabel);
        }
    }

    public final void setPullLabel(String pullLabel) {
        if (null != headerLayout) {
            headerLayout.setPullLabel(pullLabel);
        }
        if (null != footerLayout) {
            footerLayout.setPullLabel(pullLabel);
        }
    }

    public final void setRefreshingLabel(String refreshingLabel) {
        if (null != headerLayout) {
            headerLayout.setRefreshingLabel(refreshingLabel);
        }
        if (null != footerLayout) {
            footerLayout.setRefreshingLabel(refreshingLabel);
        }
    }

    // ===========================================================
    // Methods for/from SuperClass/Interfaces
    // ===========================================================

    public final void setOnScrollListener(OnScrollListener listener) {
        onScrollListener = listener;
    }

    @Override
    public final void setOnTouchListener(OnTouchListener listener) {
        onTouchListener = listener;
    }

    public final void onScroll(final AbsListView view,
            final int firstVisibleItem, final int visibleItemCount,
            final int totalItemCount) {

        if (null != onLastItemVisibleListener) {
            // detect if last item is visible
            if (visibleItemCount > 0 && visibleItemCount < totalItemCount
                    && (firstVisibleItem + visibleItemCount == totalItemCount)) {
                // only process first event
                if (firstVisibleItem != lastSavedFirstVisibleItem) {
                    lastSavedFirstVisibleItem = firstVisibleItem;
                    onLastItemVisibleListener.onLastItemVisible();
                }
            }
        }

        if (null != onScrollListener) {
            onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,
                    totalItemCount);
        }
    }

    public final void onScrollStateChanged(final AbsListView view,
            final int scrollState) {
        if (null != onScrollListener) {
            onScrollListener.onScrollStateChanged(view, scrollState);
        }
    }

    // @Override
    public final boolean onTouch(View view, MotionEvent ev) {
        if (isPullToRefreshEnabled) {
            // Returning true here stops the ListView being scrollable while we
            // refresh
            if (state == REFRESHING && disableScrollingWhileRefreshing) {
                return true;
            } else if (onAdapterViewTouch(view, ev)) {
                return true;
            }
        }

        if (null != onTouchListener) {
            return onTouchListener.onTouch(view, ev);
        }

        return false;
    }

    /**
     * This is implemented by derived classes to return the created AdapterView.
     * If you need to use a custom AdapterView (such as a custom ListView),
     * override this method and return an instance of your custom class.
     * 
     * Be sure to set the ID of the view in this method, especially if you're
     * using a ListActivity or ListFragment.
     * 
     * @param context
     * @param attrs
     *            AttributeSet from wrapped class. Means that anything you
     *            include in the XML layout declaration will be routed to the
     *            AdapterView
     * @return New instance of the AdapterView
     */
    protected abstract T createAdapterView(Context context, AttributeSet attrs);

    // ===========================================================
    // Methods
    // ===========================================================

    protected final void resetHeader() {
        state = PULL_TO_REFRESH;
        initializeYsHistory();
        startY = -1;

        if (null != headerLayout) {
            headerLayout.reset();
        }
        if (null != footerLayout) {
            footerLayout.reset();
        }

        smoothScrollTo(0);
    }

    private void init(Context context, AttributeSet attrs) {

        setOrientation(LinearLayout.VERTICAL);

        // Styleables from XML
        final TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.PullToRefresh);
        mode = a.getInteger(R.styleable.PullToRefresh_mode,
                MODE_PULL_DOWN_TO_REFRESH);

        // AdapterView
        // By passing the attrs, we can add ListView/GridView params via XML
        adapterView = this.createAdapterView(context, attrs);
        adapterView.setOnTouchListener(this);
        adapterView.setOnScrollListener(this);
        addView(adapterView, new LinearLayout.LayoutParams(
                LayoutParams.FILL_PARENT, 0, 1.0f));

        // Loading View Strings
        String pullLabel = context
                .getString(R.string.pull_to_refresh_pull_label);
        String refreshingLabel = context
                .getString(R.string.pull_to_refresh_refreshing_label);
        String releaseLabel = context
                .getString(R.string.pull_to_refresh_release_label);

        // Add Loading Views
        if (mode == MODE_PULL_DOWN_TO_REFRESH || mode == MODE_BOTH) {
            headerLayout = new LoadingLayout(context,
                    MODE_PULL_DOWN_TO_REFRESH, releaseLabel, pullLabel,
                    refreshingLabel);
            addView(headerLayout, 0, new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.FILL_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT));
            measureView(headerLayout);
            headerHeight = headerLayout.getMeasuredHeight();
        }
        if (mode == MODE_PULL_UP_TO_REFRESH || mode == MODE_BOTH) {
            footerLayout = new LoadingLayout(context, MODE_PULL_UP_TO_REFRESH,
                    releaseLabel, pullLabel, refreshingLabel);
            addView(footerLayout, new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.FILL_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT));
            measureView(footerLayout);
            headerHeight = footerLayout.getMeasuredHeight();
        }

        // Styleables from XML
        if (a.hasValue(R.styleable.PullToRefresh_headerTextColor)) {
            final int color = a.getColor(
                    R.styleable.PullToRefresh_headerTextColor, Color.BLACK);
            if (null != headerLayout) {
                headerLayout.setTextColor(color);
            }
            if (null != footerLayout) {
                footerLayout.setTextColor(color);
            }
        }
        if (a.hasValue(R.styleable.PullToRefresh_headerBackground)) {
            this.setBackgroundResource(a.getResourceId(
                    R.styleable.PullToRefresh_headerBackground, Color.WHITE));
        }
        if (a.hasValue(R.styleable.PullToRefresh_adapterViewBackground)) {
            adapterView.setBackgroundResource(a.getResourceId(
                    R.styleable.PullToRefresh_adapterViewBackground,
                    Color.WHITE));
        }
        a.recycle();

        // Hide Loading Views
        switch (mode) {
        case MODE_BOTH:
            setPadding(getPaddingLeft(), -headerHeight, getPaddingRight(),
                    -headerHeight);
            break;
        case MODE_PULL_UP_TO_REFRESH:
            setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
                    -headerHeight);
            break;
        case MODE_PULL_DOWN_TO_REFRESH:
        default:
            setPadding(getPaddingLeft(), -headerHeight, getPaddingRight(),
                    getPaddingBottom());
            break;
        }

        // If we're not using MODE_BOTH, then just set currentMode to current
        // mode
        if (mode != MODE_BOTH) {
            currentMode = mode;
        }
    }

    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);
    }

    private boolean onAdapterViewTouch(View view, MotionEvent event) {

        switch (event.getAction()) {
        case MotionEvent.ACTION_MOVE:
            updateEventStates(event);

            if (isPullingToRefresh() && startY == -1) {
                startY = event.getY();

                // Need to set current Mode if we're using both
                if (mode == MODE_BOTH) {
                    if (isUserDraggingDownwards()) {
                        currentMode = MODE_PULL_DOWN_TO_REFRESH;
                    } else if (isUserDraggingUpwards()) {
                        currentMode = MODE_PULL_UP_TO_REFRESH;
                    }
                }
                return false;
            }

            if (startY != -1 && !adapterView.isPressed()) {
                pullEvent(event, startY);
                return true;
            }
            break;
        case MotionEvent.ACTION_UP:
            initializeYsHistory();
            startY = -1;

            if (state == RELEASE_TO_REFRESH) {
                setRefreshing();
                if (onRefreshListener != null) {
                    onRefreshListener.onRefresh();
                }
            } else {
                smoothScrollTo(0);
            }
            break;
        }

        return false;
    }

    private void pullEvent(MotionEvent event, float firstY) {
        float averageY = average(lastYs);

        final int height;
        switch (currentMode) {
        case MODE_PULL_UP_TO_REFRESH:
            height = (int) Math.max(firstY - averageY, 0);
            setHeaderScroll(height);
            break;
        case MODE_PULL_DOWN_TO_REFRESH:
        default:
            height = (int) Math.max(averageY - firstY, 0);
            setHeaderScroll(-height);
            break;
        }

        if (state == PULL_TO_REFRESH && headerHeight < height) {
            state = RELEASE_TO_REFRESH;
            if (null != headerLayout) {
                headerLayout.releaseToRefresh();
            }
            if (null != footerLayout) {
                footerLayout.releaseToRefresh();
            }
        } else if (state == RELEASE_TO_REFRESH && headerHeight >= height) {
            state = PULL_TO_REFRESH;
            if (null != headerLayout) {
                headerLayout.pullToRefresh();
            }
            if (null != footerLayout) {
                footerLayout.pullToRefresh();
            }
        }
    }

    private void setHeaderScroll(int y) {
        scrollTo(0, y);
    }

    private void setRefreshing() {
        state = REFRESHING;
        if (null != headerLayout) {
            headerLayout.refreshing();
        }
        if (null != footerLayout) {
            footerLayout.refreshing();
        }

        switch (currentMode) {
        case MODE_PULL_DOWN_TO_REFRESH:
            smoothScrollTo(-headerHeight);
            break;
        case MODE_PULL_UP_TO_REFRESH:
            smoothScrollTo(headerHeight);
            break;
        }
    }

    private float average(float[] ysArray) {
        float avg = 0;
        for (int i = 0; i < EVENT_COUNT; i++) {
            avg += ysArray[i];
        }
        return avg / EVENT_COUNT;
    }

    private void initializeYsHistory() {
        for (int i = 0; i < EVENT_COUNT; i++) {
            lastYs[i] = 0;
        }
    }

    private void updateEventStates(MotionEvent event) {
        for (int i = 0, z = event.getHistorySize(); i < z; i++) {
            this.updateEventStates(event.getHistoricalY(i));
        }

        this.updateEventStates(event.getY());
    }

    private void updateEventStates(float y) {
        for (int i = 0; i < EVENT_COUNT - 1; i++) {
            lastYs[i] = lastYs[i + 1];
        }

        lastYs[EVENT_COUNT - 1] = y;
    }

    private boolean isPullingToRefresh() {
        if (isPullToRefreshEnabled && state != REFRESHING) {
            switch (mode) {
            case MODE_PULL_DOWN_TO_REFRESH:
                return isFirstItemVisible() && isUserDraggingDownwards();
            case MODE_PULL_UP_TO_REFRESH:
                return isLastItemVisible() && isUserDraggingUpwards();
            case MODE_BOTH:
                return (isFirstItemVisible() && isUserDraggingDownwards())
                        || (isLastItemVisible() && isUserDraggingUpwards());
            }
        }
        return false;
    }

    private boolean isFirstItemVisible() {
        if (this.adapterView.getCount() == 0) {
            return true;
        } else if (adapterView.getFirstVisiblePosition() == 0) {
            return adapterView.getChildAt(0).getTop() >= adapterView.getTop();
        } else {
            return false;
        }
    }

    private boolean isLastItemVisible() {
        final int count = this.adapterView.getCount();
        if (count == 0) {
            return true;
        } else if (adapterView.getLastVisiblePosition() == count - 1) {
            return true;
        } else {
            return false;
        }
    }

    private boolean isUserDraggingDownwards() {
        return this.isUserDraggingDownwards(0, EVENT_COUNT - 1);
    }

    private boolean isUserDraggingDownwards(int from, int to) {
        return lastYs[from] != 0 && lastYs[to] != 0
                && Math.abs(lastYs[from] - lastYs[to]) > 10
                && lastYs[from] < lastYs[to];
    }

    private boolean isUserDraggingUpwards() {
        return this.isUserDraggingUpwards(0, EVENT_COUNT - 1);
    }

    private boolean isUserDraggingUpwards(int from, int to) {
        return lastYs[from] != 0 && lastYs[to] != 0
                && Math.abs(lastYs[to] - lastYs[from]) > 10
                && lastYs[to] < lastYs[from];
    }

    private void smoothScrollTo(int y) {
        if (null != currentSmoothScrollRunnable) {
            currentSmoothScrollRunnable.stop();
        }

        this.currentSmoothScrollRunnable = new SmoothScrollRunnable(handler,
                getScrollY(), y);
        handler.post(currentSmoothScrollRunnable);
    }

    // ===========================================================
    // Inner and Anonymous Classes
    // ===========================================================

    public static interface OnRefreshListener {

        public void onRefresh();

    }

    public static interface OnLastItemVisibleListener {

        public void onLastItemVisible();

    }

}

Hope it will Help you out from your Problem. let me know if you are still finding any difficulties.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!