android

androidアプリ作成時のメモです。

734 views

概要

簡単なandroidのプログラムでは、EditViewなどをMainActivityのレイアウトに記述して表示します。
この方法の問題として、画面の構成が決め打ちになってしまい、データに応じて入力項目を変更することができません。

本章では、レイアウトを動的に変更する方法について説明します。

実現したい内容は、以下の図のとおりです。
activity_main.xmlの中にLinearLayoutを作成し、さらにその下にLinearLayoutを作成します。
二つ目のLinearLayoutには、child_layout1.xmlの内容とchild_layout2.xmlの内容をプログラムから動的に追加できるようにします。
例では、child_layout1.xmlには項目名に「名前」を表示し、EditViewには名前を入力できるようにします。
同様にchild_layout2.xmlには項目名に「パスワード」を表示し、EditViewにパスワードを入力できるようにします。
最後にButtonを押すと、child_layout1とchild_layout2に入力された内容をトーストで表示します。

なお、child_layout1、child_layout2からの値の取得はバインディングを用いて取得します。
バインディングについては、他のページに記載しているのでそちらを参考にしてください。

コード解説

本章では、コードの解説を記載します。

MainActivity.kt

package com.example.myapplication

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import com.example.myapplication.databinding.ActivityMainBinding
import com.example.myapplication.databinding.ChildLayout1Binding
import com.example.myapplication.databinding.ChildLayout2Binding
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private val childViewModel1 = Child1ViewModel()
    private val childViewModel2 = Child2ViewModel()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //親レイアウトのバインディング作成
        val parentBinding: ActivityMainBinding = DataBindingUtil.setContentView(
                this, R.layout.activity_main
        )

        //子レイアウト1のバインディング作成
        val childLayout1 : ChildLayout1Binding = DataBindingUtil.inflate(layoutInflater, R.layout.child_layout1, null, false)
        childViewModel1.title.set("名前")
        childViewModel1.text.set("名前を入力してください")
        childLayout1.viewmodel = childViewModel1

        //親が持つinnnerViewに子ウインドウを追加する
        parentBinding.innerLayout.addView(childLayout1.root)

        //子レイアウト2のバインディング作成
        val childLayout2 : ChildLayout2Binding = DataBindingUtil.inflate(layoutInflater, R.layout.child_layout2, null, false)
        childViewModel2.title.set("パスワード")
        childViewModel2.text.set("")
        childLayout2.viewmodel = childViewModel2

        //親が持つinnnerViewに子ウインドウを追加する
        parentBinding.innerLayout.addView(childLayout2.root)


        button.setOnClickListener {
            val text1 = childViewModel1.text.get()
            val text2 = childViewModel2.text.get()
            Toast.makeText(this, "child1:${text1}, child2:${text2}", Toast.LENGTH_SHORT).show()
        }
    }
}

26行目~31行目
26行目でchild_layout1.xmlのレイアウトを読み込みます。
27行目、28行目はchild_layout1に使用するviewmodelの値をセットしています。
29行目でchild_layout1が使用するviewModelをセットします。
31行目が肝です。
上述の図、子供のLinearLayoutの中にあるLinearLayoutのidをinnerLayoutとしています。
このinnerLayoutに、child_layout1を追加します。

35行目~41行目
26行目~31行目とやっていることは同じです。
child_layout1の代わりにchild_layout2が追加されています。

44行目~48行目
ボタンをクリックしたときの処理を記述しています。
45行目はchild_layout1.xmlにバインディングしているchildViewModel1からデータを取得しています。
46行目はchild_layout2.xmlにバインディングしているchildViewModel2からデータを取得しています。
そして47行目でトーストで取得した値を表示します。

次にactivity_main.xmlを見てみます。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

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

        <LinearLayout
            android:id="@+id/innerLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <!--ここに子供のレイアウトを追加していく -->
        </LinearLayout>

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="保存する" />
    </LinearLayout>

</layout>

12行目~18行目が、子レイアウトを追加するLinearLayoutです。このidを13行目でIDに「"@+id/innerLayout"」を指定しています。
さらに、20行目では親レイアウトにbuttonを配置しています。

child_layout1.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="viewmodel"
            type="com.example.myapplication.Child1ViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">


        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewmodel.title}" />

        <EditText
            android:id="@+id/text1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={viewmodel.text}"
            />
    </LinearLayout>


</layout>

5行目~9行目
Child1ViewModelにバインドしています。

17行目~21行目
「名前」を表示するためのTextViewです。MainActivity.ktの27行目のコードによって「名前」が指定されています。

23行目~27行目
名前を入力するためのEditTextです。MainActivity.ktの28行目のコードによって「名前を入力してください」という文字列が初期値として与えられます。

Child1ViewModelは、次のとおりです。
**ChildViewModel1.kt

package com.example.myapplication

import android.util.Log
import androidx.databinding.ObservableField
import androidx.lifecycle.ViewModel

class Child1ViewModel : ViewModel() {
    var title = ObservableField<String>()
    var text = ObservableField<String>()
}

8行目は、項目名をデータバインディングするためのフィールド、9行目はデータをデータバインディングするためのフィールドを定義しています。

child_layout2.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="viewmodel"
            type="com.example.myapplication.Child2ViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">


        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewmodel.title}" />

        <EditText
            android:id="@+id/text1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={viewmodel.text}"
            android:inputType="textPassword" />

    </LinearLayout>


</layout>

5行目~9行目
Child2ViewModelにバインドしています。

17行目~21行目
「パスワード」を表示するためのTextViewです。MainActivity.ktの27行目のコードによって「パスワード」が指定されています。

23行目~27行目
パスワードを入力するためのEditTextです。MainActivity.ktの28行目のコードによって""が初期値として与えられます。

package com.example.myapplication

import android.util.Log
import androidx.databinding.ObservableField
import androidx.lifecycle.ViewModel

class Child2ViewModel : ViewModel() {
    var title = ObservableField<String>()
    var text = ObservableField<String>()
}

8行目は、項目名をデータバインディングするためのフィールド、9行目はパスワードをデータバインディングするためのフィールドを定義しています。

実行結果

動的にレイアウトが追加されました。

Page 14 of 19.

前のページ 次のページ



[添付ファイル]


お問い合わせ

プロフィール

マッスル

自己紹介

本サイトの作成者。
趣味:プログラム/水耕栽培/仮想通貨/激辛好き
プログラムは趣味と勉強を兼ねて、のんびり本サイトを作っています。
フレームワークはdjango。
仮想通貨はNEMが好き。
水耕栽培は激辛好きが高じて、キャロライナ・リーパーの栽培にチャレンジ中。

サイト/ブログ

https://www.osumoi-stdio.com/pyarticle/

ツイッター

@darkimpact0626