ビューのレイアウト
レイアウトは、アクティビティなど、アプリ内のユーザー インターフェースの構造を定義します。レイアウトの要素はすべて、View オブジェクトと ViewGroup オブジェクトの階層を使用して作成されます。View は通常、ユーザーに表示される、ユーザーが操作できるものを描画します。ViewGroup は非表示のコンテナであり、図 1 に示すように、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 オブジェクトによっても継承されます。一部はルート View クラスから継承されるため、すべての View オブジェクトに共通します(id 属性など)。他の属性は「レイアウト パラメータ」と見なされます。これは View オブジェクトの特定のレイアウト方向を記述する属性であり、オブジェクトの親である ViewGroup オブジェクトによって定義されます。
ID
ツリー内で View を一意に識別するために、View オブジェクトに整数の ID を関連付けることができます。アプリがコンパイルされると、この ID が整数として参照されますが、この ID は通常、レイアウト XML ファイルの id 属性で、文字列として割り当てられます。これは、すべての View オブジェクトに共通の XML 属性であり、View クラスによって定義されます。使用頻度が非常に高い。XML タグ内の ID の構文は次のとおりです。
android:id="@+id/my_button"
文字列の先頭にあるアットマーク(@)は、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);
ビュー オブジェクトの ID を定義することは、RelativeLayout を作成する際に重要です。相対レイアウトでは、兄弟ビューは一意の ID によって参照される別の兄弟ビューに対して相対的にレイアウトを定義できます。
ツリー全体で ID が一意である必要はありませんが、検索するツリーの一部では一意である必要があります。ツリー全体となることが多いため、可能であれば一意にすることをおすすめします。
レイアウト パラメータ
layout_something という名前の XML レイアウト属性では、その ViewGroup に適した View のレイアウト パラメータが定義されます。
すべての ViewGroup クラスでは、ViewGroup.LayoutParams を拡張するネストされたクラスが実装されます。このサブクラスには、各子ビューのサイズと位置を ViewGroup に合うように定義するプロパティ タイプが含まれています。図 2 に示すように、親ビューグループは、子ビューグループを含む子ビューごとにレイアウト パラメータを定義します。
すべての LayoutParams サブクラスには、値を設定するための独自の構文があります。それぞれの子要素は、その親に適した LayoutParams を定義する必要がありますが、自分の子に対して異なる LayoutParams を定義することもできます。
すべてのビューグループには幅と高さ(layout_width と layout_height)が含まれており、各ビューでそれらを定義する必要があります。多くの LayoutParams には、オプションのマージンと境界線も含まれています。
必要になる頻度は多くないはずですが、幅と高さは正確な値で指定できます。多くの場合、次の定数のいずれかを使用して幅または高さを設定します。
wrap_content: ビューのサイズをそのコンテンツに必要なサイズにします。match_parent: ビューのサイズを親ビューグループで許容される最大サイズにします。
通常、ピクセルなどの絶対単位でレイアウトの幅と高さを指定することはおすすめしません。密度非依存ピクセル単位(dp)、wrap_content、match_parent などの相対値を使用する方が賢明です。これにより、さまざまなデバイスの画面サイズでアプリが適切に表示されます。使用可能な測定タイプは、レイアウト リソースで定義されています。
レイアウトの位置
ビューの形状は矩形です。位置は左座標と上座標のペアで表され、寸法は幅と高さで表されます。位置と寸法の単位はピクセルです。
getLeft() メソッドと getTop() メソッドを呼び出すことで、ビューの位置を取得できます。前者はビューを表す矩形の左(x)座標を返します。後者はビューを表す矩形の上(y)座標を返します。これらのメソッドは、親に対するビューの相対的な位置を返します。たとえば、getLeft() が 20 を返す場合、ビューは直属の親の左端から右に 20 ピクセルの位置にあります。
また、不要な計算を避けるための便利なメソッド(getRight() と getBottom())も用意されています。これらのメソッドは、ビューを表す矩形の右端と下端の座標を返します。たとえば、getRight() を呼び出すことは、getLeft() + getWidth() の計算と同様です。
サイズ、パディング、マージン
ビューのサイズは、幅と高さで表します。ビューには幅と高さの値のペアが 2 つあります。
1 つ目のペアは「測定幅」と「測定高さ」といいます。これらの寸法で、親の中でのビューの大きさが定義されます。測定寸法を取得するには、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 のサブクラスを使用できます。RecyclerView は 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()をオーバーライドし、各アイテムに必要なビューのタイプを返します。 - アプリ
SimpleCursorAdapterCursorから取得したデータの場合は、このアダプターを使用します。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は、対応するtoViewsビューに各fromColumnsアイテムを挿入することで、指定されたレイアウトを使用してCursorの行ごとにビューを作成します。
アプリの実行中に、アダプターで読み取る基データを変更する場合は、notifyDataSetChanged() を呼び出します。これにより、接続されたビューに対して、データが変更されたためビュー自身の更新が必要であることが通知されます。
クリック イベントを処理する
AdapterView.OnItemClickListener インターフェースを実装することで、AdapterView の各アイテムのクリック イベントに応答できます。次に例を示します。
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 デモアプリをご覧ください。



