wake-up-neo.com

Woher weiß man, wann der RecyclerView die Gegenstände fertig gelegt hat?

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.

39
wm1sr

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);
                        }
                    });
44
andrino

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
                 //
             }
};
26
Phatee P

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)
    // ...
}    
2
Gregory

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)

2
Eliseo Ocampos

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.

1
PavelGP
// 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");
}
0
deni5n