6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jetpack ComposeでXMLレイアウトからの卒業(超初級)

Last updated at Posted at 2023-12-12

はじめに

PHONE APPLI Advent Calender13日目です!
Jetpack ComposeやらKotlin CoroutineやらDagger Hiltやら色々勉強つまみ食いしすぎて、逆に分けわからなくなっているしがないAndroidエンジニアです。
今回は最近(?)話題のコードベースでレイアウトを構築できるJetpack Composeについて、自分なりに理解したことを初歩の初歩部分ですが記事にしていきたいと思います。

Jetpack Composeってそもそも何?

Jetpack Compose は、ネイティブ UI をビルドする際に推奨される Android の最新ツールキットです。Android での UI 開発を簡素化し、加速します。少ないコード、パワフルなツール、直感的な Kotlin API を使用してアプリをすぐに動かすことができます。
(※Android Developersサイトから抜粋)

うーん、なんかよく分からん。
百聞は一見にしかずということで、早速使ってみましょう!

まずはJetpack Composeプロジェクトの作成

Android Studio(画像はver: Android Studio Giraffe | 2022.3.1 Patch 1)ではJetpack Composeを利用するプロジェクトをテンプレートから作成出来ます。
Android Studioのメニューから [File] -> [New] -> [New Project...] と順に選んでいき、下記画像で選択状態になっている Empty Activity でJetpack Composeプロジェクトを作成出来ます。

image.png

作成されたプロジェクトの内部を見てみると、今まではリソースファイルにレイアウト用のXMLファイルが存在していましたが、Jetpack Composeのプロジェクトでは存在しません。
じゃあどうやって画面描画すんねん!と思ってしまいますが、次の章で見ていきましょう。

image.png

テンプレートで作成されたMainActivityの中身

色々書いてありますが、 setContent 内に記述される内容が従来の setContentView でXMLレイアウトを指定しているものと同等になります。
setContent 内にはComposable関数と呼ばれるUIを構成する要素を定義した関数を記述できます。
このComposable関数というものを利用して、UIを構築していきます。

MainActivity
setContent {
    MyApplicationTheme {
        // A surface container using the 'background' color from the theme
        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colorScheme.background
        ) {
            Greeting("Android")
        }
    }
}

UI部品の一例

