1. 始める前に
この Codelab では、簡単なチップ計算アプリのレイアウトを作成します。Codelab の最後にはアプリの UI が機能するようになりますが、チップの計算はまだ行えません。後続の Codelab で実際にアプリを動作させ、デザインをより洗練されたものにしていきます。
前提条件
- Android Studio でテンプレートから Android アプリを作成して実行できること
学習内容
- Android での XML レイアウトの読み取りおよび書き込み方法
- ユーザーのテキスト入力と選択を受け取る簡単なフォーム用のレイアウトを作成する方法
作成するアプリの概要
- チップ計算用 Android アプリの UI
必要なもの
- Android Studio の最新の安定版がインストールされているパソコン
- Android デベロッパー向けドキュメントにアクセスするためのインターネット接続
2. プロジェクトを開始する
Google でチップ計算ツール(https://www.google.com/search?q=tip+calculator)をご覧ください。

ここでは、チップ計算ツールの簡易版を Android アプリとして作成します。
デベロッパーは多くの場合、このようにアプリの簡易版を作成し、一部の機能が動作することを確認したうえで、完全な機能を実装してデザインを洗練されたものにします。
この Codelab を終了する時点では、チップ計算アプリは次のようになります。

Android で用意されている次の UI 要素を使用します。
EditText- テキストの入力と編集TextView- サービスに関する質問やチップ金額などのテキストの表示RadioButton- チップ オプション用の選択可能なラジオボタンRadioGroup- ラジオボタン オプションのグループ化Switch- チップを切り上げるかどうかのオン / オフの切り替え
Empty Activity プロジェクトを作成する
- まず、Android Studio で Empty Activity テンプレートを使用して新しい Kotlin プロジェクトを作成します。
- アプリの名前を「Tip Time」とし、最小 API レベルに 19(KitKat)を選びます。パッケージ名は com.example.tiptime です。
![詳細が入力されている [New Project] ペイン 4f7619e9faff20e9.png](https://developer.android.com/static/codelabs/basic-android-kotlin-training-xml-layouts/img/4f7619e9faff20e9.png?authuser=002&hl=ja)
- [Finish] をクリックして、アプリを作成します。
3.XML を読んで理解する
使い慣れている Layout Editor を使用する代わりに、UI が記述されている XML を変更することによって、アプリのレイアウトを作成します。XML を使用して UI レイアウトを理解し、修正する方法を学ぶことは、Android デベロッパーにとって重要です。
このアプリの UI レイアウトが定義されている XML ファイルを確認して編集します。XML は「拡張マークアップ言語(eXtensible Markup Language)」の略であり、テキストベースのドキュメントを使用してデータを記述する方法のひとつです。XML は拡張可能で柔軟性が高いため、Android アプリの UI レイアウトの定義など、さまざまな用途に使用されます。前の Codelab で説明したとおり、アプリの文字列などの他のリソースも、strings.xml という XML ファイルで定義されています。
Android アプリの UI は、コンポーネント(ウィジェット)の包含階層と、それらのコンポーネントの画面レイアウトとして作成されます。これらのレイアウトは UI コンポーネントそのものであることに注意してください。
画面上の UI 要素のビュー階層を記述します。たとえば、ConstraintLayout(親)には、Buttons、TextViews、ImageViews などのビュー(子)を含めることができます。ConstraintLayout は ViewGroup のサブクラスであり、これを使用して子ビューの配置やサイズ調整を柔軟に行うことができます。

Android アプリの包含階層

各 UI 要素は、XML ファイルの XML 要素で表されます。各要素の開始と終了はタグで示され、各タグは < で始まり > で終わります。Layout Editor(Design)を使用して UI 要素の属性を設定するのと同じように、XML 要素にも属性を設定できます。上記の UI 要素の XML は、簡略化すると次のようになります。
<ConstraintLayout>
<TextView
text="Hello World!">
</TextView>
</ConstraintLayout>

具体的な例を見てみましょう。
activity_main.xmlを開きます([res] > [layout] > [activity_main.xml])。- このテンプレートから作成した以前のプロジェクトと同様に、アプリの
ConstraintLayout内に「Hello World!」というTextViewが表示されます。

- Layout Editor の右上で、[Code]、[Split]、[Design] の各ビューを選択できるようになっています。
- [Code] ビューを選択します。

activity_main.xml の XML は次のようになります。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
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>
簡略化された例に比べると分量は多くなっていますが、Kotlin コードの場合と同様に、XML を読みやすくするための処理が行われています。
- インデント。Android Studio は、要素の階層を示すためにインデントを自動的に行います。
TextViewはConstraintLayoutに含まれているため、インデントされています。ConstraintLayoutが親で、TextViewは子です。各要素の属性がインデントされて、その要素の一部であることが示されます。 - 色分け(青や緑など)。ファイルの類似部分は同じ色で描画されるため、マッチングしやすくなります。特に、Android Studio では要素のタグの開始と終了が同じ色で描画されます(注: Codelab で使用されている色は、Android Studio に表示される色と一致しない場合があります)。
XML タグ、要素、属性
ここでは TextView 要素を簡略化し、重要な部分を確認できるようにしています。
<TextView
android:text="Hello World!"
/>
<TextView の行がタグの先頭、/> の行がタグの末尾です。android:text="Hello World!" の行はタグの属性で、TextView によって表示されるテキストを表します。この 3 行は空要素タグと呼ばれる短縮形で、よく使用されます。次のように開始タグと終了タグを別々に記述した場合も、同じ意味になります。
<TextView
android:text="Hello World!"
></TextView>
また、空要素タグはできるだけ少ない行数で記述し、タグの末尾を前の行と結合するのが一般的です。そのため、空要素タグが 2 行(属性がない場合は 1 行)で記述されていることもあります。
<!-- with attributes, two lines -->
<TextView
android:text="Hello World!" />
ConstraintLayout 要素は、中に他の要素を入れる必要があるため、開始タグと終了タグを別々に記述します。ConstraintLayout 要素とその中の TextView 要素を簡略化した例を次に示します。
<androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:text="Hello World!" />
</androidx.constraintlayout.widget.ConstraintLayout>
別の View を ConstraintLayout の子として追加する場合(TextView の下に Button を追加する場合など)、次のように、TextView タグの末尾 /> と ConstraintLayout の終了タグの間に配置します。
<androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:text="Hello World!" />
<Button
android:text="Calculate" />
</androidx.constraintlayout.widget.ConstraintLayout>
レイアウト用の XML の詳細
ConstraintLayoutのタグを見ると、TextViewのように単に「ConstraintLayout」ではなく、「androidx.constraintlayout.widget.ConstraintLayout」と記述されています。これは、ConstraintLayoutが Android Jetpack の一部であるためです。Jetpack には、基盤となる Android プラットフォーム上で追加の機能を提供するコードのライブラリが含まれています。Jetpack には、アプリを簡単に作成できる便利な機能が用意されています。この UI コンポーネントは「androidx」で始まっているので、Jetpack の一部だとわかります。- 次のように
xmlns:で始まり、その後にandroid、app、toolsが続く行があります。
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns は XML 名前空間を表し、各行はスキーマ(これらの単語に関連する属性の語彙)を定義しています。たとえば、android: 名前空間は、Android システムによって定義されている属性を示します。レイアウト XML のすべての属性が、それらの名前空間のいずれかで始まります。
- XML 要素間に空白文字があることで、コンピュータにとっての意味は変わりませんが、人間にとって XML が読みやすくなります。
Android Studio では、読みやすくなるように自動的に空白文字とインデントが追加されます。Android Studio で XML がコーディング スタイル規則に準拠していることを確認する方法については、後ほど説明します。
- Kotlin コードの場合と同様に、XML にもコメントを追加できます。コメントは
<!--で開始し、-->で終了します。
<!-- this is a comment in XML -->
<!-- this is a
multi-line
Comment.
And another
Multi-line comment -->
- ファイルの 1 行目に注目してください。
<?xml version="1.0" encoding="utf-8"?>
これは、ファイルが XML ファイルであることを示していますが、すべての XML ファイルにこれが含まれているわけではありません。
4. XML でレイアウトを作成する
activity_main.xmlで [Split] 画面ビューに切り替えると、Design Editor の横に XML が表示されます。Design Editor を使用すると、UI レイアウトをプレビューできます。
![Design Editor で [Split] ビューが選択されているタブ a03bcf5beacb4b45.png](https://developer.android.com/static/codelabs/basic-android-kotlin-training-xml-layouts/img/a03bcf5beacb4b45.png?authuser=002&hl=ja)
- 好みに応じてどのビューを使用しても構いませんが、この Codelab では、XML を編集しながらその変更結果を Design Editor で確認できるように、[Split] ビューを使用します。
ConstraintLayoutの下の行をクリックし、その後TextViewの下の行をクリックして、Design Editor で対応するビューが選択されることを確認します。逆も同様で、たとえば、Design Editor でTextViewをクリックすると、対応する XML がハイライト表示されます。
![Android Studio で [Split] ビュー(分割されたペイン)に activity_main.xml が表示されている 1abc54a646c39f66.png](https://developer.android.com/static/codelabs/basic-android-kotlin-training-xml-layouts/img/1abc54a646c39f66.png?authuser=002&hl=ja)
TextView を削除する
- ここでは
TextViewは不要なため、削除します。<TextViewから終了タグの/>まで、すべての内容を削除してください。
<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" />
ファイルに残っているのは ConstraintLayout だけになります。
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
- UI と画面の端の間に余裕を持たせるために、
ConstraintLayoutに 16 dp のパディングを追加します。
パディングは余白に似ていますが、ConstraintLayout の外側ではなく内側にスペースを追加します。
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
サービス料金のテキスト フィールドを追加する
このステップでは、ユーザーがアプリにサービス料金を入力できる UI 要素を追加します。EditText 要素を使用して、ユーザーがアプリでテキストを入力または変更できるようにします。

EditTextのドキュメントを参照し、サンプル XML を確認します。ConstraintLayoutの開始タグと終了タグの間にある空白を見つけます。- ドキュメントから XML をコピーして、Android Studio のレイアウトの該当領域に貼り付けます。
レイアウト ファイルは次のようになります。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/plain_text_input"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:inputType="text"/>
</androidx.constraintlayout.widget.ConstraintLayout>
まだ理解できない部分があるかもしれませんが、それについては後のステップで説明します。
EditTextに赤い下線が表示されます。- 下線部分にカーソルを合わせると、「ビューに制約が設定されていない」というエラーが表示されます。前の Codelab で説明したように、
ConstraintLayoutの子には制約を設定する必要があります。これにより、レイアウトが子の配置方法を理解できるようになります。

- 次の制約を
EditTextに追加して、親の左上に固定します。
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
英語など、左から右に記述する(LTR)言語の場合は、始端が左になります。しかし、アラビア語などの一部の言語は右から左に記述する(RTL)ので、始端は右になります。そのため、制約では「start」を使用し、LTR 言語と RTL 言語の両方で機能するようにしています。同様に、制約では right ではなく「end」を使用します。
新しい制約を追加すると、EditText 要素は次のようになります。
<EditText
android:id="@+id/plain_text_input"
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:inputType="text"/>
EditText の属性を確認する
貼り付けた EditText のすべての属性をもう一度確認して、アプリで適切に機能するようにします。
@+id/plain_text_inputに設定されているid属性を探します。id属性をより適切な名前(@+id/cost_of_service)に変更します。
layout_height属性はwrap_contentに設定されています。これは、高さが内部のコンテンツと同じになることを意味します。ここでは 1 行のテキストしか表示されないため、この設定で問題ありません。layout_width属性はmatch_parentに設定されていますが、ConstraintLayoutの子にmatch_parentを設定することはできません。また、テキスト フィールドの幅はそれほど必要がないため、160dpの固定幅に設定します。これで、ユーザーがサービス料金を入力するのに十分なスペースを確保できます。

- ここで新たに
inputType属性に注目します。この属性の値は"text"であるため、ユーザーは画面上のフィールドに任意のテキスト(アルファベット、記号など)を入力できます。
android:inputType="text"
しかし、このフィールドは金額を表すため、EditText には数値のみを入力してもらう必要があります。
- 「
text」という単語を削除し、引用符はそのままにします。 - 代わりに「
number」と入力します。「n」と入力すると、「n」を含む候補のリストが表示されます。

numberDecimalを選択します。これにより、入力できる値は小数点を含む数値のみに制限されます。
android:inputType="numberDecimal"
入力タイプのその他のオプションについては、デベロッパー向けドキュメントの入力方法のタイプの指定をご覧ください。
さらに変更を加えて、このフィールドに何を入力すべきかを示すヒントが表示されるようにしましょう。
EditTextに、このフィールドに入力する内容を説明するためのhint属性を追加します。
android:hint="Cost of Service"
Design Editor も更新されます。

- エミュレータでアプリを実行すると、次のようになります。

これで、アプリはまだ完全には動作しませんが、XML の編集については良いスタートを切ることができました。レイアウトの XML は次のようになります。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:hint="Cost of Service"
android:inputType="numberDecimal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
サービスに関する質問を追加する
このステップでは、「How was the service?」という質問のプロンプトの TextView を追加します。これをコピー&ペーストせずに直接入力すると、Android Studio に候補が表示されます。
EditTextタグの末尾の/>の後に新しい行を追加して、<TextViewの入力を始めます。- 候補から
TextViewを選択すると、TextViewのlayout_width属性とlayout_height属性が Android Studio によって自動的に追加されます。 - いずれの属性についても
wrap_contentを選択します。TextViewは内部のテキスト コンテンツと同じ大きさであれば十分であるためです。
text属性を追加し、"How was the service?"と指定します。
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="How was the service?"
/>でタグを閉じます。- Design Editor で確認すると、
TextViewがEditTextに重なっています。

次に、これが適切に表示されるよう TextView に制約を追加しましょう。この場合、どのような制約が必要になるか考えてみてください。TextView は、水平方向と垂直方向で、それぞれどこに配置すべきでしょうか?次に示すアプリのスクリーンショットを参考にしてください。

垂直方向については、TextView をサービス料金のテキスト フィールドの下に配置します。水平方向については、TextView を親の始端に揃えます。
TextViewに水平方向の制約を追加して、その始端と親の始端の間に制約を設定します。
app:layout_constraintStart_toStartOf="parent"
TextViewに垂直方向の制約を追加して、TextViewの上端とサービス料金Viewの下端の間に制約を設定します。
app:layout_constraintTop_toBottomOf="@id/cost_of_service"
ID はすでに定義されているため、@id/cost_of_service には何も追加しません。

見た目は洗練されていませんが、現時点では問題ありません。ここでは必要なすべての要素が画面に表示され、機能が正しく動作することだけを確認してください。デザインについては次の Codelab で修正します。
TextViewにリソース ID を追加します。後でビューを追加し、ビュー同士で制約を適用する際に、このビューを参照する必要があります。
android:id="@+id/service_question"
この時点で、XML は次のようになります。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:hint="Cost of Service"
android:layout_height="wrap_content"
android:layout_width="160dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:inputType="numberDecimal"/>
<TextView
android:id="@+id/service_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="How was the service?"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cost_of_service"/>
</androidx.constraintlayout.widget.ConstraintLayout>
5. チップ オプションを追加する
次に、ユーザーが選択できる各チップ オプションに対応するラジオボタンを追加します。
次の 3 つのオプションを設定します。
- Amazing(20%)
- Good(18%)
- Okay(15%)
設定方法がわからない場合は、Google で検索してください。Google 検索は、デベロッパーが行き詰ったときに使用できる優れたツールです。
- Google で「
radio button android」を検索します。検索結果の最上位に、Android デベロッパー サイトのラジオボタンの使用に関するガイドが表示されます。

- ラジオボタンに関するガイドに目を通します。
説明を読むと、必要なラジオボタンのレイアウトごとに RadioButton UI 要素を使用できることがわかります。また、一度に選択できるオプションは 1 つのみであるため、RadioGroup 内のラジオボタンもグループ化する必要があります。
このニーズに合うと思われる XML があります。説明を最後まで読むと、RadioGroup が親ビューで、RadioButtons がその子ビューであることがわかります。
- Android Studio のレイアウトに戻り、
RadioGroupとRadioButtonをアプリに追加します。 ConstraintLayout内のTextView要素の後で、<RadioGroupの入力を開始します。XML を完成させるのに便利な候補が Android Studio に表示されます。
RadioGroupのlayout_widthとlayout_heightをwrap_contentに設定します。- リソース ID を追加し、
@+id/tip_optionsに設定します。 >で開始タグを閉じます。- Android Studio が
</RadioGroup>を追加します。ConstraintLayoutと同様に、RadioGroup要素内には他の要素も配置されるため、この終了タグを別個の行に移動することをおすすめします。
RadioGroupと、サービスに関する質問の下端の間(垂直方向)、および親の始端との間(水平方向)に制約を設定します。android:orientation属性をverticalに設定します。RadioButtonsを横 1 列に並べるには、向きをhorizontalに設定します。
RadioGroup の XML は次のようになります。
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/service_question">
</RadioGroup>
RadioButton を追加する
RadioGroupの最後の属性と</RadioGroup>終了タグの間に、RadioButtonを追加します。
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/service_question">
<!-- add RadioButtons here -->
</RadioGroup>
layout_widthとlayout_heightをwrap_contentに設定します。@+id/option_twenty_percentのリソース ID をRadioButtonに割り当てます。- テキストを
Amazing (20%)に設定します。 />でタグを閉じます。
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/service_question"
app:layout_constraintStart_toStartOf="parent"
android:orientation="vertical">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amazing (20%)" />
</RadioGroup>

これで RadioButton を 1 つ追加できたので、この XML を編集し、Good (18%) と Okay (15%) 用としてラジオボタンをさらに 2 つ追加してみましょう。
RadioGroup と RadioButtons の XML は次のようになります。
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/service_question"
app:layout_constraintStart_toStartOf="parent"
android:orientation="vertical">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amazing (20%)" />
<RadioButton
android:id="@+id/option_eighteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Good (18%)" />
<RadioButton
android:id="@+id/option_fifteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Okay (15%)" />
</RadioGroup>

デフォルトの選択を追加する
チップ オプションは現在選択されていませんが、デフォルトでラジオボタンを 1 つ選択することをおすすめします。
RadioGroup に、最初にチェックするボタンを指定する属性があります。これは checkedButton と呼ばれ、選択するラジオボタンのリソース ID にこの属性を設定します。
RadioGroupで、android:checkedButton属性を@id/option_twenty_percentに設定します。
<RadioGroup
android:id="@+id/tip_options"
android:checkedButton="@id/option_twenty_percent"
...
Design Editor でレイアウトが更新され、デフォルトで 20% のチップが選択されています。だんだんチップ計算ツールらしくなってきました。

ここまでの XML は次のようになります。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:hint="Cost of Service"
android:layout_height="wrap_content"
android:layout_width="160dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:inputType="numberDecimal"/>
<TextView
android:id="@+id/service_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="How was the service?"
app:layout_constraintTop_toBottomOf="@id/cost_of_service"
app:layout_constraintStart_toStartOf="parent" />
<RadioGroup
android:id="@+id/tip_options"
android:checkedButton="@id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/service_question"
app:layout_constraintStart_toStartOf="parent"
android:orientation="vertical">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amazing (20%)" />
<RadioButton
android:id="@+id/option_eighteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Good (18%)" />
<RadioButton
android:id="@+id/option_fifteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Okay (15%)" />
</RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
6. レイアウトの残りを完成させる
次はいよいよレイアウトの最後の部分です。Switch、Button、TextView を追加して、チップの金額を表示します。

チップの端数を切り上げる Switch を追加する
次に、Switch ウィジェットを使用して、ユーザーがチップの端数の切り上げについて「はい」か「いいえ」を選択できるようにします。
Switch の幅を親と同じにするには、幅を match_parent に設定すればよいと考えるかもしれません。前述のとおり、ConstraintLayout の UI 要素に match_parent を設定することはできません。代わりに、ビューの始端と終端に制約を設定し、幅を 0dp に設定する必要があります。幅を 0dp に設定すると、システムは幅を計算せずに、ビューに設定されている制約に合致させようとします。
RadioGroupの XML の後にSwitch要素を追加します。- 上記のとおり、
layout_widthを0dpに設定します。 layout_heightをwrap_contentに設定します。これにより、Switchビューの高さを内部のコンテンツに合わせます。id属性を@+id/round_up_switchに設定します。text属性をRound up tip?に設定します。これはSwitchのラベルとして使用されます。Switchの始端とtip_optionsの始端の間、Switch の終端と親の終端の間に制約を設定します。Switchの上端とtip_optionsの下端の間に制約を設定します。/>でタグを閉じます。
Switch がデフォルトで有効になっていると便利ですが、そのために android:checked という属性が用意されています。可能な値は true(オン)または false(オフ)です。
android:checked属性をtrueに設定します。
まとめると、Switch 要素の XML は次のようになります。
<Switch
android:id="@+id/round_up_switch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:checked="true"
android:text="Round up tip?"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/tip_options"
app:layout_constraintTop_toBottomOf="@id/tip_options" />

[Calculate] ボタンを追加する
次に、Button を追加して、ユーザーがチップの計算をリクエストできるようにします。ボタンの幅は、親の幅と同じにする必要があります。そのため、水平方向の制約と幅は Switch の場合と同じように設定します。
Switchの後にButtonを追加します。Switchの場合と同様に、幅を0dpに設定します。- 高さを
wrap_contentに設定します。 - リソース ID を
@+id/calculate_buttonとし、テキストは"Calculate"とします。 Buttonの上端と [Round up tip?]Switchの下端の間に制約を設定します。- Button の始端と親の始端の間、Button の終端と親の終端の間に制約を設定します。
/>でタグを閉じます。
[Calculate] Button の XML は次のようになります。
<Button
android:id="@+id/calculate_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Calculate"
app:layout_constraintTop_toBottomOf="@id/round_up_switch"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

チップの計算結果を追加する
レイアウトの完成まであと少しです。このステップでは、チップの計算結果の TextView を追加します。これを [Calculate] ボタンの下に配置しますが、他の UI 要素のように開始位置ではなく、終了位置に合わせて配置します。
TextViewを追加して、リソース ID にtip_result、テキストにTip Amountを指定します。TextViewの終端と親の終端の間に制約を設定します。- 上端と [Calculate] ボタンの下端の間に制約を設定します。
<TextView
android:id="@+id/tip_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/calculate_button"
android:text="Tip Amount" />

- アプリを実行します。次に示すスクリーンショットのようになります。

お疲れさまでした。今回初めて XML を使用したかもしれませんが、問題なくレイアウトを作成することができました。
なお、Android Studio の新しいバージョンではテンプレートが変更されている可能性があるため、実際のアプリはスクリーンショットと一部異なる場合があります。[Calculate] ボタンはまだ機能しませんが、料金を入力し、チップの割合を選択して、チップの端数を切り上げるかどうかのオプションを切り替えることができます。[Calculate] ボタンは次の Codelab で動作するようにしますので、それまでお待ちください。
7. 適切なコーディング慣習を採用する
文字列を抽出する
ハードコードされた文字列に関する警告が表示されていることに気づいていたでしょうか。前の Codelab で、文字列をリソース ファイルに抽出すると、アプリを他の言語に翻訳したり、文字列を再利用したりしやすくなることを説明しました。activity_main.xml を確認して、すべての文字列リソースを抽出します。
- 文字列をクリックして、表示される黄色の電球アイコンの上にカーソルを合わせ、その横にある三角形をクリックします。表示されるメニューの中から、[Extract String Resource] を選択します。文字列リソースの名前はデフォルトのままでも構いませんが、チップ オプションに
amazing_service、good_service、ok_serviceを使用して、よりわかりやすい名前を付けることもできます。
追加した文字列リソースを確認します。
- [Project] ウィンドウが表示されない場合は、ウィンドウの左側にある [Project] タブをクリックします。
- [app] > [res] > [values] > [strings.xml] を開いて、UI 文字列リソースをすべて表示します。
<resources>
<string name="app_name">Tip Time</string>
<string name="cost_of_service">Cost of Service</string>
<string name="how_was_the_service">How was the service?</string>
<string name="amazing_service">Amazing (20%)</string>
<string name="good_service">Good (18%)</string>
<string name="ok_service">Okay (15%)</string>
<string name="round_up_tip">Round up tip?</string>
<string name="calculate">Calculate</string>
<string name="tip_amount">Tip Amount</string>
</resources>
XML を再フォーマットする
Android Studio には、コードを整理し、推奨されるコーディング規則に準拠できるようにするための各種ツールが用意されています。
activity_main.xmlで、[Edit] > [Select All] を選択します。- [Code] > [Reformat Code] を選択します。
こうすることで、インデントに一貫性を持たせることができます。また、ある要素のすべての android: 属性をまとめるといったように、UI 要素の XML の一部を並べ替えてグループ化することもできます。
8. 解答コード

res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/cost_of_service"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:hint="@string/cost_of_service"
android:inputType="numberDecimal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/service_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/how_was_the_service"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cost_of_service" />
<RadioGroup
android:id="@+id/tip_options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkedButton="@id/option_twenty_percent"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/service_question">
<RadioButton
android:id="@+id/option_twenty_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/amazing_service" />
<RadioButton
android:id="@+id/option_eighteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/good_service" />
<RadioButton
android:id="@+id/option_fifteen_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ok_service" />
</RadioGroup>
<Switch
android:id="@+id/round_up_switch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/round_up_tip"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/tip_options"
app:layout_constraintTop_toBottomOf="@id/tip_options" />
<Button
android:id="@+id/calculate_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/calculate"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/round_up_switch" />
<TextView
android:id="@+id/tip_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tip_amount"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/calculate_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
res/values/strings.xml
<resources>
<string name="app_name">Tip Time</string>
<string name="cost_of_service">Cost of Service</string>
<string name="how_was_the_service">How was the service?</string>
<string name="amazing_service">Amazing (20%)</string>
<string name="good_service">Good (18%)</string>
<string name="ok_service">Okay (15%)</string>
<string name="round_up_tip">Round up tip?</string>
<string name="calculate">Calculate</string>
<string name="tip_amount">Tip Amount</string>
</resources>
9. 概要
- XML(拡張マークアップ言語)は、テキストを整理する方法のひとつであり、タグ、要素、属性で構成されています。
- XML を使用して Android アプリのレイアウトを定義します。
EditTextを使用して、ユーザーがテキストを入力または編集できるようにします。EditTextには、そのフィールドに入力すべき内容を示すヒントを表示できます。android:inputType属性を指定して、ユーザーがEditTextフィールドに入力できるテキストの種類を制限します。RadioButtonsを使用してRadioGroupでグループ化し、排他的なオプションのリストを作成します。RadioGroupは、縦向きまたは横向きにすることができます。また、最初に選択するRadioButtonを指定できます。Switchを使用して、ユーザーが 2 つのオプションを切り替えられるようにします。- 別の
TextViewを使用せずにSwitchにラベルを追加できます。 ConstraintLayoutのそれぞれの子には、垂直方向と水平方向の制約が必要です。- 「start」と「end」の制約を使用すると、左から右に記述する(LTR)言語と右から左に記述する(RTL)言語の両方を処理できます。
- 制約属性の名前は、
layout_constraint<Source>_to<Target>Ofの形式をとります。 Viewの幅をConstraintLayoutの幅と同じにするには、View の始端と親の始端の間、View の終端と親の終端の間にそれぞれ制約を設定し、幅を 0 dp に設定します。
10. 詳細
以下の各リンクから、ここで説明したトピックに関するドキュメントをご覧いただけます。Android 開発のドキュメントはすべて developer.android.com から取得できます。また、行き詰まったときには、Google 検索を利用してください。
11. 自習用練習問題
次のことを行います。
- 別の計算アプリを作成します(例: ミリリットルと液量オンス、グラムとカップなどを相互に変換する、料理用の単位変換アプリ)。このアプリの場合、どのようなフィールドが必要になるでしょうか。