web-dev-qa-db-ja.com

RecyclerViewがアイテムの配置を完了したことを知る方法は?

RecyclerViewの中にCardViewがあります。 CardViewの高さは500dpですが、RecyclerViewが小さい場合はこの高さを短くします。 RecyclerViewが初めてアイテムの配置を終了し、RecyclerViewの高さをCardViewの高さに設定できるようになったときに呼び出されるリスナーがあるかどうか500dpより小さい場合)。

49
wm1sr

また、リサイクラービューがすべての要素を膨らませた後にコードを実行する必要がありました。位置が最後である場合、アダプターでonBindViewHolderをチェックインしてから、オブザーバーに通知しました。しかし、その時点では、リサイクル業者の見解はまだ完全には定着していませんでした。

RecyclerViewViewGroupを実装しているので、 this anwser は非常に役に立ちました。 recyclerViewに OnGlobalLayoutListener を追加するだけです。

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

@andrino anwserの作業修正。

@Juanchoが上記のコメントで指摘したように。このメソッドは数回呼び出されます。この場合、一度だけトリガーされるようにします。

インスタンスを使用してカスタムリスナーを作成します。

private RecyclerViewReadyCallback recyclerViewReadyCallback;

public interface RecyclerViewReadyCallback {
    void onLayoutReady();
}

次に、OnGlobalLayoutListenerRecyclerViewを設定します

recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (recyclerViewReadyCallback != null) {
                    recyclerViewReadyCallback.onLayoutReady();
                }
                recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });

その後、コードでカスタムリスナーを実装するだけです

recyclerViewReadyCallback = new RecyclerViewReadyCallback() {
             @Override
             public void onLayoutReady() {
                 //
                 //here comes your code that will be executed after all items are laid down
                 //
             }
};
32
Phatee P

Kotlinを使用する場合、よりコンパクトなソリューションがあります。 here のサンプル。

... Viewを拡張する任意のオブジェクトで使用でき、リスナーから特定のすべての機能とプロパティにアクセスすることもできます。

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

一度トリガーされたらOnGlobalLayoutListenerを削除しようとして苦労していますが、IllegalStateExceptionがスローされます。私が必要なのは、recyclerViewを2番目の要素にスクロールすることで、すでに子供がいるかどうかを確認することであり、これが初めての場合は、スクロールするだけです:

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
    }
}

誰か!

(もちろん、これは@andrinoと@Phateeの回答に触発されました)

2
Eliseo Ocampos

また、同じ場合には、リスト/グリッド項目がポップアップされた後、RecyclerView.post()メソッドを使用してコードを実行できます。私の場合、それで十分でした。

1
PavelGP