protected LoadingLayout createLoadingLayout(Context context, Mode mode, TypedArray attrs) {
   LoadingLayout layout =
       mLoadingAnimationStyle.createLoadingLayout(
           context, mode, getPullToRefreshScrollDirection(), attrs);
   layout.setVisibility(View.INVISIBLE);
   return layout;
 }
  /**
   * Updates the View State when the mode has been set. This does not do any checking that the mode
   * is different to current state so always updates.
   */
  protected void updateUIForMode() {
    // We need to use the correct LayoutParam values, based on scroll
    // direction
    final LayoutParams lp = getLoadingLayoutLayoutParams();

    // Remove Header, and then add Header Loading View again if needed
    if (this == mHeaderLayout.getParent()) {
      removeView(mHeaderLayout);
    }
    if (mMode.showHeaderLoadingLayout()) {
      addViewInternal(mHeaderLayout, 0, lp);
    }

    // Remove Footer, and then add Footer Loading View again if needed
    if (this == mFooterLayout.getParent()) {
      removeView(mFooterLayout);
    }
    if (mMode.showFooterLoadingLayout()) {
      addViewInternal(mFooterLayout, lp);
    }

    // Hide Loading Views
    refreshLoadingViewsSize();

    // If we're not using Mode.BOTH, set mCurrentMode to mMode, otherwise
    // set it to pull down
    mCurrentMode = (mMode != Mode.BOTH) ? mMode : Mode.PULL_FROM_START;
  }
  /**
   * Called when the UI has been to be updated to be in the {@link
   * com.minglang.pulltorefreshlibrary.PullToRefreshBase.State#RESET} state.
   */
  protected void onReset() {
    mIsBeingDragged = false;
    mLayoutVisibilityChangesEnabled = true;

    // Always reset both layouts, just in case...
    mHeaderLayout.reset();
    mFooterLayout.reset();

    smoothScrollTo(0);
  }
 /**
  * Called when the UI has been to be updated to be in the {@link
  * com.minglang.pulltorefreshlibrary.PullToRefreshBase.State#RELEASE_TO_REFRESH} state.
  */
 protected void onReleaseToRefresh() {
   switch (mCurrentMode) {
     case PULL_FROM_END:
       mFooterLayout.releaseToRefresh();
       break;
     case PULL_FROM_START:
       mHeaderLayout.releaseToRefresh();
       break;
     default:
       // NO-OP
       break;
   }
 }
  /** Re-measure the Loading Views height, and adjust internal padding as necessary */
  protected final void refreshLoadingViewsSize() {
    final int maximumPullScroll = (int) (getMaximumPullScroll() * 1.2f);

    int pLeft = getPaddingLeft();
    int pTop = getPaddingTop();
    int pRight = getPaddingRight();
    int pBottom = getPaddingBottom();

    switch (getPullToRefreshScrollDirection()) {
      case HORIZONTAL:
        if (mMode.showHeaderLoadingLayout()) {
          mHeaderLayout.setWidth(maximumPullScroll);
          pLeft = -maximumPullScroll;
        } else {
          pLeft = 0;
        }

        if (mMode.showFooterLoadingLayout()) {
          mFooterLayout.setWidth(maximumPullScroll);
          pRight = -maximumPullScroll;
        } else {
          pRight = 0;
        }
        break;

      case VERTICAL:
        if (mMode.showHeaderLoadingLayout()) {
          mHeaderLayout.setHeight(maximumPullScroll);
          pTop = -maximumPullScroll;
        } else {
          pTop = 0;
        }

        if (mMode.showFooterLoadingLayout()) {
          mFooterLayout.setHeight(maximumPullScroll);
          pBottom = -maximumPullScroll;
        } else {
          pBottom = 0;
        }
        break;
    }

    if (DEBUG) {
      Log.d(
          LOG_TAG,
          String.format(
              "Setting Padding. L: %d, T: %d, R: %d, B: %d", pLeft, pTop, pRight, pBottom));
    }
    setPadding(pLeft, pTop, pRight, pBottom);
  }
  /**
   * Actions a Pull Event
   *
   * @return true if the Event has been handled, false if there has been no change
   */
  private void pullEvent() {
    final int newScrollValue;
    final int itemDimension;
    final float initialMotionValue, lastMotionValue;

    switch (getPullToRefreshScrollDirection()) {
      case HORIZONTAL:
        initialMotionValue = mInitialMotionX;
        lastMotionValue = mLastMotionX;
        break;
      case VERTICAL:
      default:
        initialMotionValue = mInitialMotionY;
        lastMotionValue = mLastMotionY;
        break;
    }

    switch (mCurrentMode) {
      case PULL_FROM_END:
        newScrollValue = Math.round(Math.max(initialMotionValue - lastMotionValue, 0) / FRICTION);
        itemDimension = getFooterSize();
        break;
      case PULL_FROM_START:
      default:
        newScrollValue = Math.round(Math.min(initialMotionValue - lastMotionValue, 0) / FRICTION);
        itemDimension = getHeaderSize();
        break;
    }

    setHeaderScroll(newScrollValue);

    if (newScrollValue != 0 && !isRefreshing()) {
      float scale = Math.abs(newScrollValue) / (float) itemDimension;
      switch (mCurrentMode) {
        case PULL_FROM_END:
          mFooterLayout.onPull(scale);
          break;
        case PULL_FROM_START:
        default:
          mHeaderLayout.onPull(scale);
          break;
      }

      if (mState != State.PULL_TO_REFRESH && itemDimension >= Math.abs(newScrollValue)) {
        setState(State.PULL_TO_REFRESH);
      } else if (mState == State.PULL_TO_REFRESH && itemDimension < Math.abs(newScrollValue)) {
        setState(State.RELEASE_TO_REFRESH);
      }
    }
  }
  /**
   * Helper method which just calls scrollTo() in the correct scrolling direction.
   *
   * @param value - New Scroll value
   */
  protected final void setHeaderScroll(int value) {
    if (DEBUG) {
      Log.d(LOG_TAG, "setHeaderScroll: " + value);
    }

    // Clamp value to with pull scroll range
    final int maximumPullScroll = getMaximumPullScroll();
    value = Math.min(maximumPullScroll, Math.max(-maximumPullScroll, value));

    if (mLayoutVisibilityChangesEnabled) {
      if (value < 0) {
        mHeaderLayout.setVisibility(View.VISIBLE);
      } else if (value > 0) {
        mFooterLayout.setVisibility(View.VISIBLE);
      } else {
        mHeaderLayout.setVisibility(View.INVISIBLE);
        mFooterLayout.setVisibility(View.INVISIBLE);
      }
    }

    if (USE_HW_LAYERS) {
      /**
       * Use a Hardware Layer on the Refreshable View if we've scrolled at all. We don't use them on
       * the Header/Footer Views as they change often, which would negate any HW layer performance
       * boost.
       */
      ViewCompat.setLayerType(
          mRefreshableViewWrapper, value != 0 ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE);
    }

    switch (getPullToRefreshScrollDirection()) {
      case VERTICAL:
        scrollTo(0, value);
        break;
      case HORIZONTAL:
        scrollTo(value, 0);
        break;
    }
  }
  /**
   * Called when the UI has been to be updated to be in the {@link
   * com.minglang.pulltorefreshlibrary.PullToRefreshBase.State#REFRESHING} or {@link
   * com.minglang.pulltorefreshlibrary.PullToRefreshBase.State#MANUAL_REFRESHING} state.
   *
   * @param doScroll - Whether the UI should scroll for this event.
   */
  protected void onRefreshing(final boolean doScroll) {
    if (mMode.showHeaderLoadingLayout()) {
      mHeaderLayout.refreshing();
    }
    if (mMode.showFooterLoadingLayout()) {
      mFooterLayout.refreshing();
    }

    if (doScroll) {
      if (mShowViewWhileRefreshing) {

        // Call Refresh Listener when the Scroll has finished
        OnSmoothScrollFinishedListener listener =
            new OnSmoothScrollFinishedListener() {
              @Override
              public void onSmoothScrollFinished() {
                callRefreshListener();
              }
            };

        switch (mCurrentMode) {
          case MANUAL_REFRESH_ONLY:
          case PULL_FROM_END:
            smoothScrollTo(getFooterSize(), listener);
            break;
          default:
          case PULL_FROM_START:
            smoothScrollTo(-getHeaderSize(), listener);
            break;
        }
      } else {
        smoothScrollTo(0);
      }
    } else {
      // We're not scrolling, so just call Refresh Listener now
      callRefreshListener();
    }
  }
 protected final int getHeaderSize() {
   return mHeaderLayout.getContentSize();
 }
 protected final int getFooterSize() {
   return mFooterLayout.getContentSize();
 }