title: Tap to refresh is visible all the time and gap is still visible on list view
body: <p>I am using pull to refresh in my application. Pull to refresh is working fine when the list size is crossing screen. But when the size is one or two there is a gap between the header and the listview saying tap to refresh. </p>
  
  <p>Here is my code </p>
  
  <pre><code>public class PullToRefreshListView extends ListView implements OnScrollListener {
  
  private static final int TAP_TO_REFRESH = 1;
  private static final int PULL_TO_REFRESH = 2;
  private static final int RELEASE_TO_REFRESH = 3;
  private static final int REFRESHING = 4;
  
  private static final String TAG = "PullToRefreshListView";
  
  private OnRefreshListener mOnRefreshListener;
  
  /**
   * Listener that will receive notifications every time the list scrolls.
   */
  private OnScrollListener mOnScrollListener;
  private LayoutInflater mInflater;
  
  private RelativeLayout mRefreshView;
  private TextView mRefreshViewText;
  private ImageView mRefreshViewImage;
  private ProgressBar mRefreshViewProgress;
  private TextView mRefreshViewLastUpdated;
  
  private int mCurrentScrollState;
  private int mRefreshState;
  
  private RotateAnimation mFlipAnimation;
  private RotateAnimation mReverseFlipAnimation;
  
  private int mRefreshViewHeight;
  private int mRefreshOriginalTopPadding;
  private int mLastMotionY;
  
  private boolean mBounceHack;
  
  public PullToRefreshListView(Context context) {
      super(context);
      init(context);
  }
  
  public PullToRefreshListView(Context context, AttributeSet attrs) {
      super(context, attrs);
      init(context);
  }
  
  public PullToRefreshListView(Context context, AttributeSet attrs,
          int defStyle) {
      super(context, attrs, defStyle);
      init(context);
  }
  
  private void init(Context context) {
      // Load all of the animations we need in code rather than through XML
      mFlipAnimation = new RotateAnimation(0, -180,
              RotateAnimation.RELATIVE_TO_SELF, 0.5f,
              RotateAnimation.RELATIVE_TO_SELF, 0.5f);
      mFlipAnimation.setInterpolator(new LinearInterpolator());
      mFlipAnimation.setDuration(250);
      mFlipAnimation.setFillAfter(true);
      mReverseFlipAnimation = new RotateAnimation(-180, 0,
              RotateAnimation.RELATIVE_TO_SELF, 0.5f,
              RotateAnimation.RELATIVE_TO_SELF, 0.5f);
      mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
      mReverseFlipAnimation.setDuration(250);
      mReverseFlipAnimation.setFillAfter(true);
  
      mInflater = (LayoutInflater) context
              .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  
      mRefreshView = (RelativeLayout) mInflater.inflate(
              R.layout.pull_to_refresh_header, this, false);
      mRefreshViewText = (TextView) mRefreshView
              .findViewById(R.id.pull_to_refresh_text);
      mRefreshViewImage = (ImageView) mRefreshView
              .findViewById(R.id.pull_to_refresh_image);
      mRefreshViewProgress = (ProgressBar) mRefreshView
              .findViewById(R.id.pull_to_refresh_progress);
      mRefreshViewLastUpdated = (TextView) mRefreshView
              .findViewById(R.id.pull_to_refresh_updated_at);
  
      mRefreshViewImage.setMinimumHeight(50);
      mRefreshView.setOnClickListener(new OnClickRefreshListener());
      mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();
  
      mRefreshState = TAP_TO_REFRESH;
  
      addHeaderView(mRefreshView);
  
      super.setOnScrollListener(this);
  
      measureView(mRefreshView);
      mRefreshViewHeight = mRefreshView.getMeasuredHeight();
  }
  
  @Override
  protected void onAttachedToWindow() {
      super.onAttachedToWindow();
      setSelection(1);
  }
  
  @Override
  public void setAdapter(ListAdapter adapter) {
      super.setAdapter(adapter);
  
      setSelection(1);
  }
  
  /**
   * Set the listener that will receive notifications every time the list
   * scrolls.
   * 
   * @param l
   *            The scroll listener.
   */
  @Override
  public void setOnScrollListener(AbsListView.OnScrollListener l) {
      mOnScrollListener = l;
  }
  
  /**
   * Register a callback to be invoked when this list should be refreshed.
   * 
   * @param onRefreshListener
   *            The callback to run.
   */
  public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
      mOnRefreshListener = onRefreshListener;
  }
  
  /**
   * Set a text to represent when the list was last updated.
   * 
   * @param lastUpdated
   *            Last updated at.
   */
  public void setLastUpdated(CharSequence lastUpdated) {
      if (lastUpdated != null) {
          mRefreshViewLastUpdated.setVisibility(View.VISIBLE);
          mRefreshViewLastUpdated.setText(lastUpdated);
      } else {
          mRefreshViewLastUpdated.setVisibility(View.GONE);
      }
  }
  
  @Override
  public boolean onTouchEvent(MotionEvent event) {
      final int y = (int) event.getY();
      mBounceHack = false;
  
      switch (event.getAction()) {
      case MotionEvent.ACTION_UP:
          if (!isVerticalScrollBarEnabled()) {
              setVerticalScrollBarEnabled(true);
          }
          if (getFirstVisiblePosition() == 0 &amp;&amp; mRefreshState != REFRESHING) {
              if ((mRefreshView.getBottom() &gt;= mRefreshViewHeight || mRefreshView
                      .getTop() &gt;= 0) &amp;&amp; mRefreshState == RELEASE_TO_REFRESH) {
                  // Initiate the refresh
                  mRefreshState = REFRESHING;
                  prepareForRefresh();
                  onRefresh();
              } else if (mRefreshView.getBottom() &lt; mRefreshViewHeight
                      || mRefreshView.getTop() &lt;= 0) {
                  // Abort refresh and scroll down below the refresh view
                  resetHeader();
                  setSelection(1);
              }
          }
          break;
      case MotionEvent.ACTION_DOWN:
          mLastMotionY = y;
          break;
      case MotionEvent.ACTION_MOVE:
          applyHeaderPadding(event);
          break;
      }
      return super.onTouchEvent(event);
  }
  
  private void applyHeaderPadding(MotionEvent ev) {
      // getHistorySize has been available since API 1
      int pointerCount = ev.getHistorySize();
  
      for (int p = 0; p &lt; pointerCount; p++) {
          if (mRefreshState == RELEASE_TO_REFRESH) {
              if (isVerticalFadingEdgeEnabled()) {
                  setVerticalScrollBarEnabled(false);
              }
  
              int historicalY = (int) ev.getHistoricalY(p);
  
              // Calculate the padding to apply, we divide by 1.7 to
              // simulate a more resistant effect during pull.
              int topPadding = (int) (((historicalY - mLastMotionY) - mRefreshViewHeight) / 1.7);
  
              mRefreshView.setPadding(mRefreshView.getPaddingLeft(),
                      topPadding, mRefreshView.getPaddingRight(),
                      mRefreshView.getPaddingBottom());
          }
      }
  }
  
  /**
   * Sets the header padding back to original size.
   */
  private void resetHeaderPadding() {
      mRefreshView.setPadding(mRefreshView.getPaddingLeft(),
              mRefreshOriginalTopPadding, mRefreshView.getPaddingRight(),
              mRefreshView.getPaddingBottom());
  }
  
  /**
   * Resets the header to the original state.
   */
  private void resetHeader() {
      if (mRefreshState != TAP_TO_REFRESH) {
          mRefreshState = TAP_TO_REFRESH;
  
          resetHeaderPadding();
  
          // Set refresh view text to the pull label
          mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);
          // Replace refresh drawable with arrow drawable
          mRefreshViewImage
                  .setImageResource(R.drawable.ic_pulltorefresh_arrow);
          // Clear the full rotation animation
          mRefreshViewImage.clearAnimation();
          // Hide progress bar and arrow.
          mRefreshViewImage.setVisibility(View.GONE);
          mRefreshViewProgress.setVisibility(View.GONE);
      }
  }
  
  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 &gt; 0) {
          childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
                  MeasureSpec.EXACTLY);
      } else {
          childHeightSpec = MeasureSpec.makeMeasureSpec(0,
                  MeasureSpec.UNSPECIFIED);
      }
      child.measure(childWidthSpec, childHeightSpec);
  }
  
  @Override
  public void onScroll(AbsListView view, int firstVisibleItem,
          int visibleItemCount, int totalItemCount) {
      // When the refresh view is completely visible, change the text to say
      // "Release to refresh..." and flip the arrow drawable.
      if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL
              &amp;&amp; mRefreshState != REFRESHING) {
          if (firstVisibleItem == 0) {
              mRefreshViewImage.setVisibility(View.VISIBLE);
              if ((mRefreshView.getBottom() &gt;= mRefreshViewHeight + 20 || mRefreshView
                      .getTop() &gt;= 0) &amp;&amp; mRefreshState != RELEASE_TO_REFRESH) {
                  mRefreshViewText
                          .setText(R.string.pull_to_refresh_release_label);
                  mRefreshViewImage.clearAnimation();
                  mRefreshViewImage.startAnimation(mFlipAnimation);
                  mRefreshState = RELEASE_TO_REFRESH;
              } else if (mRefreshView.getBottom() &lt; mRefreshViewHeight + 20
                      &amp;&amp; mRefreshState != PULL_TO_REFRESH) {
                  mRefreshViewText
                          .setText(R.string.pull_to_refresh_pull_label);
                  if (mRefreshState != TAP_TO_REFRESH) {
                      mRefreshViewImage.clearAnimation();
                      mRefreshViewImage.startAnimation(mReverseFlipAnimation);
                  }
                  mRefreshState = PULL_TO_REFRESH;
              }
          } else {
              mRefreshViewImage.setVisibility(View.GONE);
              resetHeader();
          }
      } else if (mCurrentScrollState == SCROLL_STATE_FLING
              &amp;&amp; firstVisibleItem == 0 &amp;&amp; mRefreshState != REFRESHING) {
          setSelection(1);
          mBounceHack = true;
      } else if (mBounceHack &amp;&amp; mCurrentScrollState == SCROLL_STATE_FLING) {
          setSelection(1);
      }
  
      if (mOnScrollListener != null) {
          mOnScrollListener.onScroll(view, firstVisibleItem,
                  visibleItemCount, totalItemCount);
      }
  }
  
  @Override
  public void onScrollStateChanged(AbsListView view, int scrollState) {
      mCurrentScrollState = scrollState;
  
      if (mCurrentScrollState == SCROLL_STATE_IDLE) {
          mBounceHack = false;
      }
  
      if (mOnScrollListener != null) {
          mOnScrollListener.onScrollStateChanged(view, scrollState);
      }
  }
  
  public void prepareForRefresh() {
      resetHeaderPadding();
  
      mRefreshViewImage.setVisibility(View.GONE);
      // We need this hack, otherwise it will keep the previous drawable.
      mRefreshViewImage.setImageDrawable(null);
      mRefreshViewProgress.setVisibility(View.VISIBLE);
  
      // Set refresh view text to the refreshing label
      mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);
  
      mRefreshState = REFRESHING;
  }
  
  public void onRefresh() {
      Log.d(TAG, "onRefresh");
  
      if (mOnRefreshListener != null) {
          mOnRefreshListener.onRefresh();
      }
  }
  
  /**
   * Resets the list to a normal state after a refresh.
   * 
   * @param lastUpdated
   *            Last updated at.
   */
  public void onRefreshComplete(CharSequence lastUpdated) {
      setLastUpdated(lastUpdated);
      onRefreshComplete();
  }
  
  /**
   * Resets the list to a normal state after a refresh.
   */
  public void onRefreshComplete() {
      Log.d(TAG, "onRefreshComplete");
  
      resetHeader();
  
      // If refresh view is visible when loading completes, scroll down to
      // the next item.
      if (mRefreshView.getBottom() &gt; 0) {
          invalidateViews();
          setSelection(1);
      }
  }
  
  /**
   * Invoked when the refresh view is clicked on. This is mainly used when
   * there's only a few items in the list and it's not possible to drag the
   * list.
   */
  private class OnClickRefreshListener implements OnClickListener {
  
      @Override
      public void onClick(View v) {
          if (mRefreshState != REFRESHING) {
              prepareForRefresh();
              onRefresh();
          }
      }
  
  }
  
  /**
   * Interface definition for a callback to be invoked when list should be
   * refreshed.
   */
  public interface OnRefreshListener {
      /**
       * Called when the list should be refreshed.
       * &lt;p&gt;
       * A call to {@link PullToRefreshListView #onRefreshComplete()} is
       * expected to indicate that the refresh has completed.
       */
      public void onRefresh();
  }
  </code></pre>
  
  <p>}</p>
  
  <p>Here is my xml code</p>
  
  <pre><code>            &lt;com.k2b.kluebook.pulltorefresh.PullToRefreshListView
              android:id="@+id/list_pulltorefresh"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:divider="@null"
              android:dividerHeight="0dp" &gt;
          &lt;/com.k2b.kluebook.pulltorefresh.PullToRefreshListView&gt;
  </code></pre>
  
  <p>Here is my class file code</p>
  
  <pre><code>listview.setOnRefreshListener(new OnRefreshListener() {
              @Override
              public void onRefresh() {
                  // Do work to refresh the list here.
  
              }
          });
  </code></pre>
  
  <p><img src="https://i.stack.imgur.com/gxTWw.png" alt="Here is the image with gap between the header"></p>
  
  <p><img src="https://i.stack.imgur.com/oqrWm.png" alt="If the gap is clicked Tap is showing"></p>
  
  <p>How to get rid of the GAP and "Tap to Refresh".</p>