一部例や使い方を示していこうと思います。カッコ内は従来のXMLレイアウトで使用していたものを記載しています。

  • Text(TextView)
    テキストの表示を行えます。
    下記では引数に文字列しか指定していませんが、 fontSize で文字サイズの指定や color で色の指定等、引数を与えることによってテキストのプロパティを変更できます。
    また、 stringResource を利用することによって、リソースから文字列を取得することも出来ます。

    Text(text = "テキスト")
    Text(text = stringResource(id = /* stringリソース */)
    

  • Image(ImageView)
    画像の表示に利用するComposable関数で、 painterResourcedrawable リソースから画像を取得、表示できます。

    Image(
      painter = painterResource(id = /* drawableリソース */),
      contentDescription = "/* 画像の内容 */"
    )
    

    ここで、リソースからの画像を表示するのはいいけど、URLから画像を取得して読み込むのもこれでできるの?という疑問が浮かんでくると思いますが、標準で用意されているものでは不可能みたいです。
    お馴染みのライブラリであるGlideを利用することや、Coilと呼ばれるサードパーティライブラリを利用すると良いと developer guide に記載されています。
    今回、URLからの画像読み込みについては割愛しますがアプリを作成するには必須となることが多いので、追々学んでいきたいですね。

  • Row(LinearLayoutでのhorizontal指定)やColumn(LinearLayoutでのvertical指定)
    View群を並べる役割の親要素(ViewGroup)です。
    それぞれブロックの中に前述した Text や、 Image 等Composable関数を記述することによってUIを自由に構築することができます。
    今回はLinearLayoutのような単純な縦並び・横並びを紹介していますが、ConstraintLayoutのようなViewに他Viewとの制約を持たせることができるもの等、他にも色々なものが用意されています。

    Row {
      Text(text = "テスト1")
      Text(text = "テスト2")
    }
    
    Column {
      Text(text = "テスト1")
      Text(text = "テスト2") 
    }
    
    Row Column

View共通要素である余白(padding, margin)とかサイズ指定は?

従来でいう layout_widthmargin, background の指定についてですが、各標準のComposable関数に引数として Modifier というものが用意されています。
このModifierオブジェクトを変更することによって高さや幅、バックグラウンドや余白等の指定を行うことができます。

Row(
    modifier = Modifier
        .background(Color.Green)
        .height(300.dp)
        .fillMaxWidth()
        .padding(16.dp)
        .background(Color.Black)
        .padding(16.dp)
        .background(Color.Blue),
    verticalAlignment = Alignment.CenterVertically,
    horizontalArrangement = Arrangement.Center
) {
    Text(
        modifier = Modifier
            .padding(horizontal = 16.dp)
            .fillMaxWidth()
            .background(Color.White),
        text = "テスト",
        color = Color.Black,
        textAlign = TextAlign.Center
    )
}

Modifier では paddingmargin で区別されおらず、要素の指定順序によって表現されます。

上記抜粋
Modifier
    .background(Color.Green)
    .height(300.dp)
    .fillMaxWidth()
    .padding(16.dp)
    .background(Color.Black)

全体の色をグリーンで塗りつぶした上で縦幅を 300dp ,横幅を親要素いっぱいに表示してから更に 16dp の余白をとり、その中身を黒く塗りつぶすような記載順序になっています。
padding で指定した分、その後に指定する要素が狭まっていくといった形になります。

Composable関数にmodifier引数を定義し、柔軟性を持たせる

前述したように、Modifierオブジェクトを利用するとViewの余白やバックグラウンドを変更できますが、全ての場面で同一の余白やバックグラウンドを利用する場面は少ないと思います。
そこで以下のように自分で定義したComposable関数の引数にModifierを渡すことによって柔軟性を持たせることもできます。
上で作成した Row ブロックを別関数で定義して  setContent 内で利用してみます。

setContent {
    FlexModifierTest(Modifier.padding(20.dp))
}

@Composable
fun FlexModifierTest(modifier: Modifier = Modifier) {
    Row(
        modifier = modifier
            .background(Color.Green)
            .height(300.dp)
            .fillMaxWidth()
    ...
}

このように関数にComposableアノテーションを使用することで、Composable関数を作成することが可能です。
Composable関数を作成した上で、利用する箇所によって値を変更出来るようにしておくと、UI部品として様々な箇所で流用することができ、アプリ全体である程度レイアウトの統一を行うことが可能です。

構築したUIはビルドするまで分からない?

XMLレイアウトだと作成したレイアウトを確認する用のウィンドウがAndroid Studio側で用意されており、見た目を確認しながらレイアウトを構築することが可能でしたが、Jetpack Composeを利用したレイアウトでも同様のことが可能です。

その方法は引数なしのComposable関数にPreviewアノテーションを付けるだけです。
Previewアノテーションを付けることにより、Android Studioのコードウィンドウの右上に存在する Code Split Design 3つのタブの内 SplitDesign のどちらかを選択することによってPreviewアノテーションを付けたComposable関数のレイアウトを確認出来ます。

@Preview
@Composable
fun FlexModifierTestPreview() {
    FlexModifierTest(Modifier.padding(20.dp))
}

引数が存在するとレイアウトの内容が確定しない可能性を孕むので、Previewアノテーションを付けることが出来ません。
Previewアノテーションは同じファイル内の関数であってもいくつでも付けることができるので、引数を持つComposable関数の値を変更したものを複数用意することによってレイアウトの比較等行えます。

おわりに

今回紹介したものは、ほんのさわりですが利用してみると従来のXMLレイアウトを確認して、コードを書き換えて...みたいな作業が発生しなくなるので、それだけで開発スピードがあがるのではと思いました。
また、UIを部品として定義することによって再利用性が高いという点や全てコードで完結することによってXMLレイアウトとのずれを意識しなくて良い点、標準で用意されているComposable関数がマテリアルデザインに沿った作りになっているので、デザインチームとの齟齬が起きづらくなるという点も有用性が高いと感じます。

まだまだスタート地点に立ったばかりなので、今後もJetpack Composeを利用する場合のアーキテクチャやデータの流れを考慮してのEvent処理や画面の更新等行うには、どう実装していくのがベターなのかを模索するためにも、学習を続けていきたいと思います。

ほんのさわりを記事にするだけでも、とても長くなってしまい読み苦しいところも多々あったと思いますが、ご一読頂きありがとうございます。

composeでUI構築して、coroutineで非同期通信して、dagger hiltで依存性を排除してテストを作りやすくして...夢が広がりんぐですね。
(頓挫しないよう勉強しよう...)

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?