GridView基于pulltorefresh实现下拉刷新 上拉加载更多功能(推荐)

原理和listview一样 ,都是重写Android原生控件

Activity

package com.example.refreshgridview; 
import java.util.ArrayList; 
import java.util.List; 
import android.app.Activity; 
import android.os.Bundle; 
import android.widget.GridView; 
import android.widget.Toast; 
import com.example.refreshgridview.PullToRefreshBase.OnRefreshListener; 
public class MainActivity extends Activity { 
private PullToRefreshGridView mPullRefreshGridView; 
private GridView mGridView; 
private GridViewAdapter adapter; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 
mPullRefreshGridView = (PullToRefreshGridView) findViewById(R.id.video_gridView); 
mPullRefreshGridView.init(PullToRefreshGridView.MODE_BOTH); 
mGridView = mPullRefreshGridView.getRefreshableView(); 
mPullRefreshGridView.setOnRefreshListener(refreshListener); 
List list = new ArrayList(); 
for (int i = 0; i < 40; i++) { 
list.add(i+""); 
} 
adapter = new GridViewAdapter(MainActivity.this,list); 
mGridView.setAdapter(adapter); 
} 
private OnRefreshListener refreshListener = new OnRefreshListener() { 
@Override 
public void onRefresh(int mode) { 
if (PullToRefreshGridView.MODE_PULL_DOWN_TO_REFRESH == mPullRefreshGridView.getCurrentMode()) { 
Toast.makeText(MainActivity.this, "下拉刷新", Toast.LENGTH_SHORT).show(); 
mPullRefreshGridView.onRefreshComplete(); 
} else if (mode == PullToRefreshGridView.MODE_PULL_UP_TO_REFRESH) { 
// 加载更多 
Toast.makeText(MainActivity.this, "上拉加载更多", Toast.LENGTH_SHORT).show(); 
mPullRefreshGridView.onRefreshComplete(); 
} 
} 
}; 
}

adapter

package com.example.refreshgridview; 
import java.util.ArrayList; 
import java.util.List; 
import android.content.Context; 
import android.content.Intent; 
import android.text.TextUtils; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.BaseAdapter; 
import android.widget.TextView; 
public class GridViewAdapter extends BaseAdapter { 
private List mList = new ArrayList(); 
private Context mContext; 
public GridViewAdapter(Context context,List list) { 
super(); 
this.mContext = context; 
this.mList = list; 
} 
@Override 
public int getCount() { 
return mList.size(); 
} 
@Override 
public String getItem(int position) { 
return mList.get(position); 
} 
@Override 
public long getItemId(int position) { 
return position; 
} 
@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
ChildHolderOne holder; 
if (convertView == null) { 
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_grid_live_show, parent, false); 
holder = new ChildHolderOne(); 
holder.tvTitle = (TextView)convertView.findViewById(R.id.title_tv); 
convertView.setTag(holder); 
} else { 
holder = (ChildHolderOne) convertView.getTag(); 
} 
return convertView; 
} 
class ChildHolderOne { 
TextView tvTitle; 
} 
}

PullToRefreshGridView

package com.example.refreshgridview; 
import android.content.Context; 
import android.util.AttributeSet; 
import android.view.ContextMenu.ContextMenuInfo; 
import android.view.View; 
import android.widget.GridView; 
public class PullToRefreshGridView extends PullToRefreshAdapterViewBase { 
class InternalGridView extends GridView implements EmptyViewMethodAccessor { 
public InternalGridView(Context context, AttributeSet attrs) { 
super(context, attrs); 
} 
@Override 
public void setEmptyView(View emptyView) { 
PullToRefreshGridView.this.setEmptyView(emptyView); 
} 
@Override 
public void setEmptyViewInternal(View emptyView) { 
super.setEmptyView(emptyView); 
} 
@Override 
public ContextMenuInfo getContextMenuInfo() { 
return super.getContextMenuInfo(); 
} 
} 
public PullToRefreshGridView(Context context) { 
super(context); 
} 
public PullToRefreshGridView(Context context, int mode) { 
super(context, mode); 
} 
public PullToRefreshGridView(Context context, AttributeSet attrs) { 
super(context, attrs); 
} 
@Override 
protected final GridView createRefreshableView(Context context, AttributeSet attrs) { 
GridView gv = new InternalGridView(context, attrs); 
// Use Generated ID (from res/values/ids.xml) 
gv.setId(R.id.gridview); 
return gv; 
} 
@Override 
public ContextMenuInfo getContextMenuInfo() { 
return ((InternalGridView) getRefreshableView()).getContextMenuInfo(); 
} 
}

