ModifierNodeElement.kt
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.ui.node
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.InspectableValue
import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.platform.ValueElement
import androidx.compose.ui.tryPopulateReflectively
/**
* A [Modifier.Element] which manages an instance of a particular [Modifier.Node] implementation. A
* given [Modifier.Node] implementation can only be used when a [ModifierNodeElement] which creates
* and updates that implementation is applied to a Layout.
*
* A [ModifierNodeElement] should be very lightweight, and do little more than hold the information
* necessary to create and maintain an instance of the associated [Modifier.Node] type.
*
* @sample androidx.compose.ui.samples.ModifierNodeElementSample
* @sample androidx.compose.ui.samples.SemanticsModifierNodeSample
*
* @see Modifier.Node
* @see Modifier.Element
*/
abstract class ModifierNodeElement<N : Modifier.Node> : Modifier.Element, InspectableValue {
/**
* If this property returns `true`, then nodes will be automatically invalidated after the
* [update] callback completes (For example, if the returned Node is a [DrawModifierNode], its
* [DrawModifierNode.invalidateDraw] function will be invoked automatically as part of
* auto invalidation).
*
* This is enabled by default, and provides a convenient mechanism to schedule invalidation
* and apply changes made to the modifier. You may choose to set this to `false` if your
* modifier has auto-invalidatable properties that do not frequently require invalidation to
* improve performance by skipping unnecessary invalidation. If `autoInvalidate` is set to
* `false`, you must call the appropriate invalidate functions manually in [update] for the
* new attributes to become visible.
*/
open val autoInvalidate: Boolean
get() = true
private var _inspectorValues: InspectorInfo? = null
private val inspectorValues: InspectorInfo
get() = _inspectorValues ?: InspectorInfo()
.apply {
name = this@ModifierNodeElement::class.simpleName
inspectableProperties()
}
.also { _inspectorValues = it }
final override val nameFallback: String?
get() = inspectorValues.name
final override val valueOverride: Any?
get() = inspectorValues.value
final override val inspectableElements: Sequence<ValueElement>
get() = inspectorValues.properties
/**
* This will be called the first time the modifier is applied to the Layout and it should
* construct and return the corresponding [Modifier.Node] instance.
*/
abstract fun create(): N
/**
* Called when a modifier is applied to a Layout whose inputs have changed from the previous
* application. This function will have the current node instance passed in as a parameter, and
* it is expected that the node will be brought up to date.
*/
abstract fun update(node: N): N
/**
* Populates an [InspectorInfo] object with attributes to display in the layout inspector. This
* is called by tooling to resolve the properties of this modifier. By convention, implementors
* should set the [name][InspectorInfo.name] to the function name of the modifier.
*
* The default implementation will attempt to reflectively populate the inspector info with the
* properties declared on the subclass. It will also set the [name][InspectorInfo.name] property
* to the name of this instance's class by default (not the name of the modifier function).
* Modifier property population depends on the kotlin-reflect library. If it is not in the
* classpath at runtime, the default implementation of this function will populate the
* properties with an error message.
*
* If you override this function and provide the properties you wish to display, you do not need
* to call `super`. Doing so may result in duplicate properties appearing in the layout
* inspector.
*/
open fun InspectorInfo.inspectableProperties() {
tryPopulateReflectively(this@ModifierNodeElement)
}
// 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
}