Jetpack Compose入門 はじめの一歩

2022/03/17に公開

対象読者

Android開発を少しかじったことがあるが、Jetpack Composeをほとんど試したことがないエンジニア向けの記事です。入門も入門、本当に最初の一歩です。

内容

  • 環境構築して、Android Studioのテンプレートアプリを作成する
  • プレビューの表示の仕方
  • Color,Shape,Typographyなどを管理の仕方(Theme関数)
  • Composeの基本
  • Surface関数の簡単な説明
  • Modifierの簡単な説明

環境構築

以下を見るのが一番いいです。
https://developer.android.com/jetpack/compose/setup

とはいえ、もっとシンプルに今回用に簡単に書いときます。

Android Stuidoのメニュー 「File」 -> 「New Project」 -> 「Enpty Compose Activity」 を選択し、「Next」を押下します。

Enpty Compose Activity

適当な値を入力して、プロジェクトを作成します。

プロジェクト作成

できたソース

こんなソースができます。

class MainActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      SampleComposeTheme {
        // A surface container using the 'background' color from the theme
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
          Greeting("Android")
        }
      }
    }
  }
}

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

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
  SampleComposeTheme {
    Greeting("Android")
  }
}

プレビューの見方

Jetpack Composeでは、アプリをデバイスにインストールしなくともAndroid Studioのプレビュー画面でUIを確認できます。複数のプレビューを一度に見ることができます。

MainActivity.ktファイルを開き、右側にあるボタン「Split」にするとプレビュー画面が見れます。ここでBuild & Refreshを押下するとプレビュー画面が見れます。

これは、@Preview のアノテーションがついた関数の結果を表示しています。今のままのプレビューだと 「Hello Android」というTextビューが表示されるだけなので、全体の画面が見えるように以下のように変えてみます。SampleComposeThemeGreeting()関数に移動しただけです。

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

@Composable
fun Greeting(name: String) {
  SampleComposeTheme {
    Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
      Text(text = "Hello $name!")
    }
  }
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
  Greeting("Android")
}

ソースを変更した後に①のボタンを押下するとプレビュー画面に反映されます。ちなみに②を押下するとデバイスにインストールされます。①の方が高速なので基本的にはデザイン面はこれだけで実装していくのがいいでしょう。

ちなみに②の左側のアイコンはインタラクティブモードです。

この記事では扱いませんが、インタラクティブモードとは

サンドボックス環境で(他のプレビューから分離された状態で)実行されます。プレビューの要素をクリックしたり、ユーザー入力を行ったりできるほか、プレビューでアニメーションを再生することも可能です。このモードを使用することで、コンポーザブルのさまざまな状態や操作(チェックボックスのオンとオフの切り替えなど)を簡単にテストできます。

プレビューは複数記述できます。
たとえば、ダークモードのON/OFFの両方を一度に確認できます。

@Preview(
  uiMode = Configuration.UI_MODE_NIGHT_NO,
  showBackground = true
)
@Composable
fun DefaultPreview() {
  Greeting("Android")
}

@Preview(
  uiMode = Configuration.UI_MODE_NIGHT_YES,
  showBackground = true
)
@Composable
fun DarkPreview() {
  Greeting("Android")
}

ソースの説明

基本

  • @Composable アノテーションがついた関数がUIに変換されます。
  • onCreate()内の setContentの引数には必ず@Composableの関数が指定されます。
  • @Composable アノテーションがついた関数には引数を渡すことができます。
  • @Composable アノテーションがついた関数の中で、@Composable アノテーションがついた関数を呼び出すことでUIの階層を構築していきます。この階層を作ることで複雑なUIを実装することができます。
  • @Composable アノテーションがついた関数は冪等です。同じ引数を持つ関数は同じ結果を返すということです。
  • @Composable アノテーションがついた関数は副作用がありません。この関数でグローバル変数やインスタン変数などの変更はできないということです。

SampleComposeTheme関数について

これも単に@Composable 関数です。MaterialTheme関数(@Composable 関数)をラップしています。
Composeではこのような関数を作り、Color,Shape,Typographyなどを管理していくのが常套手段になります。

