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

简介: 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<String> list = new ArrayList<String>();
    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<String> mList = new ArrayList<String>();
    private Context mContext;
    public GridViewAdapter(Context context,List<String> 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<GridView> {
  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<T extends View> 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);
  }
}


相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
11月前
nvue中list组件下拉刷新后无法上拉加载更多
nvue中list组件下拉刷新后无法上拉加载更多
129 0
|
JavaScript Linux
【unapp】上拉加载,下拉刷新
【unapp】上拉加载,下拉刷新
102 0
SwipeRefreshLayout 下拉刷新控件(二)
SwipeRefreshLayout 下拉刷新控件(二)
SwipeRefreshLayout 下拉刷新控件(一)
SwipeRefreshLayout 下拉刷新控件(一)
|
前端开发
Flutter 之列表下拉刷新和上拉加载
在实际的 App 中,下拉刷新和上滑加载更多是非常常见的交互形式。在 Flutter 中,有 flutter_easyrefresh开源插件用于实现下拉刷新和上滑加载更多。本篇介绍了有状态组件和 flutter_easyrefresh 的基本应用,同时使用模拟的方式完成了异步数据加载。
704 0
Flutter 之列表下拉刷新和上拉加载
|
API
为RecyclerView添加下拉刷新功能
在之前的文章中,我们实现了带有header和footer功能的WrapRecyclerView。 现今App中列表的下拉刷新和上拉加载已经是一种习惯了,这两个操作也确实方便很多。 为RecyclerView添加这个功能可以通过多种方法,这里我选用了一种简单的做法。基于pulltorefresh这个库。
184 0
UWP 下拉刷新控件(PullToRefreshControl)
原文:UWP 下拉刷新控件(PullToRefreshControl) 最近项目里面有下拉刷新的需求,自己做了一个,效果还不错。 ...
1283 0
|
前端开发
RecyclerView学习(五)----SwipeRefreshLayout的下拉刷新与上拉加载
SwipeRefreshLayout作为官方的下拉刷新控件,简洁美观的风格使其广泛应用在项目中。美中不足的是SwipeRefreshLayout缺少上拉加载的效果,今天结合RecyclerView实现一个支持下拉刷新与上拉加载的SwipeRefreshLayout。
1349 0