2012-12-13 30 views
3

我使用的功能,下拉使用這個library chrisbanes 的刷新但當我試圖在我的XML文件中導入這個小部件 它顯示我以下error.Please幫助我如何解決這個問題。 錯誤:錯誤下拉刷新列表視圖的Android

​​
+0

發佈您的相關代碼:) – AndroidLearner

+0

發佈您的代碼。 – yokees

+2

我解決了我的問題。謝謝你的幫助。 – Priya

回答

1

我肯定會看看Chris Banes' implementation of pull-to-refresh。他的代碼不僅包括ListView的這種交互風格,還包括GridView和WebView。

特別是後者會對您的案例感興趣,因爲它是不使用內容適配器的視圖的拉到刷新示例實現。如果你看看源代碼,你會發現Banes的項目中每個具體的pull-to-refreh視圖都是從一個普通的PullToRefreshBase擴展而來的,它包含了大部分動畫和刷新邏輯。擁有這個基類的好處是對任何其他類型的視圖都做同樣的事情,例如一個TextView,應該非常簡單。

這種方法的唯一缺點是該實現是其他視圖的包裝,這意味着您需要編寫一些額外的行來獲取實際視圖。所以它不是一個完整的替代品。但是,其功能和功能遠遠超過了這種小小的不便。

編輯:

看看下面的代碼,我對你的主要的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 
     } 
    }); 

列表視圖在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> 

這裏是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; 
    } 

} 

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

    } 

} 

希望這將有助於你從你的問題了。讓我知道你是否仍然發現任何困難。