2013-09-04 33 views
8

Tôi muốn triển khai tính năng kéo làm mới trong ứng dụng Android, nhưng tôi không muốn sử dụng thư viện kéo để làm mới có sẵn trên internet vì nó quá chậm GridView Tôi đang sử dụng. Vì vậy, tôi muốn thực hiện nó bằng tay, bạn có biết làm thế nào để làm điều này? Hoặc tôi nên sử dụng phương pháp nào từ GridView?Kéo để làm mới trong Android mà không có thư viện phổ biến

+0

Tôi Kéo-to-refresh chứa chế độ xem được tạo bằng cách mở rộng LinearLa bạn. Nó hoạt động tốt với listview bạn có thể sửa đổi theo ý muốn. –

+2

Tôi muốn nói rằng tôi có một CustomLinearLayout có khả năng cung cấp chức năng pull-to-referesh cho bất kỳ khung nhìn nào. tức là bạn có thể đặt bất kỳ chế độ xem nào trong customLinerlayout và nó sẽ có chức năng pull-to-refersh. –

Trả lời

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

Làm thế nào để sử dụng 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> 

CẬP NHẬT để làm việc với 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); 
} 

Và cũng thực hiện thay đổi có liên quan trongsetListMethod();

+0

Tôi cần một chút trợ giúp, bạn có biết những gì cần thay đổi để làm việc với GridView không? Tôi quản lý chỉ để làm việc một phần GridView bằng cách thay đổi ListView để GridView –

+0

Do u có bất kỳ ý tưởng làm thế nào để cải thiện hiệu suất này? Bởi vì nó khá chậm trên sgs2 của tôi. Và cảm ơn bạn đã chỉnh sửa. –

+0

Hi Biraj, cảm ơn vì ans tuyệt vời, nó đã làm việc trong dự án của tôi quá .. Tôi muốn sử dụng GridView này nhưng muốn kéo nó từ phía dưới .. là nó có thể.? –

Các vấn đề liên quan