/**
   * Locate the visible view which has the earliest adapter position. Will skip headers unless they
   * are the only one visible.
   *
   * @param sectionFirstPosition Position of first position of section..
   * @param skipHeader Do not include the section header if it has one.
   * @return View.
   */
  public View getFirstVisibleView(int sectionFirstPosition, boolean skipHeader) {
    int lookAt = 0;
    int childCount = mLayoutManager.getChildCount();
    View candidate = null;
    while (true) {
      if (lookAt >= childCount) {
        return candidate;
      }

      final View view = mLayoutManager.getChildAt(lookAt);
      LayoutManager.LayoutParams lp = (LayoutManager.LayoutParams) view.getLayoutParams();
      if (sectionFirstPosition == lp.getTestedFirstPosition()) {
        if (!lp.isHeader || !skipHeader) {
          return view;
        } else {
          candidate = view;
        }
      } else {
        // Skipped past section.
        return candidate;
      }

      lookAt += 1;
    }
  }
 /**
  * Find the lowest displayed edge of the section. If there is no member found then return the
  * default edge instead.
  *
  * @param sectionFirstPosition Section id, position of first item in the section.
  * @param lastIndex Index to start looking from. Usually the index of the last attached view in
  *     this section.
  * @param defaultEdge Default value.
  * @return Lowest (attached) edge of the section.
  */
 public int getLowestEdge(int sectionFirstPosition, int lastIndex, int defaultEdge) {
   // Look from end to find children that are the lowest.
   for (int i = lastIndex; i >= 0; i--) {
     View child = mLayoutManager.getChildAt(i);
     LayoutManager.LayoutParams params = (LayoutManager.LayoutParams) child.getLayoutParams();
     if (params.getTestedFirstPosition() != sectionFirstPosition) {
       break;
     }
     if (params.isHeader) {
       continue;
     }
     // A more interesting layout would have to do something more here.
     return mLayoutManager.getDecoratedBottom(child);
   }
   return defaultEdge;
 }
 /**
  * Find the highest displayed edge of the section. If there is no member found then return the
  * default edge instead.
  *
  * @param sectionFirstPosition Section id, position of first item in the section.
  * @param firstIndex Child index to start looking from.
  * @param defaultEdge Default value.
  * @return Top (attached) edge of the section.
  */
 public int getHighestEdge(int sectionFirstPosition, int firstIndex, int defaultEdge) {
   // Look from start to find children that are the highest.
   for (int i = firstIndex; i < mLayoutManager.getChildCount(); i++) {
     View child = mLayoutManager.getChildAt(i);
     LayoutManager.LayoutParams params = (LayoutManager.LayoutParams) child.getLayoutParams();
     if (params.getTestedFirstPosition() != sectionFirstPosition) {
       break;
     }
     if (params.isHeader) {
       continue;
     }
     // A more interesting layout would have to do something more here.
     return mLayoutManager.getDecoratedTop(child);
   }
   return defaultEdge;
 }
  /**
   * Locate the last view in this section that is completely visible. Will skip headers unless they
   * are the only one visible.
   *
   * @param sectionFirstPosition First position of section being queried.
   * @return Last completely visible item or null.
   */
  public View getLastCompletelyVisibleView(int sectionFirstPosition) {
    final int topEdge = mLayoutManager.getClipToPadding() ? mLayoutManager.getPaddingTop() : 0;
    final int bottomEdge =
        mLayoutManager.getClipToPadding()
            ? mLayoutManager.getHeight() - mLayoutManager.getPaddingBottom()
            : mLayoutManager.getHeight();

    int lookAt = mLayoutManager.getChildCount() - 1;
    View candidate = null;
    while (true) {
      if (lookAt < 0) {
        return candidate;
      }

      final View view = mLayoutManager.getChildAt(lookAt);

      final boolean topInside = mLayoutManager.getDecoratedTop(view) >= topEdge;
      final boolean bottomInside = mLayoutManager.getDecoratedBottom(view) <= bottomEdge;

      LayoutManager.LayoutParams lp = (LayoutManager.LayoutParams) view.getLayoutParams();
      if (sectionFirstPosition == lp.getTestedFirstPosition()) {
        if (topInside && bottomInside) {
          if (!lp.isHeader) {
            return view;
          } else {
            candidate = view;
          }
        }
      } else if (candidate == null) {
        sectionFirstPosition = lp.getTestedFirstPosition();
        continue;
      } else {
        return candidate;
      }

      lookAt -= 1;
    }
  }
  /**
   * Locate the visible view which has the latest adapter position.
   *
   * @param sectionFirstPosition Section id.
   * @return View.
   */
  public View getLastVisibleView(int sectionFirstPosition) {
    int lookAt = mLayoutManager.getChildCount() - 1;
    View candidate = null;
    while (true) {
      if (lookAt < 0) {
        return candidate;
      }

      View view = mLayoutManager.getChildAt(lookAt);
      LayoutManager.LayoutParams lp = (LayoutManager.LayoutParams) view.getLayoutParams();
      if (sectionFirstPosition == lp.getTestedFirstPosition()) {
        if (!lp.isHeader) {
          return view;
        } else {
          candidate = view;
        }
      } else {
        // Skipped past section.
        return candidate;
      }

      lookAt -= 1;
    }
  }