Obtenir l’élément central visible de RecycleView lors du défilement

C’est ce que je veux:

entrer la description de l'image ici

En tant qu’image ci-dessus, je veux dessiner une ligne centrale sur RecycleView , puis obtenir l’élément central lors du défilement (ainsi que déplacer vers la gauche ou la droite)
Voici mon essai pour dessiner un RecycleView horizontal:

  HorizontalAdapter adapter = new HorizontalAdapter(data); LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); recycleView.setLayoutManager(layoutManager); recycleView.setAdapter(adapter); 

Existe-t-il un moyen de savoir quel élément est déplacé vers le centre de RecycleView ? Et comment puis-je faire défiler RecycleView à gauche ou à droite d’une seule position?

Mise à jour : J’ai essayé d’utiliser un programme d’écoute de défilement pour obtenir une position intermédiaire, mais cela ne fonctionne pas comme aspect.

  @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int firstPos = layoutManager.findFirstVisibleItemPosition(); int lastPos = layoutManager.findLastVisibleItemPosition(); int middle = Math.abs(lastPos - firstPos) / 2 + firstPos; int selectedPos = -1; for (int i = 0; i < adapter.getItemCount(); i++) { if (i == middle) { adapter.getItem(i).setSelected(true); selectedPos = i; } else { adapter.getItem(i).setSelected(false); } } adapter.notifyDataSetChanged(); } 

Et obtenez le résultat:

entrer la description de l'image ici

Je veux seulement changer l’élément de sélection (rendre le texte en blanc) lorsqu’il est sur le Rect bleu

J’ai fait quelque chose comme ça. Je peux faire exactement ce dont vous avez besoin. Tout d’abord, voici comment fonctionne mon alogrithme entrer la description de l'image ici

Ceci est mon adaptateur recyclerView

 public class DateAdapter extends RecyclerView.Adapter { private ArrayList dateDataList; private static final int VIEW_TYPE_PADDING = 1; private static final int VIEW_TYPE_ITEM = 2; private int paddingWidthDate = 0; private int selectedItem = -1; public DateAdapter(ArrayList dateData, int paddingWidthDate) { this.dateDataList = dateData; this.paddingWidthDate = paddingWidthDate; } @Override public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_ITEM) { final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_date, parent, false); return new DateViewHolder(view); } else { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_padding, parent, false); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams(); layoutParams.width = paddingWidthDate; view.setLayoutParams(layoutParams); return new DateViewHolder(view); } } @Override public void onBindViewHolder(DateViewHolder holder, int position) { LabelerDate labelerDate = dateDataList.get(position); if (getItemViewType(position) == VIEW_TYPE_ITEM) { if(labelerDate.dateType.equals(BirthDayActivity.DateType.C31)) holder.tvDate.setText(Ssortingng.valueOf(labelerDate.valueDate)); holder.tvDate.setVisibility(View.VISIBLE); holder.imgSmall.setVisibility(View.VISIBLE); if (position == selectedItem) { holder.tvDate.setTextColor(Color.parseColor("#094673")); holder.tvDate.setTextSize(35); holder.imgSmall.setBackgroundResource(R.color.textviewbold); } else { holder.tvDate.setTextColor(Color.GRAY); holder.tvDate.setTextSize(35); holder.imgSmall.setBackgroundResource(R.color.gray); } } } public void setSelecteditem(int selecteditem) { this.selectedItem = selecteditem; notifyDataSetChanged(); } @Override public int getItemCount() { return dateDataList.size(); } @Override public int getItemViewType(int position) { LabelerDate labelerDate = dateDataList.get(position); if (labelerDate.dateType.equals(BirthDayActivity.DateType.NONE)) { return VIEW_TYPE_PADDING; } return VIEW_TYPE_ITEM; } public class DateViewHolder extends RecyclerView.ViewHolder { public TextView tvDate; public ImageView imgSmall; public DateViewHolder(View itemView) { super(itemView); tvDate = (TextView) itemView.findViewById(R.id.tvNumberDate); imgSmall = (ImageView) itemView.findViewById(R.id.small_marked_dob); } }} 

