変更点
Modifierのパフォーマンスが向上したのは以下の開発者ブログの通りです。
https://android-developers.googleblog.com/2023/08/whats-new-in-jetpack-compose-august-23-release.html
Modifierには Modifier.composed {}
という、ステートフルなModifierを実装する事ができる機能があります。これはComposableな関数を引数に取るため、前回と同じModifierの状態になるかは、処理を走らせてからでないと比較する事ができませんでした。
ステートフルなModifierをComposableな関数を使わずに、単純に比較できるようにしたというのが今回の変更です。
実装してみる
今回は以下の、サイズはそのままに、表示状態だけ切り替えるvisibility機能を作成してみます。
Compose UIは1.4系を使用しています。
public fun Modifier.visibility( isVisible: Boolean, ): Modifier
Modifier.Node
まずはModifier.Nodeを継承します。今まではModifier.Elementが直接使用されていました。
描画周りを変更したいので、 DrawModifierNode
を実装します。
mutableな変数を持ち、それを使用するコードを書きます。
@OptIn(ExperimentalComposeUiApi::class) private class VisibilityModifierNode( var isVisible: Boolean, ) : Modifier.Node(), DrawModifierNode { override fun ContentDrawScope.draw() { if (isVisible) { drawContent() } } }
ModifierNodeElement
続いて、ModifierNodeElement
を継承したクラスを作成します。ModifierNodeElement
は Modifier.Element
を継承しています。
そして、ModifierNodeElement
で重要な部分は以下です。hashCode
と equals
を必ず実装するようにコメントがあります。これによってステートフルでも単純に比較できるModifierが作成されるわけです。data classを使えばhashとequalsは自動で作成されるので、それで十分です。
// Require hashCode() to be implemented. Using a data class is sufficient. Singletons and // modifiers with no parameters may implement this function by returning an arbitrary constant. abstract override fun hashCode(): Int // Require equals() to be implemented. Using a data class is sufficient. Singletons may // implement this function with referential equality (`this === other`). Modifiers with no // inputs may implement this function by checking the type of the other object. abstract override fun equals(other: Any?): Boolean
以下のようにcreate
とupdate
を実装します。
@OptIn(ExperimentalComposeUiApi::class) private data class VisibilityModifierNodeElement( private val isVisible: Boolean, ) : ModifierNodeElement<VisibilityModifierNode>() { override fun InspectorInfo.inspectableProperties() { name = "isVisible" properties["isVisible"] = isVisible } override fun create(): VisibilityModifierNode { return VisibilityModifierNode(isVisible = isVisible) } override fun update(node: VisibilityModifierNode): VisibilityModifierNode { // 1.5系では戻り値が無くなっている node.isVisible = isVisible return node } }
Modifier
これで比較可能でステートフルなModifier.Elementが作成できました。
後はModifierの拡張関数として定義してあげれば良いです。サンプルコード見ていて気が付きましたが、thenって中置演算子だったんですね。
public fun Modifier.visibility( isVisible: Boolean, ): Modifier = this then VisibilityModifierNodeElement(isVisible = isVisible)
CompositionLocalを使用する
CompositionLocalを参照したい場合は以下にサンプルコードがあります。1.5系が必要です。
androidx.compose.ui.node.CompositionLocalConsumerModifierNode
を継承し、currentValueOf
で取り出せます。
https://cs.android.com/androidx/platform/tools/dokka-devsite-plugin/+/4fb986840db2b2383d29be0aa982f2e08bcc3d88:testData/compose/samples/ui/samples/ModifierCompositionLocalSample.kt;bpv=0