All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.androidx.compose.ui.layout.ApproachMeasureScope.kt Maven / Gradle / Ivy

Go to download

Compose UI primitives. This library contains the primitives that form the Compose UI Toolkit, such as drawing, measurement and layout.

There is a newer version: 1.8.0-alpha01
Show newest version
/*
 * Copyright 2024 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.
 */

@file:OptIn(ExperimentalComposeUiApi::class)

package androidx.compose.ui.layout

import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.node.LayoutModifierNodeCoordinator
import androidx.compose.ui.node.NodeCoordinator
import androidx.compose.ui.node.checkMeasuredSize
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize

/**
 * The receiver scope of a layout's intrinsic approach measurements lambdas.
 */
sealed interface ApproachIntrinsicMeasureScope : IntrinsicMeasureScope {

    /**
     * Constraints used to measure the layout in the lookahead pass.
     */
    val lookaheadConstraints: Constraints

    /**
     * Size of the [ApproachLayoutModifierNode] measured during the lookahead pass using
     * [lookaheadConstraints]. This size can be used as the target size for the
     * [ApproachLayoutModifierNode] to approach the destination (i.e. lookahead) size.
     */
    val lookaheadSize: IntSize
}

/**
 * [ApproachMeasureScope] provides access to lookahead results to allow
 * [ApproachLayoutModifierNode] to leverage lookahead results to define how
 * measurements and placements approach their destination.
 *
 * [ApproachMeasureScope.lookaheadSize] provides the target size of the layout.
 * By knowing the target size and position, layout adjustments such as animations can be defined
 * in [ApproachLayoutModifierNode] to morph the layout gradually in both size and position
 * to arrive at its precalculated bounds.
 */
sealed interface ApproachMeasureScope : ApproachIntrinsicMeasureScope, MeasureScope

internal class ApproachMeasureScopeImpl(
    val coordinator: LayoutModifierNodeCoordinator,
    var approachNode: ApproachLayoutModifierNode,
) : ApproachMeasureScope, MeasureScope by coordinator, LookaheadScope {
    override val lookaheadConstraints: Constraints
        get() = requireNotNull(coordinator.lookaheadConstraints) {
            "Error: Lookahead constraints requested before lookahead measure."
        }
    override val lookaheadSize: IntSize
        get() = coordinator.lookaheadDelegate!!.measureResult.let { IntSize(it.width, it.height) }

    internal var approachMeasureRequired: Boolean = false

    override fun LayoutCoordinates.toLookaheadCoordinates(): LayoutCoordinates {
        if (this is LookaheadLayoutCoordinates) return this
        if (this is NodeCoordinator) {
            return lookaheadDelegate?.lookaheadLayoutCoordinates ?: this
        }
        throw IllegalArgumentException("Unsupported LayoutCoordinates: $this")
    }

    override val Placeable.PlacementScope.lookaheadScopeCoordinates: LayoutCoordinates
        get() {
            val lookaheadRoot = coordinator.layoutNode.lookaheadRoot
            requireNotNull(lookaheadRoot) {
                "Error: Requesting LookaheadScopeCoordinates is not permitted from outside of a" +
                    " LookaheadScope."
            }
            return if (lookaheadRoot.isVirtualLookaheadRoot) {
                lookaheadRoot.parent?.innerCoordinator
                // Root node is in a lookahead scope
                    ?: lookaheadRoot.children[0].outerCoordinator
            } else {
                lookaheadRoot.outerCoordinator
            }
        }

    override fun layout(
        width: Int,
        height: Int,
        alignmentLines: Map,
        rulers: (RulerScope.() -> Unit)?,
        placementBlock: Placeable.PlacementScope.() -> Unit
    ): MeasureResult {
        checkMeasuredSize(width, height)
        return object : MeasureResult {
            override val width = width
            override val height = height

            @Suppress("PrimitiveInCollection")
            override val alignmentLines = alignmentLines
            override val rulers = rulers
            override fun placeChildren() {
                coordinator.placementScope.placementBlock()
            }
        }
    }

    // Intermediate layout pass is post-lookahead. Therefore isLookingAhead is always false.
    override val isLookingAhead: Boolean
        get() = false
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy