androidアプリ作成時のメモです。
1007 views
簡単なandroidのプログラムでは、EditViewなどをMainActivityのレイアウトに記述して表示します。
この方法の問題として、画面の構成が決め打ちになってしまい、データに応じて入力項目を変更することができません。
本章では、レイアウトを動的に変更する方法について説明します。
実現したい内容は、以下の図のとおりです。
activitymain.xmlの中にLinearLayoutを作成し、さらにその下にLinearLayoutを作成します。
二つ目のLinearLayoutには、childlayout1.xmlの内容とchildlayout2.xmlの内容をプログラムから動的に追加できるようにします。
例では、childlayout1.xmlには項目名に「名前」を表示し、EditViewには名前を入力できるようにします。
同様にchildlayout2.xmlには項目名に「パスワード」を表示し、EditViewにパスワードを入力できるようにします。
最後にButtonを押すと、childlayout1とchild_layout2に入力された内容をトーストで表示します。
なお、childlayout1、childlayout2からの値の取得はバインディングを用いて取得します。
バインディングについては、他のページに記載しているのでそちらを参考にしてください。
本章では、コードの解説を記載します。
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行目でchildlayout1.xmlのレイアウトを読み込みます。
27行目、28行目はchildlayout1に使用するviewmodelの値をセットしています。
29行目でchildlayout1が使用するviewModelをセットします。
31行目が肝です。
上述の図、子供のLinearLayoutの中にあるLinearLayoutのidをinnerLayoutとしています。
このinnerLayoutに、childlayout1を追加します。
35行目~41行目
26行目~31行目とやっていることは同じです。
childlayout1の代わりにchildlayout2が追加されています。
44行目~48行目
ボタンをクリックしたときの処理を記述しています。
45行目はchildlayout1.xmlにバインディングしているchildViewModel1からデータを取得しています。
46行目はchildlayout2.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。
ChatGPTで自動プログラム作成に取り組み中。
https://www.osumoi-stdio.com/novel/