Android: Comment obtenir le décalage X actuel de RecyclerView?

J’utilise une Scrollview de Scrollview pour un “carrousel de sélecteur de temps” infini et j’ai découvert que ce n’était pas la meilleure approche ( dernière question )

Maintenant, j’ai trouvé la vue Recycler, mais je ne parviens pas à obtenir le décalage de défilement actuel dans la direction X de recyclerView ? (Supposons que chaque élément a une largeur de 100 pixels et que le second élément est uniquement visible à 50%, le décalage de défilement est donc de 150 pixels)

  • tous les objects ont la même largeur, mais il y a un certain écart avant le premier, après le dernier élément
  • recyclerView.getScrollX() renvoie 0 (les documents indiquent: valeur de défilement initiale)
  • le LayoutManager a findFirstVisibleItemPosition , mais je ne peux pas calculer le décalage X avec cela

METTRE À JOUR

Je viens de trouver un moyen de continuer à suivre la position X, tout en mettant à jour la valeur avec le rappel onScrolled , mais je préférerais obtenir la valeur réelle au lieu de la suivre tout le temps!

 private int overallXScroll = 0; //... mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); overallXScroll = overallXScroll + dx; Log.i("check","overallXScroll->" + overallXScroll); } }); 

RecyclerView a déjà une méthode pour obtenir un décalage horizontal et vertical du défilement

 mRecyclerView.computeHorizontalScrollOffset() mRecyclerView.computeVerticalScrollOffset() 

Cela fonctionnera pour RecyclerViews contenant des cellules de même hauteur (pour le décalage vertical) et de même largeur (pour le décalage horizontal).

entrer la description de l'image ici

Solution 1: setOnScrollListener

Enregistrez votre X-Position en tant que variable de classe et mettez à jour chaque modification dans onScrollListener . Assurez-vous de ne pas réinitialiser overallXScroll (par exemple, onScreenRotationChange )

  private int overallXScroll = 0; //... mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); overallXScroll = overallXScroll + dx; Log.i("check","overall X = " + overallXScroll); } }); 

Solution 2: Calculer la position actuelle.

Dans mon cas, j’ai une liste horizontale remplie de valeurs de temps (0:00, 0:30, 1:00, 1:30 … 23:00, 23:30). Je calcule l’heure à partir du point temporel, qui se trouve au milieu de l’écran (sharepoint calcul). C’est pourquoi j’ai besoin de la position X-Scroll exacte de mon RecycleView

  • Chaque élément de temps a la même largeur de 60dp (fyi: 60dp = 30min, 2dp = 1min)
  • Le premier élément (élément d’en-tête) a un remplissage supplémentaire, pour définir 0min au centre

     private int mScreenWidth = 0; private int mHeaderItemWidth = 0; private int mCellWidth = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //init recycle views //... LinearLayoutManager mLLM = (LinearLayoutManager) getLayoutManager(); DisplayMesortingcs displaymesortingcs = new DisplayMesortingcs(); this.getWindowManager().getDefaultDisplay().getMesortingcs(displaymesortingcs); this.mScreenWidth = displaymesortingcs.widthPixels; //calculate value on current device mCellWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources() .getDisplayMesortingcs()); //get offset of list to the right (gap to the left of the screen from the left side of first item) final int mOffset = (this.mScreenWidth / 2) - (mCellWidth / 2); //HeaderItem width (blue rectangle in graphic) mHeaderItemWidth = mOffset + mCellWidth; mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); //get first visible item View firstVisibleItem = mLLM.findViewByPosition(mLLM.findFirstVisibleItemPosition()); int leftScrollXCalculated = 0; if (firstItemPosition == 0){ //if first item, get width of headerview (getLeft() < 0, that's why I Use Math.abs()) leftScrollXCalculated = Math.abs(firstVisibleItem.getLeft()); } else{ //X-Position = Gap to the right + Number of cells * width - cell offset of current first visible item //(mHeaderItemWidth includes already width of one cell, that's why I have to subtract it again) leftScrollXCalculated = (mHeaderItemWidth - mCellWidth) + firstItemPosition * mCellWidth + firstVisibleItem.getLeft(); } Log.i("asdf","calculated X to left = " + leftScrollXCalculated); } }); 

    }

Merci à @ umar-qureshi pour la bonne piste! Il semble que vous pouvez déterminer le pourcentage de défilement avec Offset , Extent et Range tels que

 percentage = 100 * offset / (range - extent) 

Par exemple (à mettre dans un OnScrollListener ):

 int offset = recyclerView.computeVerticalScrollOffset(); int extent = recyclerView.computeVerticalScrollExtent(); int range = recyclerView.computeVerticalScrollRange(); int percentage = (int)(100.0 * offset / (float)(range - extent)); Log.i("RecyclerView, "scroll percentage: "+ percentage + "%"); 
 public class CustomRecyclerView extends RecyclerView { public CustomRecyclerView(Context context) { super(context); } public CustomRecyclerView(Context context, AtsortingbuteSet attrs) { super(context, attrs); } public CustomRecyclerView(Context context, AtsortingbuteSet attrs, int defStyle) { super(context, attrs, defStyle); } public int getHorizontalOffset() { return super.computeHorizontalScrollOffset(); } } 

Que là où vous devez obtenir le décalage:

 recyclerView.getHorizontalOffset() 

en onScrolled(int dx,int dy) RecyclerView onScrolled(int dx,int dy) , vous pouvez obtenir le décalage de défilement. mais lorsque vous ajoutez ou supprimez l’élément, la valeur peut être incorrecte.

 public class TempRecyclerView extends RecyclerView { private int offsetX = 0; private int offsetY = 0; public TempRecyclerView(Context context) { super(context); } public TempRecyclerView(Context context, @Nullable AtsortingbuteSet attrs) { super(context, attrs); } public TempRecyclerView(Context context, @Nullable AtsortingbuteSet attrs,int defStyle){ super(context, attrs, defStyle); } /** * Called when the scroll position of this RecyclerView changes. Subclasses should usethis method to respond to scrolling within the adapter's data set instead of an explicit listener. * 

This method will always be invoked before listeners. If a subclass needs to perform any additional upkeep or bookkeeping after scrolling but before listeners run, this is a good place to do so.

*/ @Override public void onScrolled(int dx, int dy) { // super.onScrolled(dx, dy); offsetX+=dx; offsetY+=dy; } }

Si vous avez besoin de connaître la page actuelle et son décalage par rapport à la largeur de RecyclerView, vous pouvez essayer quelque chose comme ceci:

 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); final int scrollOffset = recyclerView.computeHorizontalScrollOffset(); final int width = recyclerView.getWidth(); final int currentPage = scrollOffset / width; final float pageOffset = (float) (scrollOffset % width) / width; // the following lines just the example of how you can use it if (currentPage == 0) { leftIndicator.setAlpha(pageOffset); } if (adapter.getItemCount() <= 1) { rightIndicator.setAlpha(pageOffset); } else if (currentPage == adapter.getItemCount() - 2) { rightIndicator.setAlpha(1f - pageOffset); } } }); 

Si currentPage a l'index 0 alors leftIndicator (arrow) sera transparent, et le sera aussi rightIndicator s'il n'y a qu'une seule page (dans l'exemple, l'adaptateur a toujours au moins un élément à afficher donc il n'y a pas de contrôle pour la valeur vide).

De cette façon, vous aurez pratiquement les mêmes fonctionnalités que si vous utilisiez la pageScrolled de ViewPager.OnPageChangeListener de ViewPager.OnPageChangeListener .