Loading
BLOG 開発者ブログ

2020年12月15日

Jetpack Composeでレイアウト作成の基本



Androidの新しいUI作成ツールJetpack Composeを触ってみたので、基本的な使い方、使い勝手について書いて行こうと思います。
まだアルファ版なので、どのくらい実用性がありそうなのか確認するためにも、まずは基本的なレイアウト作成についてまとめていきます。

はじめに

こんにちは。
モバイルソリューショングループのkatsu.rです。

この記事は アイソルート Advent Calendar 2020 15日目の記事です。




Jetpack Composeとは

Jetpack Compose は、Android のネイティブ UI を構築するための最新のツールキットです。Jetpack Compose は、少ないコード、パワフルなツール、直感的な Kotlin API を使用して Android での UI の開発を簡素化し、加速します。

引用:https://developer.android.com/jetpack/compose/tutorial




準備

それでは、ここからJetpack Composeを使用する方法について書いていきます。

冒頭でも書きましたがJetpack Composeはアルファ版となります。

今回は以下の環境で動作を確認しました。
・Android Studio 4.2 Beta1
・Jetpack Compose1.0.0-alpha07

いずれもバージョンアップなどで変更が入る可能性が十分に想定されますのでご注意ください。

Jetpack Compose使用するために、まず以下のリンク先にしたがって、build.gradleの設定等をしておく必要があります。
https://developer.android.com/jetpack/compose/setup



※Android Studio内でJetpack Composeを使用して作成したレイアウトのプレビューを確認する方法については
今回は割愛するので以下をご参考ください。
https://developer.android.com/jetpack/compose/preview




基本的な使い方

準備が整ったら、さっそくレイアウトを作成していきます。


テキスト

画面にテキストを表示させる方法です。
「Hello World!」というテキストを表示するコンポーザブルな関数を作成し、Text()で画面に指定したテキストを表示することができます。


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            HelloWorld()
        }
    }
}

@Composable
fun HelloWorld() {
    Text(text = "Hello World!")
}



引数の渡し方

コンポーザブルな関数に引数を渡して動的にテキストを表示する方法です。
引数によって指定された文字列を「Hello XXX!」と表示したい場合は、以下のようにすれば実装が可能です。


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Greeting("Isoroot")
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}




レイアウト

複数のViewを縦に並べたり横に並べたりしたいときの方法です。
Column()を使うと、各Viewを縦に並べることができます。
※Rowメソッドを使うと横並びのレイアウトになります。


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            LineText()
        }
    }
}

@Composable
fun LineText(){
    Column {
        Text(text = "1つ目のテキスト")
        Text(text = "2つ目のテキスト")
        Text(text = "3つ目のテキスト")
    }
}



スタイル

レイアウトに余白や表示領域など、スタイルを設定する方法です。
以下では、Columnのレイアウトを横幅いっぱい表示、内側の余白16dpを設定しました。

また、horizontalAlignmentを設定することで、水平方向の位置を指定できます。
今回は要素のViewが画面の真ん中に表示されるように設定しました。
※垂直方向の設定は、verticalArrangementで可能です。


@Composable
fun LineText(){
    Column(
        modifier = Modifier.fillMaxSize().padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally

    ) {
        Text(text = "1つ目のテキスト")
        Text(text = "2つ目のテキスト")
        Text(text = "3つ目のテキスト")
    }
}



画像

画像を表示する方法です。
以下のようにImage()を使用して画像の表示が可能です。
また、先ほどと同様にModifierでスタイルを設定したり、角丸の設定も簡単にできます。


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            LogoImage()
        }
    }
}

@Composable
fun LogoImage(){
    val image = imageResource(R.drawable.logo_isoroot)
    val imageModifier = Modifier
        .padding(16.dp)
        .fillMaxWidth()

    Image(image, modifier = imageModifier, contentScale = ContentScale.Crop)
}



リスト

リストの表示方法です。(個人的にここが一番今までと比較して簡単に実装できてよかったです!)

まず、セル用のコンポーザブルな関数を作成します。
今回は固定の画像と名前のテキストを表示するようにしています。


