Android – 画面要素の階層構造を取得する

投稿者: | 2019年2月2日

Android開発をしていて、画面上で少し複雑な構造を動的に追加していくと、要素の階層構造を取得したくなることがあります。

今回は画面上に表示されている要素の階層構造を取得するプログラムを作成してみます。

 

やりたいことは、次のような画面で、「追加」ボタンを押す度に赤枠部分が動的に追加され、その都度、要素の階層構造をログに表示することです。

 

追加される要素群には、テキストフィールド、ラジオボタン、チェックボックスを設けました。

 

まず、string.xmlで画面文言を定義。

<resources>
    <string name="app_name">NestLayoutSample</string>
    <string name="header_message">ボタンを押すと要素グループを追加します</string>
    <string name="etName">お名前</string>
    <string name="cb_train">電車</string>
    <string name="cb_car">バス</string>
    <string name="cb_plane">飛行機</string>
    <string name="rb_male">男</string>
    <string name="rb_female">女</string>
    <string name="bt_add">追加</string>
</resources>

 

次にメインのレイアウトを定義します。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/et_Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/header_message"
        android:textSize="20dp"/>

    <View
        android:layout_width="fill_parent"
        android:layout_height="1dp"
        android:background="@android:color/darker_gray"/>

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="32dp">

        <LinearLayout
            android:id="@+id/root"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <Button
                android:id="@+id/button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/bt_add" />

        </LinearLayout>
    </ScrollView>

</LinearLayout>

 

そして「追加」ボタンを押す度に追加される要素群を、別のレイアウトxmlで定義します。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:textSize="15dp"
            android:text="@string/etName"/>
        <EditText
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15dp"
            android:text="@string/cb_train"/>
        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15dp"
            android:text="@string/cb_car"/>
        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15dp"
            android:text="@string/cb_plane"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <RadioGroup
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15dp"
            android:text="@string/rb_male"/>
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15dp"
            android:text="@string/rb_female"/>
    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@android:color/darker_gray"/>

</LinearLayout>

 

最後にActivityコード。Logcatに文字列が表示されるようにしています。

public class MainActivity extends AppCompatActivity {

    private LinearLayout rootView;
    private LayoutInflater inflater;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rootView = findViewById(R.id.root);
        inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        Button b = findViewById(R.id.button);
        SampleListener sl = new SampleListener();
        b.setOnClickListener(sl);

    }

    private class SampleListener implements View.OnClickListener {

        @Override
        public void onClick(View view) {
            View subView = inflater.inflate(R.layout.sub, null);
            rootView.addView(subView, rootView.getChildCount() - 1);

            // Viewの階層構造を取得しLogに表示する
            StringBuilder sb = new StringBuilder();
            storeViewClassName(rootView, sb, "\t");
            Log.i(this.getClass().getName().toString() + "-->\n", "\n" + sb.toString());
        }

        // Viewの階層構造をStringBuilderに格納する
        private void storeViewClassName (View v, StringBuilder sb, String tab) {
            sb.append(tab).append(v.getClass().getSimpleName()).append("\n");
            if (v instanceof ViewGroup) {
                for (int i = 0; i < ((ViewGroup) v).getChildCount() ; i++) {
                    storeViewClassName(((ViewGroup) v).getChildAt(i), sb, tab + "\t");
                }
            }
        }
    }

}

 

初期画面はこんな感じ。ここからスタートします。

 

「追加」ボタンを一回押したとき。要素が追加されると共に、Logcatに要素名が表示されています。

    	LinearLayout
    		LinearLayout
    			LinearLayout
    				AppCompatTextView
    				AppCompatEditText
    			LinearLayout
    				AppCompatCheckBox
    				AppCompatCheckBox
    				AppCompatCheckBox
    			LinearLayout
    				RadioGroup
    				AppCompatRadioButton
    				AppCompatRadioButton
    			View
    		AppCompatButton

 

さらにもう一度「追加」ボタンを押すと、再度要素追加が行われ、Logcatに現れる階層構造も一つ増えています。

    	LinearLayout
    		LinearLayout
    			LinearLayout
    				AppCompatTextView
    				AppCompatEditText
    			LinearLayout
    				AppCompatCheckBox
    				AppCompatCheckBox
    				AppCompatCheckBox
    			LinearLayout
    				RadioGroup
    				AppCompatRadioButton
    				AppCompatRadioButton
    			View
    		LinearLayout
    			LinearLayout
    				AppCompatTextView
    				AppCompatEditText
    			LinearLayout
    				AppCompatCheckBox
    				AppCompatCheckBox
    				AppCompatCheckBox
    			LinearLayout
    				RadioGroup
    				AppCompatRadioButton
    				AppCompatRadioButton
    			View
    		AppCompatButton