完成形のイメージを確認
個人開発者の中には、『コーディングしながらデザインを調整していく』という人もいるかと思いますが、一般的には、デザインデータを元に仕様通りにコーディングを行っていきます。
今回はプロフィールカードを作成(レイアウト)していくので、まずはそのデザインデータ(完成形のイメージ)が必要ということになりますね。
ということで、デザインデータを用意しました。できる限りこの完成形と同じになるように、レイアウトを行っていきます。
なお、今回はあくまでレイアウト(要素の配置)がテーマであるため、カラーやフォントなど、その他のデザインの要素に関しては特にこだわらなくて良いこととします。
また、Androidアプリ開発においてよく出てくる 【dp(Density-independent Pixels)】 という単位ですが、これはデバイスの画面密度に関係なく、一貫したサイズを表すための単位です。
たとえば、100個のドットで文字や画像を表現できるデバイスと、200個のドットで表現できるデバイスがあり、それぞれ画面の大きさは同じだとしましょう。
このとき、『ドット50個分の大きさ』という方法でサイズを指定すると、100個のドットでは画面の半分の大きさになる一方、200個のドットの画面の方ではそれよりも小さい(画面の1/4サイズ)で表示されることになってしまいます。
これでは画面密度によって大きさが変わってしまうため、dpという画面密度に依存しない単位を用いるのがセオリーとなっています。
何はともあれ完成形のデザインが確認できたので、次のステップでは、さっそくJetpack Composeを使ってレイアウトしていきましょう!
POINT!
- ・基本的には、完成系のデザインデータを元にレイアウトを行っていく!
- ・今回はレイアウトに的を絞っているので、その他の要素(カラーなど)に関してはテキトーでOK!
- ・dp(Density-independent Pixels)は、画面密度に依存しない大きさを表す単位!
Boxで重ねる
デザインをよく見ると、横並びになっている部分(1)と、縦並びになっている部分(2)、そしてどちらにも該当しない部分(3)があります。
(1)は Row()
、(2)は Column()
、そして(3)は Box()
コンポザーブルを使ってレイアウトすることができます。
まず、Card
コンポーザブルでカードの形をした背景を用意し、その次に(3)のアイコンをレイアウトするための Box()
を配置します。
カードのサイズ指定は Card
コンポーザブルで行い、Box
は親となるCardコンポーザブルの幅いっぱいになるように、Modifier(修飾子)で fillMaxSize()
を指定します。
なお、カード内のPadding(余白)は、Boxに指定しておきます。
さらに、後でBoxスコープ内に画像やテキストを配置するので、contentAlignment = Alignment.CenterStart
と指定することで、要素が上下の中央かつ左揃えに配置されるようにしておきます。
@Composable
fun LayoutSample(modifier: Modifier = Modifier) {
Card(
modifier = Modifier
.padding(16.dp)
.size(width = 300.dp, height = 150.dp)
) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
}
}
}
この時点で、表示結果は次のようになります。
Boxは、要素を親要素内に自由な位置に重ねて配置したいときに使うレイアウト用のコンポザーブルです。
今回は、アイコンをCardの右上に配置したいので、Boxスコープ内にIconを配置して、Iconの位置をModifireで .align(Alignment.TopEnd)
と指定します。
@Composable
fun LayoutSample(modifier: Modifier = Modifier) {
Card(
modifier = Modifier
.padding(16.dp)
.size(width = 300.dp, height = 150.dp)
) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.align(Alignment.TopEnd)
)
}
}
}
すると、アイコンがCardの右上に配置されます。
なお、より実際のアプリに近づけるのであれば、ここはただのIconではなく、IconButton
にしてクリック動作を行えるようにすべきところですが、今回は単にアイコンを配置するだけに留めておきます。
次のステップで、残りの要素を一気にレイアウトして完成させていきます!
POINT!
- ・Cardコンポーザブルで、カード風の背景を簡単に作ることができる!
- ・Box()は、要素を重ね合わせることができる!
- ・Boxスコープ内の要素のModifierに .align(Alignment.TopEnd) を指定すると、Boxの右上に配置される!
RowとColumnで横並びと縦並び
レイアウトの大枠ができたので、次に画像とテキストを配置していきたいと思います。
まず、Row()
で画像とテキストを横並びに並べます。
画像のサイズは縦横 100.dp
に指定した上で、画像が丸く切り取られるように、clip(CircleShape)
を指定します。
なお、画像とテキストの間隔は 8.dp
なので、Rowコンポザーブルの horizontalArrangement
パラメータに、Arrangement.spaceBy(8.dp)
を指定しておきます。
テキスト部分は縦並びなので、Column()
を使ってテキストをレイアウトします。
テキスト同士の間隔は 8.dp
なので、Columnコンポザーブルの verticalArrangement
パラメータに、Arrangement.spaceBy(8.dp)
を指定します。
テキストの大きさやフォントに関しては、今回特に指定がないものとして扱いますので、違和感が出ない程度にお好きなように設定してください。
コードと表示結果は次のようになります。
@Composable
fun LayoutSample(modifier: Modifier = Modifier) {
Card(
modifier = Modifier
.padding(16.dp)
.size(width = 300.dp, height = 150.dp)
) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.align(Alignment.TopEnd)
)
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier
) {
Image(
painter = painterResource(R.drawable.me),
contentDescription = "Profile",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(100.dp)
.clip(CircleShape)
)
Column(
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = "Michihiro",
style = MaterialTheme.typography.titleLarge
)
Text(
text = "Hi! My name is Michihiro. I'm a developer of Android apps!"
)
}
}
}
}
}
ということで、無事に完成形のデザインデータと同じようにレイアウトすることができました!
今回、要素の間隔を空けるのに Arrangement.spacedBy()
を主に使ってますが、要素が複数あってその間隔が一定ではない場合は、要素に padding()
を指定して余白を調整する必要があります。
余白の調整をはじめ、レイアウトを調整する方法は一つだけでなく色んなやり方があるので、状況に応じて効率よく調整できる方法を選択すると良いでしょう。
POINT!
- ・Row() で要素を横並びにレイアウトできる!
- ・Column() で要素を縦並びにレイアウトできる!
- ・余白の開け方など、調整方法は色々あるので状況に応じて使い分けよう!