レイアウトとフラグメント
今回はレイアウトとフラグメントについて解説します。新しめのライブラリを使用するので、昔Androidアプリ開発をやっていた方でも楽しめるでしょう。
レイアウトXML
Androidアプリの画面はViewオブジェクトのツリーで構成されています。つまり、次のようにプログラムでViewのツリーを作れば、画面のレイアウトができることになります。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ルートとなるViewを作って
val root = LinearLayout(this)
root.orientation = LinearLayout.VERTICAL
// ラベルとなるViewを作って、ルートに追加
val text1 = TextView(this)
text1.text = "Email"
root.addView(text1)
// 入力欄を作って、ルートに追加
val emailEdit = EditText(this)
emailEdit.inputType = EditorInfo.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
root.addView(emailEdit)
// でもって、画面としてセット
setContentView(root)
}
この方法で画面レイアウトをするのはかなり大変です。Androidでは、画面レイアウトのためのXMLファイルを用意し、それを読み込む方法を主に使用します。このXMLファイルをレイアウトXMLと呼び、res/layoutフォルダの中に配置します。
Android Studioが自動で作成するレイアウトXMLを示します。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
要素名で部品を表し、属性で大きさや配置方法などを指定します。子供を持つことのできるView(ViewGroupと呼びます)の場合、子供となるViewは子要素として記述します。
レイアウトエディタ
Android StudioでレイアウトXML(activity_main.xml)を開くと、レイアウトエディタが表示されます。詳しい使い方は次回説明します。現時点では、エディタの左上にPaletteというウィンドウがあり、そこに画面の部品があるという認識で大丈夫です。

フラグメント
画面のレイアウトをするには、レイアウトXMLを書き、アクティビティのsetContentView()で指定すればよいことがわかりました。しかし、「アクティビティはAndroid OSがオブジェクトを生成して使うもの」というルールがあるため、別の画面の一部として使うようなことができません。
そこで登場したのがフラグメントという仕組みです。Android 3(2011年)で登場しましたが、学習コストの高さや、アプリの構造自体を見直す必要などから敬遠しているエンジニアもいました。また、画面レイアウトの方法を学ぶだけならフラグメントを使わずに学ぶこともできるため、初心者向けの書籍などでは説明がなかったりもします。
「原理はこうですが、実際はこのライブラリを使います」といった、遠回りの説明を避けるため、本ブログではフラグメントを用いた画面レイアウト方法を最初から説明します。
フラグメントを使う場合、アクティビティのレイアウトには「どこにフラグメントを貼り付けるか」だけを記述します。フラグメントが登場した当初はFrameLayoutという部品を使いましたが、2018年のGoogle I/Oでナビゲーションというライブラリが登場し、NavHostFragmentという部品が追加されました。
NavHostFragmentを追加する
早速、activity_main.xmlを開き、レイアウトにNavHostFragmentを追加してみましょう。左上のPaletteのところで「NavHost」ぐらいまでを入力し、NavHostFragmentを探します。見つかったらエディタ中央部分に表示されている画面にドラッグ&ドロップします。

すると、Navigation Graphsを選ぶウィンドウが表示されます。もちろんそんなものは作っていないので、右上のAdd new resourceをクリックし追加します。

ファイル名を説明のためにnav_mainとし、右下のOKでNavigation Graphファイルを作ります。これでNavHostFragmentが追加できました。

最初から画面に配置されているTextViewは邪魔なので、Paletteの下にあるComponent TreeでTextViewを選び、右クリック→deleteで消してしまいましょう。

フラグメントを追加する
ようやくアクティビティ側の準備が完了しました。次に画面となるフラグメントを追加しましょう。いくつか方法がありますが、今回はNavigation Graph経由で作成してみましょう。
先ほど、activity_main.xmlで画面にNavHostFragmentを貼り付けました。貼り付けたNavHostFragmentをダブルクリックしてみましょう。最初は何も表示されず、次のようなダイアログが表示されます。「ナビゲーションという仕組みを使うためにライブラリを追加しますか?」という意味なのでOKを押して追加します。NavHostFragmentを画面に貼った時点で出してほしい気もしますが、気にしたら負けです。

ライブラリの追加が終わると次のような画面が表示されます。これはナビゲーションエディタで、Android Studio 3.3で追加されました。

画面上部にあるをクリックすると、画面(フラグメント)の追加ができます。Create new destinationを選びましょう。

するとフラグメントを追加するダイアログが表示されます。フラグメントの名前を決め、「include fragment factory methods?」と「include interface callbacks?」のチェックを外します。最後に右下のOKボタンをクリックし、フラグメントを追加します。新しいフラグメントを追加すると、.ktファイルと、その中で読み込まれるレイアウトXMLがプロジェクトに追加されます。余談ですが、ダイアログではAPI 4から使えるフラグメントの追加に見えます。しかし実際はAPI 14以降でしか動作しません。

ここまでできたら、一度アプリを実行してみましょう。Hello blank fragmentが表示されていればOKです。

まとめ
レイアウトXMLの役割と、フラグメントを追加することでアプリに画面を追加する方法を説明しました。アプリに画面を追加する方法はAndroidの進化とともに変化しているので、なるべく最新の方法を学び、使うようにしていきましょう。