C’est l’alogrithme le plus important:

 public void getRecyclerviewDate() { recyclerViewDate = (RecyclerView) findViewById(R.id.recyclerViewDay); ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver(); vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this); finalWidthDate = recyclerViewDate.getMeasuredWidth(); itemWidthDate = getResources().getDimension(R.dimen.item_dob_width); paddingDate = (finalWidthDate - itemWidthDate) / 2; firstItemWidthDate = paddingDate ; allPixelsDate = 0; final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext()); dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerViewDate.setLayoutManager(dateLayoutManager); recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); synchronized (this) { if(newState == RecyclerView.SCROLL_STATE_IDLE){ calculatePositionAndScrollDate(recyclerView); } } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); allPixelsDate += dx; } }); if (labelerDates == null) labelerDates = new ArrayList<>(); labelerDates.addAll(genLabelerDate(currentMonth, currentYear)); dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate); recyclerViewDate.setAdapter(dateAdapter); return true; } }); } /* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/ private void calculatePositionAndScrollDate(RecyclerView recyclerView) { int expectedPositionDate = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate); if (expectedPositionDate == -1) { expectedPositionDate = 0; } else if (expectedPositionDate >= recyclerView.getAdapter().getItemCount() - 2) { expectedPositionDate--; } scrollListToPositionDate(recyclerView, expectedPositionDate); } /* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/ private void scrollListToPositionDate(RecyclerView recyclerView, int expectedPositionDate) { float targetScrollPosDate = expectedPositionDate * itemWidthDate + firstItemWidthDate - paddingDate; float missingPxDate = targetScrollPosDate - allPixelsDate; if (missingPxDate != 0) { recyclerView.smoothScrollBy((int) missingPxDate, 0); } } private void setDateValue() { int expectedPositionDateColor = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate); setColorDate = expectedPositionDateColor + 1; //set color here dateAdapter.setSelecteditem(setColorDate); } @Override protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); allPixelsDate = savedInstanceState.getFloat(BUNDLE_LIST_PIXELS_DATE); allPixelsDateChanged = savedInstanceState.getFloat(BUNDLE_LIST_PIXELS_DATE_CHANGED); } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putFloat(BUNDLE_LIST_PIXELS_DATE, allPixelsDate); outState.putFloat(BUNDLE_LIST_PIXELS_DATE_CHANGED, allPixelsDateChanged); } 

Et ceci est mon résultat: entrer la description de l'image ici

Regardez ce lien vidéo, c'est ma démo d'application

Parfois, nous avons besoin du bloc de code exemple complet, car nous pouvons manquer quelque chose. Voici ce que j’ai, n’hésitez pas à corriger quoi que ce soit, car je fais peut-être une petite erreur quelque part. Et oui, cette réponse est une extension de la réponse de @tranhieu. Merci @tranhieu.

MainActivity.java

 package com.test; import android.app.Activity; import android.graphics.Color; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.TextView; import java.util.ArrayList; public class MainActivity extends Activity { private static final Ssortingng TAG = MainActivity.class.getSimpleName(); public float firstItemWidthDate; public float paddingDate; public float itemWidthDate; public int allPixelsDate; public int finalWidthDate; private DateAdapter dateAdapter; private ArrayList labelerDates = new ArrayList<>(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getRecyclerviewDate(); } public void getRecyclerviewDate() { final RecyclerView recyclerViewDate = (RecyclerView) findViewById(R.id.rv_tasks_date); if (recyclerViewDate != null) { recyclerViewDate.postDelayed(new Runnable() { @Override public void run() { setDateValue(); } }, 300); recyclerViewDate.postDelayed(new Runnable() { @Override public void run() { recyclerViewDate.smoothScrollToPosition(dateAdapter.getItemCount()-1); setDateValue(); } }, 5000); } ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver(); vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this); finalWidthDate = recyclerViewDate.getMeasuredWidth(); itemWidthDate = getResources().getDimension(R.dimen.item_dob_width); paddingDate = (finalWidthDate - itemWidthDate) / 2; firstItemWidthDate = paddingDate; allPixelsDate = 0; final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext()); dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerViewDate.setLayoutManager(dateLayoutManager); recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); synchronized (this) { if (newState == RecyclerView.SCROLL_STATE_IDLE) { calculatePositionAndScrollDate(recyclerView); } } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); allPixelsDate += dx; } }); if (labelerDates == null) { labelerDates = new ArrayList<>(); } genLabelerDate(); dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate); recyclerViewDate.setAdapter(dateAdapter); dateAdapter.setSelecteditem(dateAdapter.getItemCount() - 1); return true; } }); } private void genLabelerDate() { for (int i = 0; i < 32; i++) { LabelerDate labelerDate = new LabelerDate(); labelerDate.setNumber(Integer.toString(i)); labelerDates.add(labelerDate); if (i == 0 || i == 31) { labelerDate.setType(DateAdapter.VIEW_TYPE_PADDING); } else { labelerDate.setType(DateAdapter.VIEW_TYPE_ITEM); } } } /* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/ private void calculatePositionAndScrollDate(RecyclerView recyclerView) { int expectedPositionDate = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate); if (expectedPositionDate == -1) { expectedPositionDate = 0; } else if (expectedPositionDate >= recyclerView.getAdapter().getItemCount() - 2) { expectedPositionDate--; } scrollListToPositionDate(recyclerView, expectedPositionDate); } /* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/ private void scrollListToPositionDate(RecyclerView recyclerView, int expectedPositionDate) { float targetScrollPosDate = expectedPositionDate * itemWidthDate + firstItemWidthDate - paddingDate; float missingPxDate = targetScrollPosDate - allPixelsDate; if (missingPxDate != 0) { recyclerView.smoothScrollBy((int) missingPxDate, 0); } setDateValue(); } // private void setDateValue() { int expectedPositionDateColor = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate); int setColorDate = expectedPositionDateColor + 1; // set color here dateAdapter.setSelecteditem(setColorDate); } public class DateAdapter extends RecyclerView.Adapter { private ArrayList dateDataList; private static final int VIEW_TYPE_PADDING = 1; private static final int VIEW_TYPE_ITEM = 2; private int paddingWidthDate = 0; private int selectedItem = -1; public DateAdapter(ArrayList dateData, int paddingWidthDate) { this.dateDataList = dateData; this.paddingWidthDate = paddingWidthDate; } @Override public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_ITEM) { final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); return new DateViewHolder(view); } else { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams(); layoutParams.width = paddingWidthDate; view.setLayoutParams(layoutParams); return new DateViewHolder(view); } } @Override public void onBindViewHolder(DateViewHolder holder, int position) { LabelerDate labelerDate = dateDataList.get(position); if (getItemViewType(position) == VIEW_TYPE_ITEM) { holder.tvDate.setText(labelerDate.getNumber()); holder.tvDate.setVisibility(View.VISIBLE); Log.d(TAG, "default " + position + ", selected " + selectedItem); if (position == selectedItem) { Log.d(TAG, "center" + position); holder.tvDate.setTextColor(Color.parseColor("#76FF03")); holder.tvDate.setTextSize(35); } else { holder.tvDate.setTextColor(Color.WHITE); holder.tvDate.setTextSize(18); } } else { holder.tvDate.setVisibility(View.INVISIBLE); } } public void setSelecteditem(int selecteditem) { this.selectedItem = selecteditem; notifyDataSetChanged(); } @Override public int getItemCount() { return dateDataList.size(); } @Override public int getItemViewType(int position) { LabelerDate labelerDate = dateDataList.get(position); if (labelerDate.getType() == VIEW_TYPE_PADDING) { return VIEW_TYPE_PADDING; } else { return VIEW_TYPE_ITEM; } } public class DateViewHolder extends RecyclerView.ViewHolder { public TextView tvDate; public DateViewHolder(View itemView) { super(itemView); tvDate = (TextView) itemView.findViewById(R.id.txt_date); } } } private class LabelerDate { private int type; private Ssortingng number; public Ssortingng getNumber() { return number; } public void setNumber(Ssortingng number) { this.number = number; } public int getType() { return type; } public void setType(int type) { this.type = type; } } } 

activity_main.xml

        

item.xml

     

dimens.xml

  100dp  

Comme mentionné dans l’autre réponse, il n’y a pas de moyen direct de le faire.

C’est probablement ainsi que vous pouvez réaliser ce que vous avez décrit dans la question.

  1. Connaître le nombre d’éléments visibles à l’écran.
  2. Sélectionnez l’élément central par programmation à chaque défilement de la vue.
  3. Conservez une image partiellement transparente en tant que superposition sur l’élément intermédiaire de la recyclerview. (Vous devrez calculer les coordonnées en fonction de la largeur de la vue du recycleur ou de la largeur de l’écran et de la largeur de l’image de superposition que vous choisissez de placer.
  4. Actualisez la valeur sélectionnée dans une vue de texte sous la vue du recycleur chaque fois qu’il y a un défilement.

Les superpositions d’image doivent être placées de manière à ce qu’elles semblent connectées et en un seul contrôle.

Je suis utilisé le SnapHelper ici:

  // init snaphelper SnapHelper snapHelper = new LinearSnapHelper(); snapHelper.attachToRecyclerView(recyclerView) // init layout manager LinearLayoutManager layoutManager = new LinearLayoutManager(mainActivity); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerView.setLayoutManager(layoutManager); // init adapter adatper.setSnapHelper(snapHelper); adatper.setLayoutManager(layoutManager); adatper.initAdapter(new Float((DisplayHelper.getDisplayWidth(mainActivity) / 2) - (fooViewWidth / 2)).intValue()); recyclerView.setAdapter(adatper); 

Comme le dit TranHieu, la solution consistant à insérer 2 éléments pour le rembourrage (au début et à la fin) est bonne.

Je n’aime pas l’utilisation de ViewTreeObserver en raison de la mauvaise lisibilité du code. Avec cette technique, vous devez également gérer le redessinage des éléments s’ils sont recyclés.

Si vous utilisez des classes de vues personnalisées, vous pouvez définir sa largeur directement dans ces classes.

Par exemple c’est ma classe de padding

 /** * Created by firegloves on 25/09/15. */ @EViewGroup(R.layout.view_padding) public class PaddingView extends FooView { Context mCtx; public PaddingView(Context context) { super(context); mCtx = context; } public void setWidth(int width) { setLayoutParams(new LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT)); } } 

Dans mon adaptateur, je stocke la largeur d’élément de remplissage souhaitée, qui est égale à (displayWidth / 2) – (realItemWidth / 2)

Ceci est mon adaptateur, ne regardez pas les méthodes ne correspondant pas à RecyclerView.Adapter, faites attention à la méthode initAdapter et à la méthode onCreateItemView

 @EBean public class FooAdapterRecycler extends RecyclerViewAdapterBase { private final int TYPE_PADDING_VIEW = 0; private final int TYPE_REAL_VIEW = 1; @RootContext Context ctx; @Bean(Finder.class) IFinder finder; SnapHelper snapHelper; RecyclerView.LayoutManager layoutManager; private int paddingWidth = 0; /** * preleva i dati dal finder */ public void initAdapter(int paddingWidth) { /******************************* * THIS CODE IS THE IMPORTANT ONE ******************************/ this.paddingWidth = paddingWidth; // add 1 item for initial space mItems = new ArrayList<>(); Foo foo = new Foo(); mItems.add(foo); // get real items from finder mItems.addAll(finder.findAll()); // add 1 item for final space mItems = new ArrayList<>(); Foo foo2 = new Foo(); mItems.add(foo2); } @Override public int getItemViewType(int position) { if (position == 0 || position == getItemCount()-1) { return TYPE_PADDING_VIEW; } else { return TYPE_REAL_VIEW; } } @Override protected FooView onCreateItemView(ViewGroup parent, int viewType) { /******************************* * THIS CODE IS THE IMPORTANT ONE ******************************/ if (viewType == TYPE_PADDING_VIEW) { PaddingView view = PaddingView_.build(ctx); view.setWidth(paddingWidth); return view; } else { return FooView_.build(ctx); } } public void setSnapHelper(SnapHelper snapHelper) { this.snapHelper = snapHelper; } public void setLayoutManager(RecyclerView.LayoutManager layoutManager) { this.layoutManager = layoutManager; } } 

J’utilise la bibliothèque AndroidAnnotations mais ce n’est pas obligatoire

J’espère que cela pourra aider

Pour cette fonctionnalité, utilisez la bibliothèque EcoGallery: https://github.com/falnatsheh/EcoGallery

UTILISATION DE SNAPHELPER – UNE SOLUTION PLUS SIMPLE

Voici une autre solution utilisant SnapHelper . À partir de la réponse de @TranHieu ici:

https://stackoverflow.com/a/34647005/3944251

et le compressé par @ sector11 ici:

https://stackoverflow.com/a/38411582/3944251

J’ai écrit le code suivant qui est également basé sur les deux réponses ci-dessus, mais il est plus simple et offre une solution plus fluide en utilisant SnapHelper présenté dans la bibliothèque de support Android 24.2.0 .

Ici vous avez la classe MainActivity . Le rest est le même avec la réponse de @ sector11.

 import android.graphics.Color; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearSnapHelper; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.TextView; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { private static final Ssortingng TAG = MainActivity.class.getSimpleName(); public float firstItemWidthDate; public float itemWidthDate; public int allPixelsDate; public int finalWidthDate; private DateAdapter dateAdapter; private ArrayList labelerDates; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); labelerDates = new ArrayList<>(); getRecyclerviewDate(); } public void getRecyclerviewDate() { final RecyclerView recyclerViewDate = (RecyclerView) findViewById(R.id.rv_tasks_date); recyclerViewDate.postDelayed(new Runnable() { @Override public void run() { //recyclerViewDate.smoothScrollToPosition(dateAdapter.getItemCount()-1); setDateValue(); } }, 300); ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver(); vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this); finalWidthDate = recyclerViewDate.getMeasuredWidth(); itemWidthDate = getResources().getDimension(R.dimen.item_dob_width); firstItemWidthDate = (finalWidthDate - itemWidthDate) / 2; allPixelsDate = 0; final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext()); dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerViewDate.setLayoutManager(dateLayoutManager); /* Create a LinearSnapHelper and attach the recyclerView to it. */ final LinearSnapHelper snapHelper = new LinearSnapHelper(); snapHelper.attachToRecyclerView(recyclerViewDate); recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { allPixelsDate += dx; recyclerView.post(new Runnable() { public void run() { setDateValue(); } }); } }); genLabelerDate(); dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate); recyclerViewDate.setAdapter(dateAdapter); dateAdapter.setSelecteditem(dateAdapter.getItemCount() - 1); return true; } }); } private void genLabelerDate() { for (int i = 0; i < 32; i++) { LabelerDate labelerDate = new LabelerDate(); labelerDate.setNumber(Integer.toString(i)); labelerDates.add(labelerDate); if (i == 0 || i == 31) { labelerDate.setType(DateAdapter.VIEW_TYPE_PADDING); } else { labelerDate.setType(DateAdapter.VIEW_TYPE_ITEM); } } } // private void setDateValue() { int expectedPositionDateColor = Math.round(allPixelsDate / itemWidthDate); int setColorDate = expectedPositionDateColor + 1; // set color here dateAdapter.setSelecteditem(setColorDate); } public class DateAdapter extends RecyclerView.Adapter { private ArrayList dateDataList; private static final int VIEW_TYPE_PADDING = 1; private static final int VIEW_TYPE_ITEM = 2; private int paddingWidthDate = 0; private int selectedItem = -1; public DateAdapter(ArrayList dateData, int paddingWidthDate) { this.dateDataList = dateData; this.paddingWidthDate = paddingWidthDate; } @Override public DateAdapter.DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); if (viewType == VIEW_TYPE_PADDING) { RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams(); layoutParams.width = paddingWidthDate; view.setLayoutParams(layoutParams); } return new DateViewHolder(view); } @Override public void onBindViewHolder(DateAdapter.DateViewHolder holder, int position) { LabelerDate labelerDate = dateDataList.get(position); if (getItemViewType(position) == VIEW_TYPE_ITEM) { holder.tvDate.setText(labelerDate.getNumber()); holder.tvDate.setVisibility(View.VISIBLE); Log.d(TAG, "default " + position + ", selected " + selectedItem); if (position == selectedItem) { Log.d(TAG, "center" + position); holder.tvDate.setTextColor(Color.parseColor("#76FF03")); holder.tvDate.setTextSize(35); } else { holder.tvDate.setTextColor(Color.WHITE); holder.tvDate.setTextSize(18); } } else { holder.tvDate.setVisibility(View.INVISIBLE); } } public void setSelecteditem(int selecteditem) { this.selectedItem = selecteditem; notifyDataSetChanged(); } @Override public int getItemCount() { return dateDataList.size(); } @Override public int getItemViewType(int position) { LabelerDate labelerDate = dateDataList.get(position); if (labelerDate.getType() == VIEW_TYPE_PADDING) { return VIEW_TYPE_PADDING; } else { return VIEW_TYPE_ITEM; } } public class DateViewHolder extends RecyclerView.ViewHolder { public TextView tvDate; public DateViewHolder(View itemView) { super(itemView); tvDate = (TextView) itemView.findViewById(R.id.txt_date); } } } private class LabelerDate { private int type; private Ssortingng number; public Ssortingng getNumber() { return number; } public void setNumber(Ssortingng number) { this.number = number; } public int getType() { return type; } public void setType(int type) { this.type = type; } } } 

Je ne pense pas qu’il y ait une approche directe pour y parvenir. Vous pouvez essayer ceci –

listView.setOnScrollListener (écouteur);

@Passer outre

 public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) { int firstVisibleRow = listView.getFirstVisiblePosition(); int lastVisibleRow = listView.getLastVisiblePosition(); int count - ((int*)count/2; int middle = listview.getChildAt(count - ((int)count/2)); } } 

vous pouvez vous référer à cette réponse également https://stackoverflow.com/a/13134100/1320616 https://stackoverflow.com/a/19205940/1320616

Au début, j’avais besoin de quelque chose de similaire, pas de ça. Mais j’ai pu adapter la solution @TranHieu à mes besoins, alors j’ai voté pour sa solution.

Je voulais créer une recyclerview horizontal en plein écran qui, après le lancement de l’utilisateur, mettrait à jour scrollPosition sur mostVisibleItem.

installer:

 private void setUpScrolling() { mRecyclerVIew.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mRecyclerVIew.getViewTreeObserver().removeOnPreDrawListener(this); CustomScrollListener listener = (CustomScrollListener) mScrollListener; listener.width = mRecyclerVIew.getMeasuredWidth(); listener.dx = 0; return true; } }); } 

auditeur:

 private class CustomScrollListener extends OnScrollListener { private int mLastDx = 0; int width = 0; int dx = 0; @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (newState == RecyclerView.SCROLL_STATE_IDLE) { if (mLastDx != dx) { scrollToMostVisibleItem(); } else { dx = 0; mLastDx = 0; } } super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); this.dx += dx; } private void scrollToMostVisibleItem() { int direction = (dx > 0) ? 1 : -1; dx = Math.abs(dx); int shiftCount = Math.round(dx / width); int pixelShift = dx % width; if (pixelShift > width / 2) { shiftCount++; } float targetScrollPixels = shiftCount * width; float finalScrollPixels = (targetScrollPixels - dx) * direction; if (finalScrollPixels != 0) { mRecyclerVIew.smoothScrollBy((int) finalScrollPixels, 0); mLastDx = (int) finalScrollPixels; dx = 0; } } } 

