Kuwapp's Blog

Android と Flutter やってます

【Android】Viewの階層を調べてみた

getRootViewやfindViewById(android.R.id.content)で何が取れるのか良く理解していなかったので調べてみた。

以下の記事によると
Activityのビュー階層とコンテンツルート(View)を取得する - Kazzzの日記

次のような階層になっているらしい。
PhoneWindow$Decorview

LinearLayout

FrameLayout , FrameLayout(android.R.id.content)

実際にそうなのか下記コードで確認してみた。

View contentView = findViewById(android.R.id.content);
System.out.println("contentView : " + contentView.getClass().getName() + ", id : " + contentView.getId());

ViewGroup rootView = (ViewGroup)contentView.getRootView();
System.out.println("rootView : " + rootView.getClass().getName() + ", id : " + rootView.getId());

ViewGroup rootChildView = (ViewGroup)rootView.getChildAt(0);        
System.out.println("rootChildView : " + rootChildView.getClass().getName() + ", id : " + rootChildView.getId());

for (int i = 0; i < rootChildView.getChildCount(); i++) {
            System.out.println("rootGrandChildView" + i + ": " + rootChildView.getChildAt(i).getClass().getName() + ", id : " + rootChildView.getChildAt(i).getId());
}

この結果が↓

contentView : android.widget.FrameLayout, id : 16908290
rootView : com.android.internal.policy.impl.PhoneWindow$DecorView, id : -1
rootChildView : android.widget.LinearLayout, id : -1
rootGrandChildView0: android.view.ViewStub, id : 16909171
rootGrandChildView1: android.widget.FrameLayout, id : 16908290

contentViewとrootGrandChildView1は同一IDで問題ないのだけれど
rootGrandChildView0は参考記事ではFrameLayoutがとれるはずがViewStubだった。
古い記事なので、最近のAndroidでは変更があったのかもしれない・・?
ViewStubは使うことはないだろうから、とりあえず保留。

ちなみにsetContentViewを行ったxmlの一番外側のレイアウトの親を調べると次のようになった

View parentView = findViewById(R.id.parentView);
System.out.println("parentId : " + ((View)parentView.getParent()).getId());
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parentView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</RelativeLayout>

結果↓

parentId : 16908290

先ほど取得したcontentViewのIDと同一だった。 つまり、普段レイアウトを載せてるViewはandroid.R.id.contentで取れるViewでした。

分かった事

・getRootView()で一番最上位のDecorViewが取れる
・findViewById(androd.R.id.content)でsetContentViewでViewを載せる親のViewをとれる