2013-09-04 11 views
8

Chcę zaimplementować odświeżanie w aplikacji na Androida, ale nie chcę używać biblioteki odciągania do odświeżania, która jest dostępna w Internecie, ponieważ jest zbyt wolna dla gridView, którego używam. Więc chcę ją wdrożyć ręcznie, czy wiesz, jak to zrobić? Lub z których metod powinienem korzystać z GridView?Pociągnij, aby odświeżyć w Androidzie bez popularnej biblioteki

+0

Jestem Pociągnąć do odświeżania kontenera widok, który jest tworzony przez rozszerzenie LinearLa yout. Działa dobrze z listview można modyfikować, jak chcesz. –

+2

Mam na myśli, że mam CustomLinearLayout, który jest w stanie dać funkcjonalność pull-to-referesh każdemu widokowi. Możesz umieścić dowolny widok w customLinerlayout i będzie on miał funkcję pull-to-referh. –

Odpowiedz

13

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

Jak korzystać 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 DO PRACY Z 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); 
} 

A także powiązany ze zmianami wsetListMethod();

+0

Potrzebuję małej pomocy, czy wiesz, co zmienić, aby pracować z GridView? Udało mi się tylko częściowo pracować z GridView zmieniając ListView na GridView –

+0

Czy masz pojęcie, jak poprawić wydajność tego? Ponieważ jest dość powolny na moim sgs2. I dziękuję za edycję. –

+0

Witaj Biraj, dzięki za wspaniałe ans, działało to również w moim projekcie. Chcę użyć tego GridView, ale chcę go ściągnąć od dołu ... czy to możliwe? –