1
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】Modifierを自作する

Posted at

はじめに

突然ですがみなさんはJetpack ComposeのModifierを自作したことはあるでしょうか。カスタムModifierを作る方法は大きく2つあります。

  1. 既存のModifierをラップする方法
  2. Modifier.NodeModifierNodeElementを実装する方法

今回は後者の方法で背景を単色で塗りつぶすModifierを自作してみようと思います。

この記事を通してModifierの仕組みを理解し、より自由度の高いカスタムModifierを作るヒントになっていると幸いです。

カスタムModifierを作る流れ

以下の大きく3ステップに分かれます。

  1. Modifier.Nodeを実装する
  2. ModifierNodeElementを実装する
  3. ModifierのExtensionを実装する

1.がModifierの振る舞いを決めるメインの実装部分になります。2.は1.で作成したModifier.Nodeのインスタンスを管理したりデバッグ用の情報を提供したりする部分になります。3.は既存のModifierと組み合わせて使えるようにする部分になります。

順番に作っていきましょう。

Modifier.Node を作る

Modifier.Nodeを作っていきます。今回は背景色を塗りつぶすという描画に関するModifierのためDrawModifierNodeを使用します。他にもModifierの役割に応じて様々なノードタイプが用意されており、例えばLayoutModifierNodeやPointerInputModifierNodeなどがあります。

背景を単色で塗りつぶすためにdrawRect()を呼び出します。引数のsizeを省略すると領域いっぱいに描画されます。

またdrawRect()を呼び出した後にdrawContent()を呼び出すのを忘れないでください。これを呼び出さないと矩形が描画されるだけでModifierを適用したComposableの内容が描画されなくなるので注意です。

class BackgroundNode(var color: Color) : DrawModifierNode, Modifier.Node() {
    override fun ContentDrawScope.draw() {
        drawRect(color = color) // コンテンツの背後に矩形を描画
        drawContent() // コンテンツを描画(忘れないで!)
    }
}

ModifierNodeElementを実装する

ModifierNodeElement<BackgroundNode>()を実装したクラスを作成します。必ず実装する必要のあるメソッドはfun create()fun update(BackgroundNode)の2つです。

fun create()はレイアウトに初めてModifierが適用されるときに呼ばれるもので、Modifier.Nodeのインスタンスを返せばOKです。

fun update()はレイアウトの入力に変更があった際に呼ばれます。基本的には最新の状態が保たれるようにModifier.Nodeのインスタンスのパラメータを更新すればOKです。インスタンスをコピーして新しいインスタンスを作りたくなるところですが、パフォーマンスのために同じインスタンスを使い回すのが一般的なため、プロパティを書き換えられるように先ほど作ったBackgroundNodecolorプロパティはvarで宣言しています。

ちなみにModifierNodeElementのクラスにdata classを使用しているのもパフォーマンスが理由で、equals()hashCode()の自動生成を活用し同じインスタンスを再利用するためです。

InspectorInfo.inspectableProperties() の実装は任意です。ここで設定した内容はAndroid StudioのLayout Inspectorで確認することができます。デバッグ時に便利なので実装しておくことをおすすめします。

data class BackgroundElement(val color: Color) : ModifierNodeElement<BackgroundNode>() {
    override fun create(): BackgroundNode {
        return BackgroundNode(color)
    }


    override fun update(node: BackgroundNode) {
        node.color = color
    }

    override fun InspectorInfo.inspectableProperties() {
        name = "Background"
        properties["color"] = color
    }
}

image.png

ModifierのExtensionを実装する

既存のModifierとチェーンして呼び出せるようにModifierのExtensionを定義します。infix関数のthenはModifierとModifierをチェーンします。

fun Modifier.backgroundColor(color: Color) = this then BackgroundElement(color)

使用する側はこんな感じです。

Text(
    text = "Compose",
    modifier = Modifier
        .backgroundColor(Color.Yellow)
        .padding(16.dp)
)

完成!

image.png

Modifierについてさらに詳しく

ModifierはJetpack Composeの中でも奥が深く、カスタマイズ性に富んだ面白い技術です。
もっと詳しく知りたい方は以下の資料などを参考にしてみてください :thumbsup:

1
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
1
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?