@Composable
fun Card(name: String) {
    val image = imageResource(R.drawable.logo_isoroot)
    Column (
        Modifier
            .padding(16.dp)
            .fillMaxWidth()
    ) {
        val imageModifier = Modifier
            .wrapContentSize()
        Image(image, modifier = imageModifier, contentScale = ContentScale.Crop)
        Text(text = name, style = TextStyle(fontSize = 20.sp))

    }
}


次に、リスト用のコンポーザブルな関数を作成します。
先ほど作成したセル用の関数を、ScrollableColumnを使用して繰り返し表示します。
ScrollableColumn()を使用すると、スクロール可能なレイアウトが作成できます。
※Dividerは区切り線です。


@Composable
fun NameList(
    listItems: List
) {
    ScrollableColumn(Modifier.fillMaxSize()) {
        listItems.forEach {
            Card(it)
            Divider(color = Color(0x44666666))
        }
    }
}


最後に、表示したいリストを作成してリスト用の関数を以下のように呼び出してあげると
リスト表示が可能です。


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val nameList: List = listOf("太郎", "花子", "次郎", "一郎")
        setContent {
            NameList(nameList)
        }
    }
}



今までリストを作成するときは、リストのレイアウト、セルのレイアウト、Adapterクラスを作成していましたが、
Jetpack Composeを使うとこれだけのコード量で実現できてしまうのは驚きですね!

クリックイベント

Viewにクリックイベントを追加する方法です。
先ほどのリストのセル用関数の引数にクリックイベントを追加します。

今回はクリック可能領域をセル全体にするため、まずはColumnのModifierにクリックイベントを付与します。
(ImageやText単体にクリックイベントを付与することも可能です。)


@Composable
fun Card(name: String, onSelected: () -> Unit) {
    val image = imageResource(R.drawable.logo_isoroot)
    Column (
        Modifier
            .clickable(onClick = onSelected)
            .padding(16.dp)
            .fillMaxWidth()
    ) {
        val imageModifier = Modifier
            .wrapContentSize()
        Image(image, modifier = imageModifier, contentScale = ContentScale.Crop)
        Text(text = name, style = TextStyle(fontSize = 20.sp))
    }
}


次に、リスト用の関数にも引数にクリックイベントを追加します。


@Composable
fun NameList(
    listItems: List,
    onSelected: (String) -> Unit
) {
    ScrollableColumn(Modifier.fillMaxSize()) {
        listItems.forEach {
            Card(it, { onSelected(it) })
            Divider(color = Color(0x44666666))
        }
    }
}


最後に、呼び出し元でセルタップ時の実装を作成し、引数に設定してあげればクリックイベントの設定は完了です。
今回はタップしたセルの名前をトーストで表示ようにしました。
※もちろん、コンポーザブルな関数内でタップ時の実装を作成するのも可能です。


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val nameList: List = listOf("太郎", "花子", "次郎", "一郎")
        val onItemSelected: (String) -> Unit = {
            Toast.makeText(this, "$it がタップされました", Toast.LENGTH_SHORT).show()
        }
        setContent {
            NameList(nameList, onItemSelected)
        }
    }
}



まとめ

今までのxmlファイルでレイアウトを作成する時と比べ、コード量はかなり削減しました!
書き方に慣れる時間は必要ですが、慣れてしまえばレイアウト作成の時間は短縮できそうです。
また、View操作時の実装をする時にxmlファイルとktファイルなどファイル間の行き来が減るのも個人的には使いやすいと感じました!
複雑なレイアウトを作成する際は、コンポーザブルな関数を別ファイルに書き出して整理したりは必要になると思いますが、
よく使うViewの使いまわしもより簡単に実現できそうなのも良い点かなと思います。

今回は紹介していませんが、コンポーザブルな関数内でViewModelなどの状態が変化する値の監視についても可能になります。
こちらをうまく利用すれば、APIで取得した値を動的に画面表示なども簡単に実現可能です。
https://developer.android.com/jetpack/compose/state?hl=ja#use-other-types-of-state-in-jetpack-compose

明日は kikuchi.s さんの 【アジャイル】設計書に時間をかけたくない人のための話 です。


katsu.rのブログ