ビューのレイアウト
レイアウトは、アクティビティなどのアプリのユーザー インターフェースの構造を定義します。レイアウト内のすべての要素は、View
オブジェクトと ViewGroup
オブジェクトの階層を使用して作成されます。View
は通常、ユーザーが表示して操作できるものを描画します。図 1 に示すように、ViewGroup
は View
などの ViewGroup
オブジェクトのレイアウト構造を定義する非表示のコンテナです。
View
オブジェクトはウィジェットと呼ばれることも多く、Button
や TextView
など、多くのサブクラスのいずれかになります。ViewGroup
オブジェクトは通常「レイアウト」と呼ばれ、LinearLayout
や ConstraintLayout
など、異なるレイアウト構造を提供する多くのタイプのいずれかになります。
レイアウトを宣言する方法は 2 通りあります。
- XML で UI 要素を宣言する。Android には、ウィジェットやレイアウトなど、
View
のクラスとサブクラスに対応するシンプルな XML ボキャブラリが用意されています。また、Android Studio の Layout Editor を使用して、ドラッグ&ドロップ インターフェースから XML レイアウトを作成することもできます。 - レイアウト要素を実行時にインスタンス化する。アプリでは、
View
オブジェクトとViewGroup
オブジェクトを作成し、そのプロパティをプログラムで操作できます。
XML で UI を宣言すると、アプリの動作をコードから切り離すことができます。また、XML ファイルを使用すると、画面サイズと向きに応じてさまざまなレイアウトを簡単に提供できます。この詳細については、各種の画面サイズのサポートをご覧ください。
Android フレームワークでは、これらの方法のいずれかまたは両方を柔軟に使用して、アプリの UI をビルドできます。たとえば、アプリのデフォルト レイアウトを XML で宣言し、実行時にレイアウトを変更できます。
XML の記述
Android の XML ボキャブラリを使用すると、一連のネストされた要素を使用して HTML でウェブページを作成するのと同じ方法で、UI レイアウトとそれに含まれる画面要素をすばやく設計できます。
各レイアウト ファイルには、ルート要素を 1 つだけ含める必要があります。ルート要素は View
オブジェクトまたは ViewGroup
オブジェクトである必要があります。ルート要素を定義したら、別のレイアウト オブジェクトまたはウィジェットを子要素として追加し、レイアウトを定義する View
階層を段階的に構築できます。たとえば、縦長の LinearLayout
を使用して TextView
と Button
を保持する 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" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a Button" /> </LinearLayout>
XML でレイアウトを宣言したら、.xml
拡張子を付けて Android プロジェクトの res/layout/
ディレクトリにファイルを保存し、正しくコンパイルされるようにします。
レイアウト XML ファイルの構文の詳細については、レイアウト リソースをご覧ください。
XML リソースを読み込む
アプリをコンパイルすると、各 XML レイアウト ファイルは View
リソースにコンパイルされます。アプリの Activity.onCreate()
コールバック実装でレイアウト リソースを読み込みます。そのためには、setContentView()
を呼び出して、R.layout.layout_file_name
の形式でレイアウト リソースへの参照を渡します。たとえば、XML レイアウトが main_layout.xml
として保存されている場合は、次のように Activity
で読み込みます。
Kotlin
fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.main_layout) }
Java
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); }
Android フレームワークは、Activity
の起動時に Activity
内の onCreate()
コールバック メソッドを呼び出します。アクティビティのライフサイクルの詳細については、アクティビティの概要をご覧ください。
属性
すべての View
オブジェクトと ViewGroup
オブジェクトは、それぞれ独自の XML 属性をサポートしています。一部の属性は View
オブジェクトに固有のものです。たとえば、TextView
は textSize
属性をサポートしています。ただし、これらの属性は、このクラスを拡張する View
オブジェクトにも継承されます。一部のオブジェクトは id
属性のようにルートの View
クラスから継承されるため、すべての View
オブジェクトに共通です。その他の属性はレイアウト パラメータと見なされます。レイアウト パラメータは、View
オブジェクトの親オブジェクトによって定義されるViewGroup
オブジェクトの特定のレイアウト方向を記述する属性です。
ID
ツリー内の View
を一意に識別するために、すべての View
オブジェクトに整数 ID を関連付けることができます。アプリがコンパイルされると、この ID は整数として参照されますが、この ID は通常、レイアウト XML ファイル内で id
属性の文字列として割り当てられます。これはすべての View
オブジェクトに共通の XML 属性であり、View
クラスで定義されます。非常に頻繁に使用します。XML タグ内の ID の構文は次のとおりです。
android:id="@+id/my_button"
文字列の先頭にある at 記号(@)は、XML パーサーが ID 文字列の残りの部分を解析して展開し、それを ID リソースとして識別することを示します。プラス記号(+)は新しいリソース名で、R.java
ファイルで作成してリソースに追加する必要があります。
Android フレームワークには、他にも多くの ID リソースが用意されています。Android リソース ID を参照する場合、プラス記号は必要ありませんが、次のように android
パッケージ名前空間を追加する必要があります。
android:id="@android:id/empty"
android
パッケージの名前空間は、ローカル リソース クラスではなく、android.R
リソースクラスから ID を参照していることを示します。
ビューを作成してアプリから参照するには、次のような一般的なパターンを使用します。
- 次の例に示すように、レイアウト ファイルでビューを定義し、一意の ID を割り当てます。
<Button android:id="@+id/my_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/my_button_text"/>
- ビュー オブジェクトのインスタンスを作成して、レイアウトからキャプチャします。通常は、次の例に示すように
onCreate()
メソッドで行います。Kotlin
val myButton: Button = findViewById(R.id.my_button)
Java
Button myButton = (Button) findViewById(R.id.my_button);
RelativeLayout
を作成するときに、ビュー オブジェクトの ID を定義することが重要です。相対レイアウトでは、兄弟ビューは、一意の ID で参照される別の兄弟ビューを基準としてレイアウトを定義できます。
ID はツリー全体で一意である必要はありませんが、検索するツリーの一部では一意である必要があります。多くの場合、ツリー全体であるため、可能であれば一意のものにすることをおすすめします。
レイアウト パラメータ
layout_something
という XML レイアウト属性は、それが存在する ViewGroup
に適した View
のレイアウト パラメータを定義します。
すべての ViewGroup
クラスは、ViewGroup.LayoutParams
を拡張するネストされたクラスを実装します。このサブクラスには、ビューグループに応じて、各子ビューのサイズと位置を定義するプロパティ型が含まれます。図 2 に示すように、親ビューグループは、子ビューグループを含む子ビューごとにレイアウト パラメータを定義します。
すべての LayoutParams
サブクラスには、値を設定するための独自の構文があります。各子要素では、その親に適した LayoutParams
を定義する必要があります。ただし、自身の子に異なる LayoutParams
を定義することもできます。
すべてのビューグループには、layout_width
と layout_height
を使用して幅と高さが含まれ、各ビューでそれらを定義する必要があります。多くの LayoutParams
には、オプションのマージンや枠線が含まれています。
幅と高さは正確な測定値で指定できますが、頻繁には指定しないことをおすすめします。多くの場合、次のいずれかの定数を使用して幅または高さを設定します。
wrap_content
: コンテンツに必要なサイズに合わせてビューのサイズを調整します。match_parent
: ビューを親ビューグループと同じ大きさにするように指定します。
一般に、ピクセルなどの絶対単位でレイアウトの幅と高さを指定することはおすすめしません。密度非依存ピクセル単位(dp)、wrap_content
、match_parent
などの相対測定を使用すると、さまざまなデバイスの画面サイズでアプリを適切に表示できます。使用できる測定タイプは、レイアウト リソースで定義されています。
レイアウトの位置
ビューは長方形のジオメトリを持ちます。位置は、左座標と上座標のペアで表され、2 次元は幅と高さで表されます。位置と寸法の単位はピクセルです。
ビューのロケーションを取得するには、getLeft()
メソッドと getTop()
メソッドを呼び出します。前者はビューを表す長方形の左(x)座標を返します。後者は、ビューを表す長方形の上部(y)座標を返します。これらのメソッドは、親に対する相対的なビューの位置を返します。たとえば、getLeft()
が 20 を返す場合、ビューは直接親の左端から 20 ピクセル右に配置されています。
さらに、getRight()
と getBottom()
という、不要な計算を回避するためのコンビニエンス メソッドもあります。これらのメソッドは、ビューを表す長方形の右端と下端の座標を返します。たとえば、getRight()
の呼び出しは、getLeft() + getWidth()
の計算に似ています。
サイズ、パディング、マージン
ビューのサイズは、幅と高さで表します。ビューには幅と高さの値の ペアが 2 つあります
最初のペアは測定された幅と測定された高さと呼ばれます。これらのディメンションは、親内のビューのサイズを定義します。測定した寸法を取得するには、getMeasuredWidth()
と getMeasuredHeight()
を呼び出します。
2 つ目のペアは幅と高さ、または描画幅と描画高さと呼ばれることもあります。これらのディメンションは、描画時およびレイアウト後の画面上のビューの実際のサイズを定義します。これらの値は、測定された幅と高さと異なる場合がありますが、必須ではありません。幅と高さを取得するには、getWidth()
と getHeight()
を呼び出します。
寸法を測定するために、ビューはパディングを考慮します。パディングは、ビューの左、上、右、下の部分のピクセル単位で表されます。パディングを使用して、特定のピクセル数だけビューのコンテンツをオフセットできます。たとえば、左パディングを 2 にすると、ビューのコンテンツは左端から 2 ピクセル右側に押し出されます。setPadding(int, int, int, int)
メソッドを使用してパディングを設定し、getPaddingLeft()
、getPaddingTop()
、getPaddingRight()
、getPaddingBottom()
を呼び出してクエリを実行できます。
ビューではパディングを定義できますが、マージンはサポートされていません。ただし、ビューグループはマージンをサポートしています。詳しくは、ViewGroup
と ViewGroup.MarginLayoutParams
をご覧ください。
ディメンションの詳細については、ディメンションをご覧ください。
マージンとパディングをプログラムで設定するだけでなく、次の例に示すように 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" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="16dp" android:padding="8dp" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:paddingBottom="4dp" android:paddingEnd="8dp" android:paddingStart="8dp" android:paddingTop="4dp" android:text="Hello, I am a Button" /> </LinearLayout>
上記の例は、マージンとパディングが適用されていることを示しています。TextView
では周囲に均一なマージンとパディングが適用されています。Button
では、それらをさまざまなエッジに個別に適用する方法を示しています。
一般的なレイアウト
ViewGroup
クラスの各サブクラスには、内部にネストしたビューを表示する独自の方法が用意されています。最も柔軟なレイアウト タイプであり、レイアウト階層を浅く維持するための最適なツールを提供するのは ConstraintLayout
です。
Android プラットフォームに組み込まれている一般的なレイアウト タイプの一部を以下に示します。
動的リストを作成する
レイアウトのコンテンツが動的である場合や、事前に決定されていない場合は、RecyclerView
または AdapterView
のサブクラスを使用できます。AdapterView
よりもメモリを効率的に使用する RecyclerView
の方が一般的に適切なオプションです。
RecyclerView
と AdapterView
で使用できる一般的なレイアウトは次のとおりです。
RecyclerView
は、より多くの可能性を提供し、カスタム レイアウト マネージャーを作成するオプションを提供します。
アダプター ビューにデータを入力する
AdapterView
インスタンスを Adapter
にバインドすることで、ListView
や GridView
などの AdapterView
にデータを入力できます。これにより、外部ソースからデータを取得し、各データエントリを表す View
を作成できます。
Android には、さまざまな種類のデータの取得や AdapterView
のビューの作成に役立つ Adapter
のサブクラスがいくつか用意されています。最も一般的なアダプタは次の 2 つです。
ArrayAdapter
- データソースが配列の場合は、このアダプターを使用します。デフォルトでは、
ArrayAdapter
は、各アイテムに対してtoString()
を呼び出し、コンテンツをTextView
に配置することで、各配列アイテムのビューを作成します。たとえば、
ListView
に表示する文字列の配列がある場合、コンストラクタを使用して新しいArrayAdapter
を初期化し、各文字列と文字列配列のレイアウトを指定します。Kotlin
val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray)
Java
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray);
このコンストラクタの引数は次のとおりです。
- アプリ
Context
- 配列内の各文字列の
TextView
を含むレイアウト - 文字列配列
次に、
ListView
でsetAdapter()
を呼び出します。Kotlin
val listView: ListView = findViewById(R.id.listview) listView.adapter = adapter
Java
ListView listView = (ListView) findViewById(R.id.listview); listView.setAdapter(adapter);
各アイテムの外観をカスタマイズするには、配列内のオブジェクトの
toString()
メソッドをオーバーライドします。または、TextView
以外のアイテムごとにビューを作成する場合(たとえば、配列アイテムごとにImageView
が必要な場合)は、ArrayAdapter
クラスを拡張し、getView()
をオーバーライドして、各アイテムに必要なビューのタイプを返します。 - アプリ
SimpleCursorAdapter
- このアダプターは、データが
Cursor
から取得される場合に使用します。SimpleCursorAdapter
を使用する場合は、Cursor
の各行に使用するレイアウトと、レイアウトのビューに挿入するCursor
の列を指定します。たとえば、人の名前と電話番号のリストを作成する場合は、各人の行と、名前と番号の列を含むCursor
を返すクエリを実行できます。次に、各結果に対してCursor
のどの列をレイアウトに含めるかを指定する文字列配列と、各列を配置する必要のある対応するビューを指定する整数配列を作成します。Kotlin
val fromColumns = arrayOf(ContactsContract.Data.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER) val toViews = intArrayOf(R.id.display_name, R.id.phone_number)
Java
String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER}; int[] toViews = {R.id.display_name, R.id.phone_number};
SimpleCursorAdapter
をインスタンス化するときに、各結果に使用するレイアウト、結果を格納するCursor
、および次の 2 つの配列を渡します。Kotlin
val adapter = SimpleCursorAdapter(this, R.layout.person_name_and_number, cursor, fromColumns, toViews, 0) val listView = getListView() listView.adapter = adapter
Java
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.person_name_and_number, cursor, fromColumns, toViews, 0); ListView listView = getListView(); listView.setAdapter(adapter);
次に
SimpleCursorAdapter
は、各fromColumns
アイテムを対応するtoViews
ビューに挿入することで、指定されたレイアウトを使用してCursor
の各行のビューを作成します。
アプリの実行中に、アダプタによって読み取られる基になるデータを変更する場合は、notifyDataSetChanged()
を呼び出します。これにより、アタッチされたビューにデータが変更されたことが通知され、ビュー自体が更新されます。
クリック イベントを処理する
AdapterView
の各項目でクリック イベントに応答するには、AdapterView.OnItemClickListener
インターフェースを実装します。次に例を示します。
Kotlin
listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id -> // Do something in response to the click. }
Java
// Create a message handling object as an anonymous class. private OnItemClickListener messageClickedHandler = new OnItemClickListener() { public void onItemClick(AdapterView parent, View v, int position, long id) { // Do something in response to the click. } }; listView.setOnItemClickListener(messageClickedHandler);
参考情報
GitHub の Sunflower デモアプリで、レイアウトの使用方法をご覧ください。