Jetpack Composeを使ってみたい①

Jetpack Composeを使ってみたい!と思ってCodelabを元に勉強してみた記録。
Jetpack Compose  |  Android デベロッパー  |  Android Developers

まずはチュートリアルより。
Android Compose のチュートリアル  |  Android デベロッパー  |  Android Developers

Jetpack Composeとは

Android 向けの宣言型UIフレームワーク
kotlinでコンポーズ関数としてUIを定義するとComposeコンパイラが画面を構築する。
コードがシンプルで直感的になる。

コンポーズ可能な関数

@Composableアノテーションをつけてコンポーズ可能な関数(コンポーザブル)を定義する。
このアノテーションによってコンパイラにUIに変換する関数であることを伝える。
コンポーズ関数はパラメータを受け入れることができる。
この例では、Textコンポーザブルを呼び出してテキストを表示する。

@Composable
fun MessageCard(msg: Message) {
    Text(text = msg)

@Previewアノテーションをつけるとアプリをビルドせずにプレビューが表示できる。

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}

定義したコンポーザブルはonCreate メソッド内のsetContentブロックから呼び出される。

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

レイアウト

複数の要素を追加する場合、単に並べて記述するだけでは重なって表示されてしまう。

@Composable
fun MessageCard(msg: Message) {
    //NG
    Text(text = msg.author)
    Text(text = msg.body)
}

Column 関数を使用すると垂直方向に、Row関数を使用すると水平方向に要素を揃えることができ、
Box関数を使用すると要素を積み重ねることができる。
以下の例ではRowで画像とテキストが横並びに、テキストはColumnを使用して縦に2行表示される。
また、レイアウト(サイズや形、余白など)を整えるために修飾子Modifierを使用する。

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
           //連結して複数指定できる
        )

        Spacer(modifier = Modifier.width(8.dp))

        Column {
            Text(text = msg.author)
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}

マテリアルデザイン

AndroidStudioで [Empty Compose Activity] を選択してプロジェクトを作成すると、
ui.theme サブパッケージ内にファイルがデフォルトで作成されており、
「プロジェクト名Theme」という名前でマテリアルテーマが定義されている。
マテリアルテーマでコンポーザブルをラップすることで、
定義されたテーマを継承することができ、アプリ内で一貫性が保てる。

@Preview
@Composable
fun PreviewMessageCard() {
    ComposeTutorialTheme {
        MessageCard(
            msg = Message("Colleague", "Take a look at Jetpack Compose, it's great!")
        )
    }
}

リスト

リストを表示するにはLazyColumnもしくはLazyRowを使用する。
このコンポーザブルは画面上に表示される要素のみを生成して表示するため、長いリストで効果を発揮する。
子要素としてitemsを持ち、パラメータとして表示したいリストを受け取り、
ラムダでリスト内のアイテムごとにUIを記述する。

@Composable
fun Conversation(messages: List<Message>) {
    LazyColumn {
        items(messages) { message -> 
            MessageCard(message)
            //リストmessagesのアイテムごとにMessageCardコンポーザブルを呼び出す
        }
    }
}

状態変化

状態の変更によってUIが自動的に更新(再コンポジション)されるためには、
mutableStateOf関数に変更する可能性のある状態(値)を渡し、
remember関数を使用してその状態を保存して、変更をトラッキングする。

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        ...
        var isExpanded by remember { mutableStateOf(false) }

        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            ...
        }
    }
}

この例ではColumnがクリックされてisExpandedの値が変更されると、
状態の変更を認識して再コンポジションされる。