J'ai une RecyclerView
qui est dans une CardView
. La CardView
a une hauteur de 500dp, mais je veux la raccourcir si la RecyclerView
est plus petite . Je me demande donc si un auditeur est appelé lorsque la RecyclerView
a fini de déposer ses éléments pour la première fois, ce qui rend il est possible de régler la hauteur de la RecyclerView
à la hauteur de la CardView
(si elle est inférieure à 500dp).
J'avais également besoin d'exécuter du code une fois que ma vue du recycleur avait fini de gonfler tous les éléments. J'ai essayé de vérifier onBindViewHolder
dans mon adaptateur si la position était la dernière, puis j'ai averti l'observateur. Mais à ce stade, la vue recycleur n'était toujours pas complètement renseignée.
Comme RecyclerView implements ViewGroup
, cette réponse était très utile. Vous devez simplement ajouter un OnGlobalLayoutListener à recyclerView:
View recyclerView = findViewById(R.id.myView);
recyclerView.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//At this point the layout is complete and the
//dimensions of recyclerView and any child views are known.
//Remove listener after changed RecyclerView's height to prevent infinite loop
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
Modification de travail de @andrino anwser.
Comme @Juancho l'a souligné dans le commentaire ci-dessus. Cette méthode est appelée plusieurs fois. Dans ce cas, nous souhaitons qu’il ne soit déclenché qu’une fois.
Créer un écouteur personnalisé avec une instance, par exemple
private RecyclerViewReadyCallback recyclerViewReadyCallback;
public interface RecyclerViewReadyCallback {
void onLayoutReady();
}
Puis définissez OnGlobalLayoutListener
sur votre RecyclerView
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (recyclerViewReadyCallback != null) {
recyclerViewReadyCallback.onLayoutReady();
}
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
après cela, vous devez uniquement implémenter un programme d'écoute personnalisé avec votre code
recyclerViewReadyCallback = new RecyclerViewReadyCallback() {
@Override
public void onLayoutReady() {
//
//here comes your code that will be executed after all items are laid down
//
}
};
Si vous utilisez Kotlin, il existe alors une solution plus compacte… ..échantillon de ici .
Cet écouteur de présentation est généralement utilisé pour effectuer une opération après la mesure d'une vue. Vous devez donc normalement attendre que largeur et hauteur soient supérieures à 0.
... il peut être utilisé par n'importe quel objet qui étend View et peut également accéder à toutes ses fonctions et propriétés spécifiques à partir du listener.
// define 'afterMeasured' layout listener:
inline fun <T: View> T.afterMeasured(crossinline f: T.() -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (measuredWidth > 0 && measuredHeight > 0) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
f()
}
}
})
}
// using 'afterMeasured' handler:
recycler.afterMeasured {
// do the scroll (you can use the RecyclerView functions and properties directly)
// ...
}
J'ai eu du mal à essayer de supprimer OnGlobalLayoutListener
une fois que cela s'est déclenché, mais cela jette un IllegalStateException
. Puisque ce dont j'ai besoin, c’est de faire défiler mon recyclerView vers le deuxième élément. Ce que j’ai fait, c’était de vérifier si elle avait déjà des enfants et si c’était la première fois que c’était vrai, alors seulement je fais le parchemin:
public class MyActivity extends BaseActivity implements BalanceView {
...
private boolean firstTime = true;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
ViewTreeObserver vto = myRecyclerView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (myRecyclerView.getChildCount() > 0 && MyActivity.this.firstTime){
MyActivity.this.firstTime = false;
scrollToSecondPosition();
}
}
});
}
...
private void scrollToSecondPosition() {
// do the scroll
}
}
HTH quelqu'un!
(Bien sûr, cela a été inspiré par les réponses @andrino et @Phatee)
Dans les mêmes cas, vous pouvez également utiliser la méthode RecyclerView.post()
pour exécuter votre code une fois que les éléments de la liste/de la grille sont apparus. Dans mes cas, c'était assez joli.
// Another way
// Get the values
Maybe<List<itemClass>> getItemClass(){
return /* */
}
// Create a listener
void getAll(DisposableMaybeObserver<List<itemClass>> dmo) {
getItemClass().subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(dmo);
}
// In the code where you want to track the end of loading in recyclerView:
DisposableMaybeObserver<List<itemClass>> mSubscriber = new DisposableMaybeObserver<List<itemClass>>() {
@Override
public void onSuccess(List<itemClass> item_list) {
adapter.setWords(item_list);
adapter.notifyDataSetChanged();
Log.d("RECYCLER", "DONE");
}
@Override
public void onError(Throwable e) {
Log.d("RECYCLER", "ERROR " + e.getMessage());
}
@Override
public void onComplete() {
Log.d("RECYCLER", "COMPLETE");
}
};
void getAll(mSubscriber);
//and
@Override
public void onDestroy() {
super.onDestroy();
mSubscriber.dispose();
Log.d("RECYCLER","onDestroy");
}