Ich habe eine RecyclerView
, die sich in einer CardView
befindet. Die CardView
hat eine Höhe von 500dp, aber ich möchte diese Höhe verkürzen, wenn die RecyclerView
kleiner ist .. __ Ich frage mich, ob es einen Listener gibt, der aufgerufen wird, wenn die RecyclerView
-Komponente zum ersten Mal fertig ist Es ist möglich, die Höhe von RecyclerView
auf die Höhe von CardView
(falls kleiner als 500 dp) einzustellen.
Ich musste auch Code ausführen, nachdem meine Recycler-Ansicht alle Elemente aufgeblasen hatte. Ich habe versucht, onBindViewHolder
in meinem Adapter einzuchecken, ob die Position die letzte war, und dann den Beobachter benachrichtigt. Zu diesem Zeitpunkt war die Sicht der Wiederverwerter jedoch noch nicht vollständig besiedelt.
Da RecyclerViewViewGroup
implementiert, war diese Antwort sehr hilfreich. Sie müssen lediglich einen OnGlobalLayoutListener zum RecyclerView hinzufügen:
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);
}
});
Funktionsänderung von @andrino anwser.
Als @Juancho in Kommentar oben gezeigt. Diese Methode wird mehrfach aufgerufen. In diesem Fall möchten wir, dass es nur einmal ausgelöst wird.
Erstellen Sie einen benutzerdefinierten Listener mit einer Instanz, z
private RecyclerViewReadyCallback recyclerViewReadyCallback;
public interface RecyclerViewReadyCallback {
void onLayoutReady();
}
Setzen Sie dann OnGlobalLayoutListener
auf Ihre RecyclerView
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (recyclerViewReadyCallback != null) {
recyclerViewReadyCallback.onLayoutReady();
}
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
danach müssen Sie nur noch einen benutzerdefinierten Listener mit Ihrem Code implementieren
recyclerViewReadyCallback = new RecyclerViewReadyCallback() {
@Override
public void onLayoutReady() {
//
//here comes your code that will be executed after all items are laid down
//
}
};
Wenn Sie Kotlin verwenden, gibt es eine kompaktere Lösung. Beispiel aus hier .
Dieser Layout-Listener wird normalerweise verwendet, um etwas zu tun, nachdem eine Ansicht gemessen wurde. Daher müssen Sie normalerweise warten, bis width und height größer als 0 sind.
... kann von jedem Objekt verwendet werden, das View erweitert, und kann auch auf alle seine spezifischen Funktionen und Eigenschaften vom Listener aus zugreifen.
// 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)
// ...
}
Ich habe mit dem Versuch gekämpft, OnGlobalLayoutListener
zu entfernen, sobald es ausgelöst wird, aber dies wirft eine IllegalStateException
. Da ich meine RecyclerView zum zweiten Element scrollen muss, habe ich überprüft, ob bereits Kinder vorhanden sind. Wenn dies das erste Mal ist, stimmt das.
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 jemand
(Natürlich wurde dies auf @andrino und @Phatee Antworten inspiriert)
In denselben Fällen können Sie die RecyclerView.post()
-Methode verwenden, um Ihren Code auszuführen, nachdem Listen-/Rasterelemente aufgetaucht sind. In meinen Fällen war es hübsch genug.
// 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");
}