PullToRefreshBase

package com.example.refreshgridview; 
import android.content.Context; 
import android.os.Handler; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.ViewConfiguration; 
import android.view.ViewGroup; 
import android.view.animation.AccelerateDecelerateInterpolator; 
import android.view.animation.Interpolator; 
import android.widget.LinearLayout; 
import android.widget.TextView; 
/** 
* 
* @author zlw 
*/ 
public abstract class PullToRefreshBase extends LinearLayout { 
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 float FRICTION = 2.0f; 
static final int PULL_TO_REFRESH = 0x0; 
static final int RELEASE_TO_REFRESH = 0x1; 
static final int REFRESHING = 0x2; 
static final int MANUAL_REFRESHING = 0x3; 
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 touchSlop; 
private float initialMotionY; 
private float lastMotionX; 
private float lastMotionY; 
private boolean isBeingDragged = false; 
private int state = PULL_TO_REFRESH; 
private int mode = MODE_PULL_UP_TO_REFRESH; 
private int currentMode; 
private boolean disableScrollingWhileRefreshing = true; 
T refreshableView; 
private boolean isPullToRefreshEnabled = true; 
private LoadingLayout headerLayout; 
private LoadingLayout footerLayout; 
private int headerHeight; 
private final Handler handler = new Handler(); 
private OnRefreshListener onRefreshListener; 
private SmoothScrollRunnable currentSmoothScrollRunnable; 
// =========================================================== 
// Constructors 
// =========================================================== 
public PullToRefreshBase(Context context) { 
super(context); 
init(context, null); 
} 
public PullToRefreshBase(Context context, int mode) { 
super(context); 
this.mode = mode; 
init(context, null); 
} 
public PullToRefreshBase(Context context, AttributeSet attrs) { 
super(context, attrs); 
init(context, attrs); 
} 
// =========================================================== 
// Getter & Setter 
// =========================================================== 
/** 
* Deprecated. Use {@link #getRefreshableView()} from now on. 
* 
* @deprecated 
* @return The Refreshable View which is currently wrapped 
*/ 
public final T getAdapterView() { 
return refreshableView; 
} 
/** 
* Get the Wrapped Refreshable View. Anything returned here has already been 
* added to the content view. 
* 
* @return The View which is currently wrapped 
*/ 
public final T getRefreshableView() { 
return refreshableView; 
} 
/** 
* Whether Pull-to-Refresh is enabled 
* 
* @return enabled 
*/ 
public final boolean isPullToRefreshEnabled() { 
return isPullToRefreshEnabled; 
} 
/** 
* Returns whether the widget has disabled scrolling on the Refreshable View 
* while refreshing. 
* 
* @return true if the widget has disabled scrolling while refreshing 
*/ 
public final boolean isDisableScrollingWhileRefreshing() { 
return disableScrollingWhileRefreshing; 
} 
/** 
* Returns whether the Widget is currently in the Refreshing state 
* 
* @return true if the Widget is currently refreshing 
*/ 
public final boolean isRefreshing() { 
return state == REFRESHING || state == MANUAL_REFRESHING; 
} 
/** 
* By default the Widget disabled scrolling on the Refreshable View while 
* refreshing. This method can change this behaviour. 
* 
* @param disableScrollingWhileRefreshing 
* - true if you want to disable scrolling while refreshing 
*/ 
public final 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() { 
if (state != PULL_TO_REFRESH) { 
resetHeader(); 
if (onShowLayoutListener != null) { 
onShowLayoutListener.onDismiss(); 
} 
} 
} 
/** 
* Set OnRefreshListener for the Widget 
* 
* @param listener 
* - Listener to be used when the Widget is set to Refresh 
*/ 
public final void setOnRefreshListener(OnRefreshListener listener) { 
onRefreshListener = listener; 
} 
/** 
* auto load headerLayout to refresh 
* 
* @param listener 
*/ 
public final void setFirstAutoPullUpToRefresh(OnRefreshListener listener) { 
setRefreshingInternal(true, MODE_PULL_DOWN_TO_REFRESH); 
listener.onRefresh(MODE_PULL_DOWN_TO_REFRESH); 
} 
/** 
* set refreshLable , default use null 
* 
* @param pullLabel 
* @param releaseLabel 
* @param refreshingLabel 
*/ 
public void setRefreshLabel(String pullLabel, String releaseLabel, 
String refreshingLabel) { 
if (pullLabel != null) { 
setPullLabel(pullLabel); 
} 
if (releaseLabel != null) { 
setReleaseLabel(releaseLabel); 
} 
if (refreshingLabel != null) { 
setRefreshingLabel(refreshingLabel); 
} 
} 
/** 
* A mutator to enable/disable Pull-to-Refresh for the current View 
* 
* @param enable 
* Whether Pull-To-Refresh should be used 
*/ 
public final void setPullToRefreshEnabled(boolean enable) { 
this.isPullToRefreshEnabled = enable; 
} 
/** 
* Set Text to show when the Widget is being pulled, and will refresh when 
* released 
* 
* @param releaseLabel 
* - String to display 
*/ 
private void setReleaseLabel(String releaseLabel) { 
if (null != headerLayout) { 
headerLayout.setReleaseLabel(releaseLabel); 
} 
if (null != footerLayout) { 
footerLayout.setReleaseLabel(releaseLabel); 
} 
} 
/** 
* Set Text to show when the Widget is being Pulled 
* 
* @param pullLabel 
* - String to display 
*/ 
private void setPullLabel(String pullLabel) { 
if (null != headerLayout) { 
headerLayout.setPullLabel(pullLabel); 
} 
if (null != footerLayout) { 
footerLayout.setPullLabel(pullLabel); 
} 
} 
/** 
* Set Text to show when the Widget is refreshing 
* 
* @param refreshingLabel 
* - String to display 
*/ 
private void setRefreshingLabel(String refreshingLabel) { 
if (null != headerLayout) { 
headerLayout.setRefreshingLabel(refreshingLabel); 
} 
if (null != footerLayout) { 
footerLayout.setRefreshingLabel(refreshingLabel); 
} 
} 
public final void setRefreshing() { 
this.setRefreshing(true); 
} 
/** 
* Sets the Widget to be in the refresh state. The UI will be updated to 
* show the 'Refreshing' view. 
* 
* @param doScroll 
* - true if you want to force a scroll to the Refreshing view. 
*/ 
public final void setRefreshing(boolean doScroll) { 
if (!isRefreshing()) { 
setRefreshingInternal(doScroll); 
state = MANUAL_REFRESHING; 
} 
} 
public final boolean hasPullFromTop() { 
return currentMode != MODE_PULL_UP_TO_REFRESH; 
} 
// =========================================================== 
// Methods for/from SuperClass/Interfaces 
// =========================================================== 
@Override 
public final boolean onTouchEvent(MotionEvent event) { 
if (!isPullToRefreshEnabled) { 
return false; 
} 
if (isRefreshing() && disableScrollingWhileRefreshing) { 
return true; 
} 
if (event.getAction() == MotionEvent.ACTION_DOWN 
&& event.getEdgeFlags() != 0) { 
return false; 
} 
switch (event.getAction()) { 
case MotionEvent.ACTION_MOVE: { 
if (isBeingDragged) { 
if (Math.abs(event.getY() - downLocation) > 5 
&& onShowLayoutListener != null) { 
onShowLayoutListener.onShow(); 
} 
lastMotionY = event.getY(); 
this.pullEvent(); 
return true; 
} 
break; 
} 
case MotionEvent.ACTION_DOWN: { 
if (isReadyForPull()) { 
downLocation = event.getY(); 
lastMotionY = initialMotionY = event.getY(); 
return true; 
} 
break; 
} 
case MotionEvent.ACTION_CANCEL: 
case MotionEvent.ACTION_UP: { 
if (isBeingDragged) { 
isBeingDragged = false; 
if (state == RELEASE_TO_REFRESH && null != onRefreshListener) { 
setRefreshingInternal(true); 
onRefreshListener.onRefresh(currentMode); 
} else { 
smoothScrollTo(0); 
if (onShowLayoutListener != null) { 
onShowLayoutListener.onDismiss(); 
} 
} 
return true; 
} 
break; 
} 
} 
return false; 
} 
// remeber to down location 
private float downLocation = 0; 
@Override 
public final boolean onInterceptTouchEvent(MotionEvent event) { 
if (!isPullToRefreshEnabled) { 
return false; 
} 
if (isRefreshing() && disableScrollingWhileRefreshing) { 
return true; 
} 
final int action = event.getAction(); 
if (action == MotionEvent.ACTION_CANCEL 
|| action == MotionEvent.ACTION_UP) { 
isBeingDragged = false; 
return false; 
} 
if (action != MotionEvent.ACTION_DOWN && isBeingDragged) { 
return true; 
} 
switch (action) { 
case MotionEvent.ACTION_MOVE: { 
if (isReadyForPull()) { 
final float y = event.getY(); 
final float dy = y - lastMotionY; 
final float yDiff = Math.abs(dy); 
final float xDiff = Math.abs(event.getX() - lastMotionX); 
if (yDiff > touchSlop && yDiff > xDiff) { 
if ((mode == MODE_PULL_DOWN_TO_REFRESH || mode == MODE_BOTH) 
&& dy >= 0.0001f && isReadyForPullDown()) { 
lastMotionY = y; 
isBeingDragged = true; 
if (mode == MODE_BOTH) { 
currentMode = MODE_PULL_DOWN_TO_REFRESH; 
} 
} else if ((mode == MODE_PULL_UP_TO_REFRESH || mode == MODE_BOTH) 
&& dy <= 0.0001f && isReadyForPullUp()) { 
lastMotionY = y; 
isBeingDragged = true; 
if (mode == MODE_BOTH) { 
currentMode = MODE_PULL_UP_TO_REFRESH; 
} 
} 
} 
} 
break; 
} 
case MotionEvent.ACTION_DOWN: { 
if (isReadyForPull()) { 
lastMotionY = initialMotionY = event.getY(); 
lastMotionX = event.getX(); 
isBeingDragged = false; 
} 
break; 
} 
case MotionEvent.ACTION_UP: 
break; 
} 
setRefreshLabel(currentMode); 
return isBeingDragged; 
} 
protected void addRefreshableView(Context context, T refreshableView) { 
addView(refreshableView, new LinearLayout.LayoutParams( 
LayoutParams.FILL_PARENT, 0, 1.0f)); 
} 
/** 
* This is implemented by derived classes to return the created View. If you 
* need to use a custom View (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 
* created View 
* @return New instance of the Refreshable View 
*/ 
protected abstract T createRefreshableView(Context context, 
AttributeSet attrs); 
public final int getCurrentMode() { 
return currentMode; 
} 
protected final LoadingLayout getFooterLayout() { 
return footerLayout; 
} 
protected final LoadingLayout getHeaderLayout() { 
return headerLayout; 
} 
protected final int getHeaderHeight() { 
return headerHeight; 
} 
protected final int getMode() { 
return mode; 
} 
/** 
* Implemented by derived class to return whether the View is in a state 
* where the user can Pull to Refresh by scrolling down. 
* 
* @return true if the View is currently the correct state (for example, top 
* of a ListView) 
*/ 
protected abstract boolean isReadyForPullDown(); 
/** 
* Implemented by derived class to return whether the View is in a state 
* where the user can Pull to Refresh by scrolling up. 
* 
* @return true if the View is currently in the correct state (for example, 
* bottom of a ListView) 
*/ 
protected abstract boolean isReadyForPullUp(); 
// =========================================================== 
// Methods 
// =========================================================== 
protected void resetHeader() { 
state = PULL_TO_REFRESH; 
isBeingDragged = false; 
if (null != headerLayout) { 
headerLayout.reset(); 
} 
if (null != footerLayout) { 
footerLayout.reset(); 
} 
smoothScrollTo(0); 
} 
/** 
* unless special requirements to call the method ,default call the method 
* {@link #setRefreshingInternal(boolean doScroll)} 
* 
* @param doScroll 
* @param mode 
*/ 
protected void setRefreshingInternal(boolean doScroll, int mode) { 
state = REFRESHING; 
setRefreshLabel(mode); 
if (null != headerLayout) { 
headerLayout.refreshing(); 
} 
if (doScroll) { 
smoothScrollTo(mode == MODE_PULL_DOWN_TO_REFRESH ? -headerHeight 
: headerHeight); 
} 
} 
/** 
* set last refresh time 
* 
* @param time 
*/ 
public void setRefreshTime(String time) { 
TextView mHeaderTimeView = (TextView) headerLayout 
.findViewById(R.id.xlistview_header_time); 
mHeaderTimeView.setText(time); 
} 
public void setRefreshTime(long time){ 
TextView mHeaderTimeView = (TextView) headerLayout 
.findViewById(R.id.xlistview_header_time); 
mHeaderTimeView.setText(TimeUtil.getChatTime(time)); 
} 
protected void setRefreshingInternal(boolean doScroll) { 
state = REFRESHING; 
setRefreshLabel(currentMode); 
if (null != footerLayout) { 
footerLayout.refreshing(); 
} 
if (null != headerLayout) { 
headerLayout.refreshing(); 
} 
if (doScroll) { 
smoothScrollTo(currentMode == MODE_PULL_DOWN_TO_REFRESH ? -headerHeight 
: headerHeight); 
} 
} 
private void setRefreshLabel(int mode) { 
if (mode == MODE_PULL_DOWN_TO_REFRESH) { 
setRefreshLabel("涓����锋��", "���剧���冲�锋��", "姝e�ㄥ�锋��"); 
} 
if (mode == MODE_PULL_UP_TO_REFRESH) { 
setRefreshLabel("涓����峰���村�", "�惧��剧ず�村�", "姝e�ㄥ��杞�"); 
} 
} 
protected final void setHeaderScroll(int y) { 
scrollTo(0, y); 
} 
protected final void smoothScrollTo(int y) { 
if (null != currentSmoothScrollRunnable) { 
currentSmoothScrollRunnable.stop(); 
} 
if (this.getScrollY() != y) { 
this.currentSmoothScrollRunnable = new SmoothScrollRunnable( 
handler, getScrollY(), y); 
handler.post(currentSmoothScrollRunnable); 
} 
} 
public void init(int mode) { 
// 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 (null != headerLayout) { 
// headerLayout.setTextColor(Color.BLACK); 
} 
if (null != footerLayout) { 
// footerLayout.setTextColor(Color.BLACK); 
} 
// Hide Loading Views 
switch (mode) { 
case MODE_BOTH: 
setPadding(0, -headerHeight, 0, -headerHeight); 
break; 
case MODE_PULL_UP_TO_REFRESH: 
setPadding(0, 0, 0, -headerHeight); 
break; 
case MODE_PULL_DOWN_TO_REFRESH: 
default: 
setPadding(0, -headerHeight, 0, 0); 
break; 
} 
// If we're not using MODE_BOTH, then just set currentMode to current 
// mode 
if (mode != MODE_BOTH) { 
currentMode = mode; 
} 
this.mode = mode; 
} 
private void init(Context context, AttributeSet attrs) { 
this.context = context; 
setOrientation(LinearLayout.VERTICAL); 
touchSlop = ViewConfiguration.getTouchSlop(); 
// Refreshable View 
// By passing the attrs, we can add ListView/GridView params via XML 
refreshableView = this.createRefreshableView(context, attrs); 
this.addRefreshableView(context, refreshableView); 
} 
private Context context; 
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); 
} 
/** 
* Actions a Pull Event 
* 
* @return true if the Event has been handled, false if there has been no 
* change 
*/ 
private boolean pullEvent() { 
final int newHeight; 
final int oldHeight = this.getScrollY(); 
switch (currentMode) { 
case MODE_PULL_UP_TO_REFRESH: 
newHeight = Math.round(Math.max(initialMotionY - lastMotionY, 0) 
/ FRICTION); 
// newHeight = Math.round((initialMotionY - lastMotionY) / 
// FRICTION); 
break; 
case MODE_PULL_DOWN_TO_REFRESH: 
default: 
newHeight = Math.round(Math.min(initialMotionY - lastMotionY, 0) 
/ FRICTION); 
// newHeight = Math.round((initialMotionY - lastMotionY) / 
// FRICTION); 
break; 
} 
setHeaderScroll(newHeight); 
if (newHeight != 0) { 
if (state == PULL_TO_REFRESH && headerHeight < Math.abs(newHeight)) { 
state = RELEASE_TO_REFRESH; 
switch (currentMode) { 
case MODE_PULL_UP_TO_REFRESH: 
footerLayout.releaseToRefresh(); 
break; 
case MODE_PULL_DOWN_TO_REFRESH: 
headerLayout.releaseToRefresh(); 
break; 
} 
return true; 
} else if (state == RELEASE_TO_REFRESH 
&& headerHeight >= Math.abs(newHeight)) { 
state = PULL_TO_REFRESH; 
switch (currentMode) { 
case MODE_PULL_UP_TO_REFRESH: 
footerLayout.pullToRefresh(); 
break; 
case MODE_PULL_DOWN_TO_REFRESH: 
headerLayout.pullToRefresh(); 
break; 
} 
return true; 
} 
} 
return oldHeight != newHeight; 
} 
private boolean isReadyForPull() { 
switch (mode) { 
case MODE_PULL_DOWN_TO_REFRESH: 
return isReadyForPullDown(); 
case MODE_PULL_UP_TO_REFRESH: 
return isReadyForPullUp(); 
case MODE_BOTH: 
return isReadyForPullUp() || isReadyForPullDown(); 
} 
return false; 
} 
// =========================================================== 
// Inner and Anonymous Classes 
// =========================================================== 
public static interface OnRefreshListener { 
public void onRefresh(int mode); 
} 
private OnShowLayoutListener onShowLayoutListener; 
public void setOnShowLayoutListener(OnShowLayoutListener listener) { 
this.onShowLayoutListener = listener; 
} 
public static interface OnShowLayoutListener { 
/** 
* ����姝e�ㄦ�剧ず搴��ㄥ�灞� 
*/ 
public void onShow(); 
/** 
* ����娑�澶� 
*/ 
public void onDismiss(); 
} 
public static interface OnLastItemVisibleListener { 
public void onLastItemVisible(); 
} 
@Override 
public void setLongClickable(boolean longClickable) { 
getRefreshableView().setLongClickable(longClickable); 
} 
}

主要代码都在上面贴出来了,当然还是一定要有demo

DEMO源码下载

这个源码里面 我把 PullToRefreshExpandableListView 和 PullToRefreshListView 也都放进来了,一样的逻辑。希望对大家有用。如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

你可能感兴趣的:(GridView基于pulltorefresh实现下拉刷新 上拉加载更多功能(推荐))