下拉到刷新列表视图android时出错

我正在使用这个function下拉刷新使用这个chrisbanes 库但是当我尝试在我的xml文件中导入这个小部件时它向我显示以下错误。请帮我解决这个问题。 错误:

com.handmark.pulltorefresh.library.PullToRefreshListView failed to instantiate. 

我肯定会看看Chris Banes实现的pull-to-refresh 。 他的代码不仅包括ListView的这种交互风格,还包括GridView和WebView。

特别是后者将在您的情况下感兴趣,因为它是对于不对其内容使用适配器的视图的pull-to-refresh的示例实现。 如果你看一下源代码,你会发现Banes项目中每个具体的pull-to-refreh视图都是从一个普通的PullToRefreshBase扩展而来的,它包含了动画和刷新的大部分逻辑。 拥有该基类的好处是,对任何其他类型的视图(例如TextView)执行相同的操作应该非常简单。

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

编辑:

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

在您的主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 } }); 

Listview在xml文件中定义:

     

这是PullToRefreshListView:

  package com.FlightMate.AirpostTab; import android.content.Context; import android.util.AttributeSet; import android.widget.ListView; public class PullToRefreshListView extends PullToRefreshBase { 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; } } 

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

希望它能帮助你解决问题。 如果你仍然发现任何困难,请告诉我。