J’ai utilisé une autre approche dans mon cas.

vous pouvez trouver les deatils ici: RecyclerView – Comment mettre en évidence l’élément visible central pendant le défilement 1

À mon avis, ma solution est plus facile que les autres.

Si quelqu’un cherche une implémentation plus générique, voici mon code basé sur les réponses de ce sujet:

Ajouter le CenterLinearSnapHelper

 public class CenterLinearSnapHelper extends LinearSnapHelper { //Constants public static final Ssortingng TAG = CenterLinearSnapHelper.class.getSimpleName(); //Atsortingbutes private Context context; private float itemWidth; private OnPaddingComputationListener listener; //Constructors /** * A linear snap helper which helps centering the items in a recyclerview. * * @param itemWidth The (fixed) width of a child view in pixels. */ public CenterLinearSnapHelper(float itemWidth) { this.itemWidth = itemWidth; } public void attachToRecyclerView(@Nullable RecyclerView recyclerView, @NonNull OnPaddingComputationListener listener) throws IllegalStateException { this.listener = listener; //Calculates the padding for the first and end item calculatePadding(recyclerView); //Create a LinearSnapHelper and attach the recyclerView to it. attachToRecyclerView(recyclerView); } public float getItemWidth() { return itemWidth; } private void calculatePadding(RecyclerView recyclerView) { if (recyclerView == null) return; ViewTreeObserver observer = recyclerView.getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { recyclerView.getViewTreeObserver().removeOnPreDrawListener(this); int finalWidth = recyclerView.getMeasuredWidth(); float padding = (finalWidth - itemWidth) / 2; listener.onPadding(padding, finalWidth); return true; } }); } public interface OnPaddingComputationListener { void onPadding(float padding, int finalWidth); } } 

Dans votre activité / fragment où vous créez votre RecyclerView:

 float itemWidth = getResources().getDimension(R.dimen.favorite_room_width); CenterLinearSnapHelper snapHelper = new CenterLinearSnapHelper(itemWidth); snapHelper.attachToRecyclerView(binding.listFavorites, (padding, finalWidth) -> { //Set the adapter roomAdapter = new RoomAdapter(requireContext(), rooms); roomAdapter.addPaddingItems((int) padding); roomAdapter.setOnToggleClickListener(FavoritesFragment.this); binding.listFavorites.setAdapter(roomAdapter); }); 

Dans votre adaptateur:

 public void addPaddingItems(int padding) { if (padding < 0) throw new IllegalStateException("Padding cannot be smaller than 0"); this.padding = padding; //Add 2 new items as the first and last //NOTE: If you update your existing dataset (eg add new items), you should redo the calculation! rooms.add(0, new Room("First")); rooms.add(rooms.size(), new Room("Last")); } @Override public int getItemViewType(int position) { if (padding >= 0 && (position == 0 || position == rooms.size() - 1)) { return VIEW_TYPE_PADDING; } return VIEW_TYPE_ITEM; } @NonNull @Override public RoomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { ViewFavoriteRoomBinding binding = DataBindingUtil.inflate(inflater, R.layout.view_favorite_room, parent, false); if (viewType == VIEW_TYPE_PADDING) { RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) binding.getRoot().getLayoutParams(); layoutParams.width = padding; binding.getRoot().setLayoutParams(layoutParams); } RoomViewHolder viewHolder = new RoomViewHolder(context, binding, onToggleClickListener); viewHolder.getRecyclerView().setRecycledViewPool(viewPool); return viewHolder; } 

Oh mec. Je cherchais cette réponse depuis près d’une semaine et j’ai ensuite trouvé la solution. LayoutManagers personnalisés? No. ItemDecorator ? Nan.

Voici le moyen le plus simple de le faire:

  

La partie critique est la suivante:

  android:paddingStart="150dp" android:paddingEnd="150dp" android:clipToPadding="false" 

Et puis, assignez simplement SnapHelper à votre RecylcerView :

 val snapHelper = LinearSnapHelper() snapHelper.attachToRecyclerView(recyclerView) 

Ça y est. La solution la plus simple et la plus parfaite au problème