private val DarkColorPalette = darkColors(
  primary = Purple200,
  primaryVariant = Purple700,
  secondary = Teal200
)

private val LightColorPalette = lightColors(
  primary = Purple500,
  primaryVariant = Purple700,
  secondary = Teal200

  /* Other default colors to override
    background = Color.White,
    surface = Color.White,
    onPrimary = Color.White,
    onSecondary = Color.Black,
    onBackground = Color.Black,
    onSurface = Color.Black,
    */
)

@Composable
fun SampleComposeTheme(
  darkTheme: Boolean = isSystemInDarkTheme(),
  content: @Composable () -> Unit
) {
  val colors = if (darkTheme) {
    DarkColorPalette
  } else {
    LightColorPalette
  }

  MaterialTheme(
    colors = colors,
    typography = Typography,
    shapes = Shapes,
    content = content
  )
}

Surface関数について

マテリアルデザインにおけるSurfaceを表現する関数になります。
マテリアルデザインの中心的なメタファーです。Surfaceには高さがあり、他のSurfaceとどのように視覚的に関係し、そのSurfaceがどんな影を作るかなどを管理されます。
マテリアルデザインにおけるSurfaceの詳細は次のURLに記述されています。
https://material.io/design/environment/surfaces.html#material-environment

Surfaceの役割はドキュメントに以下と書かれています。

  1. Clipping: Surface clips its children to the shape specified by shape
  2. Elevation: Surface draws a shadow to represent depth, where elevation represents the depth of this surface. If the passed shape is concave the shadow will not be drawn on Android versions less than 10.
  3. Borders: If shape has a border, then it will also be drawn.
  4. Background: Surface fills the shape specified by shape with the color. If color is Colors.surface, the ElevationOverlay from LocalElevationOverlay will be used to apply an overlay - by default this will only occur in dark theme. The color of the overlay depends on the elevation of this Surface, and the LocalAbsoluteElevation set by any parent surfaces. This ensures that a Surface never appears to have a lower elevation overlay than its ancestors, by summing the elevation of all previous Surfaces.
  5. Content color: Surface uses contentColor to specify a preferred color for the content of this surface - this is used by the Text and Icon components as a default color.
  6. Blocking touch propagation behind the surface.

modifierについて

@Composable関数(=以降はコンポーザブルと呼びます)は、ほとんどmodifierパラメーターがついています。

日本語にすると修飾子です。コンポーザブルを装飾できます。
以下ができます。

  • コンポーザブルのサイズ、レイアウト、動作、外観を変更する
  • ユーザー補助ラベルなどの情報を追加する
  • ユーザー入力を処理する
  • 要素をクリック可能、スクロール可能、ドラッグ可能、ズーム可能にするなど、高レベルの操作を追加する

今回の場合は、Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) と記述されているので、fillMaxSize()によって、すべての縦横を子レイアウトで埋める処理になっています。

まとめ

簡単なソースですが、ひとつひとつを読み込んでみると色々な学びがあったと思います。
まずは、基本を平たく覚えて、少しづつそれぞれの要素を深ぼっていくのが、覚えていくのにいい気がします。

この記事のコードで見えるメリットは

  • UIもコードで書ける(XML不要)
  • 複数のプレビューが表示される。しかもデバイスへのインストール不要で高速
  • ダークモード対応やTheme設定が簡単

あと、経験していくとよりわかるメリットとして

  • UIを関数で分割できる。小さく考えて、階層的に組み立てられる
  • UIが副作用なしで冪等なので、シンプルに考えられる

かなと思います。

この記事ではわからないですが、その他に

  • 値の変更が勝手にUIに反映される
    という宣言的UIの大きなメリットがあります。

ちなみにこれらはFlutterやSwiftUIなどの宣言的UIなプロダクトの特徴でもあります。
この記事をきっかけにJetpack Composeを始めた人が増えると幸いです。
次回も初心者向けの記事を書きたいと思います。

NewsPicks の Zenn

Discussion