How to mimic the listView stickey-items like on Lollipop's contacts app?

后端 未结 5 1975
遥遥无期
遥遥无期 2020-12-09 04:17

Background

Google has recently published a new version of Android, which has a contact app that look like this :

5条回答
  •  清歌不尽
    2020-12-09 05:00

    You can do the following:

    1. On the leftmost side of your RecyclerView, creates a TextView that will hold the letter index;
    2. On the top of the Recycler view (in the layout that wrappes it) place a TextView in order to cover the one you created in step 1, this will be the sticky one;
    3. Add a OnScrollListener in your RecyclerView. On method onScrolled (), set the TextView created in step 2 for the reference text taken from firstVisibleRow. Until here you shall have a stiky index, without the effects of transition;
    4. To add the fade in/out transition effect, develop a logic that checks if the item previous of the currentFirstVisibleItem is the last of the previous letter list, or if the secondVisibleItem is the first one of the new letter. Based on these information make the sticky index visible/invisible and the row index the opposed, adding in this last the alpha effect.

         if (recyclerView != null) {
          View firstVisibleView = recyclerView.getChildAt(0);
          View secondVisibleView = recyclerView.getChildAt(1);
      
          TextView firstRowIndex = (TextView) firstVisibleView.findViewById(R.id.sticky_row_index);
          TextView secondRowIndex = (TextView) secondVisibleView.findViewById(R.id.sticky_row_index);
      
          int visibleRange = recyclerView.getChildCount();
          int actual = recyclerView.getChildPosition(firstVisibleView);
          int next = actual + 1;
          int previous = actual - 1;
          int last = actual + visibleRange;
      
          // RESET STICKY LETTER INDEX
          stickyIndex.setText(String.valueOf(getIndexContext(firstRowIndex)).toUpperCase());
          stickyIndex.setVisibility(TextView.VISIBLE);
      
          if (dy > 0) {
              // USER SCROLLING DOWN THE RecyclerView
              if (next <= last) {
                  if (isHeader(firstRowIndex, secondRowIndex)) {
                      stickyIndex.setVisibility(TextView.INVISIBLE);
                      firstRowIndex.setVisibility(TextView.VISIBLE);
                      firstRowIndex.setAlpha(1 - (Math.abs(firstVisibleView.getY()) / firstRowIndex.getHeight()));
                      secondRowIndex.setVisibility(TextView.VISIBLE);
                  } else {
                      firstRowIndex.setVisibility(TextView.INVISIBLE);
                      stickyIndex.setVisibility(TextView.VISIBLE);
                  }
              }
          } else {
              // USER IS SCROLLING UP THE RecyclerVIew
              if (next <= last) {
                  // RESET FIRST ROW STATE
                  firstRowIndex.setVisibility(TextView.INVISIBLE);
      
                  if ((isHeader(firstRowIndex, secondRowIndex) || (getIndexContext(firstRowIndex) != getIndexContext(secondRowIndex))) && isHeader(firstRowIndex, secondRowIndex)) {
                      stickyIndex.setVisibility(TextView.INVISIBLE);
                      firstRowIndex.setVisibility(TextView.VISIBLE);
                      firstRowIndex.setAlpha(1 - (Math.abs(firstVisibleView.getY()) / firstRowIndex.getHeight()));
                      secondRowIndex.setVisibility(TextView.VISIBLE);
                  } else {
                      secondRowIndex.setVisibility(TextView.INVISIBLE);
                  }
              }
          }
      
          if (stickyIndex.getVisibility() == TextView.VISIBLE) {
              firstRowIndex.setVisibility(TextView.INVISIBLE);
          }
      }
      

    I have developed a component that does the above logic, it can be found here: https://github.com/edsilfer/sticky-index

提交回复
热议问题