如何在pull中仅加载新项目以刷新自定义列表视图?

Bal*_*lai 4 android android-listview

我只需要在拉动时加载新项目以刷新,剩余加载的项目应在加载新项目后向下移动.我正在装载10,10件物品再加载如果我拉动刷新我希望所有装载的物品在最新的更新项目.

怎么做?

((PullAndLoadListView)getListView()).setOnRefreshListener(new OnRefreshListener(){public void onRefresh(){}}
Run Code Online (Sandbox Code Playgroud)

Bha*_*iya 6

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.

这种方法的唯一缺点是实现是其他视图的包装器,这意味着您将编写几个额外的行来获取实际视图.所以这不是一个完全的替代品.但是,它的功能和特性远远超过了那么一点不便.

编辑:

看看我已实施的下面的代码

在您的主JAVA文件中:

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
        }
    });
Run Code Online (Sandbox Code Playgroud)

Listview在xml文件中定义:

 <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>
Run Code Online (Sandbox Code Playgroud)

这是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;
    }

}
Run Code Online (Sandbox Code Playgroud)

这是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();

    }

}
Run Code Online (Sandbox Code Playgroud)

希望它能帮助你摆脱困境.如果您仍然遇到任何困难,请告诉我.