LoginSignup
8
5

More than 3 years have passed since last update.

Jetpack ComposeのConstraintLayoutなどがどのようにModifierクラスだけで様々なレイアウトを処理するか

Posted at

こんなKotlin DSLの使い方あるんだと思って知らなかったのでメモしておきます。

Jetpack ComposeのConstraintLayoutは現状では、以下のように書きます。

https://android-review.googlesource.com/c/platform/frameworks/support/+/1321040/8/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/ConstraintLayoutDemo.kt より

    ConstraintLayout {
        val (text1, text2, text3) = createRefs()

        Text("Text1", Modifier.constrainAs(text1) {
            start.linkTo(text2.end, margin = 20.dp)
        })
        Text("Text2", Modifier.constrainAs(text2) {
            centerTo(parent)
        })

        val barrier = createBottomBarrier(text1, text2)
        Text("This is a very long text", Modifier.constrainAs(text3) {
            top.linkTo(barrier, margin = 20.dp)
            centerHorizontallyTo(parent)
            width = Dimension.preferredWrapContent.atMost(40.dp)
        })
    }

以下のように Modifier.constrainAs() を使うことができていますが、これがConstraintLayout以外のレイアウトでも見えてしまうと全く関係ないレイアウトでConstraintLayoutのプロパティが使えてカオスになってしまいます。しかもModifierはただのinterfaceです。どのようにしているのでしょうか?

    ConstraintLayout {
        val (text1, text2, text3) = createRefs()

        Text("Text1", Modifier.constrainAs(text1) {
            start.linkTo(text2.end, margin = 20.dp)
        })

最初にコードで結論を書くと以下のように、スコープを作って、interfaceを継承したcompanion objectを実装して、companion objectとインスタンス両方に対しての拡張関数を定義して、そのスコープから呼び出してあげることで、スコープ内のみでしかCompanion objectのメソッドも使えないようにすることができます。

interface MyModifier {
    companion object : MyModifier
}

class MyLayoutScope {
    fun MyModifier.myCustomMethod() {
    }
}

fun myLayout() {
    MyLayoutScope().apply {
        MyModifier.myCustomMethod()
    }
}

以下どうやっているかのメモ

ConstraintLayout{}で ConstraintLayoutScopeのブロックを渡させる。

@Composable
fun ConstraintLayout(
    modifier: Modifier = Modifier,
    children: @Composable ConstraintLayoutScope.() -> Unit
) {

ConstraintLayoutScopeにはModifier.constrainAs()という拡張関数がある。

image.png

拡張関数だけではModifier.constrainAs()のようにstatic methodの呼び出しのようにすることはできないのを以下のようにinterfaceを継承したcompanion objectを実装することで可能にしている。

@Stable
interface Modifier {
...
    companion object : Modifier {
8
5
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
8
5