Loading mechanics/src/com/android/mechanics/behavior/EdgeContainerExpansionBackground.kt→mechanics/src/com/android/mechanics/behavior/VerticalExpandContainerBackground.kt +59 −5 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.mechanics.behavior import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Rect Loading @@ -34,19 +35,72 @@ import androidx.compose.ui.util.fastCoerceIn import androidx.compose.ui.util.lerp import kotlin.math.min /** * Draws the background of a vertically container, and applies clipping to it. * * Intended to be used with a [VerticalExpandContainerSpec] motion. */ fun Modifier.verticalExpandContainerBackground( backgroundColor: Color, spec: VerticalExpandContainerSpec, ): Modifier = this.then( if (spec.isFloating) { Modifier.verticalFloatingExpandContainerBackground(backgroundColor, spec) } else { Modifier.verticalEdgeExpandContainerBackground(backgroundColor, spec) } ) /** * Draws the background of an floating container, and applies clipping to it. * * Intended to be used with a [VerticalExpandContainerSpec] motion. */ internal fun Modifier.verticalFloatingExpandContainerBackground( backgroundColor: Color, spec: VerticalExpandContainerSpec, ): Modifier = this.drawWithCache { val targetRadiusPx = spec.radius.toPx() val currentRadiusPx = min(targetRadiusPx, min(size.width, size.height) / 2f) val horizontalInset = targetRadiusPx - currentRadiusPx val shapeTopLeft = Offset(horizontalInset, 0f) val shapeSize = Size(size.width - (horizontalInset * 2f), size.height) val layer = obtainGraphicsLayer().apply { clip = true setRoundRectOutline(shapeTopLeft, shapeSize, cornerRadius = currentRadiusPx) record { drawContent() } } onDrawWithContent { drawRoundRect( color = backgroundColor, topLeft = shapeTopLeft, size = shapeSize, cornerRadius = CornerRadius(currentRadiusPx), ) drawLayer(layer) } } /** * Draws the background of an edge container, and applies clipping to it. * * Intended to be used with a [EdgeContainerExpansionSpec] motion. * Intended to be used with a [VerticalExpandContainerSpec] motion. */ fun Modifier.edgeContainerExpansionBackground( internal fun Modifier.verticalEdgeExpandContainerBackground( backgroundColor: Color, spec: EdgeContainerExpansionSpec, spec: VerticalExpandContainerSpec, ): Modifier = this.then(EdgeContainerExpansionBackgroundElement(backgroundColor, spec)) internal class EdgeContainerExpansionBackgroundNode( var backgroundColor: Color, var spec: EdgeContainerExpansionSpec, var spec: VerticalExpandContainerSpec, ) : Modifier.Node(), DrawModifierNode { private var graphicsLayer: GraphicsLayer? = null Loading Loading @@ -126,7 +180,7 @@ internal class EdgeContainerExpansionBackgroundNode( private data class EdgeContainerExpansionBackgroundElement( val backgroundColor: Color, val spec: EdgeContainerExpansionSpec, val spec: VerticalExpandContainerSpec, ) : ModifierNodeElement<EdgeContainerExpansionBackgroundNode>() { override fun create(): EdgeContainerExpansionBackgroundNode = EdgeContainerExpansionBackgroundNode(backgroundColor, spec) Loading mechanics/src/com/android/mechanics/behavior/EdgeContainerExpansionSpec.kt→mechanics/src/com/android/mechanics/behavior/VerticalExpandContainerSpec.kt +14 −10 Original line number Diff line number Diff line Loading @@ -34,19 +34,21 @@ import com.android.mechanics.spec.MotionSpec import com.android.mechanics.spec.OnChangeSegmentHandler import com.android.mechanics.spec.SegmentData import com.android.mechanics.spec.SegmentKey import com.android.mechanics.spec.buildDirectionalMotionSpec import com.android.mechanics.spec.builder import com.android.mechanics.spec.reverseBuilder import com.android.mechanics.spring.SpringParameters /** Motion spec for a vertically expandable container. */ class EdgeContainerExpansionSpec( class VerticalExpandContainerSpec( val isFloating: Boolean, val minRadius: Dp = Defaults.MinRadius, val radius: Dp = Defaults.Radius, val visibleHeight: Dp = Defaults.VisibleHeight, val preDetachRatio: Float = Defaults.PreDetachRatio, val detachHeight: Dp = Defaults.DetachHeight, val attachHeight: Dp = Defaults.AttachHeight, val detachHeight: Dp = if (isFloating) radius * 3 else Defaults.DetachHeight, val attachHeight: Dp = if (isFloating) radius * 2 else Defaults.AttachHeight, val widthOffset: Dp = Defaults.WidthOffset, val minRadius: Dp = Defaults.MinRadius, val radius: Dp = Defaults.Radius, val attachSpring: SpringParameters = Defaults.AttachSpring, val detachSpring: SpringParameters = Defaults.DetachSpring, val opacitySpring: SpringParameters = Defaults.OpacitySpring, Loading Loading @@ -99,14 +101,16 @@ class EdgeContainerExpansionSpec( density: Density, ): MotionSpec { return with(density) { MotionSpec.builder( SpringParameters(motionScheme.defaultSpatialSpec()), initialMapping = { input -> if (isFloating) { MotionSpec(buildDirectionalMotionSpec(Mapping.Fixed(intrinsicWidth))) } else { MotionSpec( buildDirectionalMotionSpec({ input -> val fraction = (input / detachHeight.toPx()).fastCoerceIn(0f, 1f) intrinsicWidth - lerp(widthOffset.toPx(), 0f, fraction) }, }) ) .complete() } } } Loading Loading
mechanics/src/com/android/mechanics/behavior/EdgeContainerExpansionBackground.kt→mechanics/src/com/android/mechanics/behavior/VerticalExpandContainerBackground.kt +59 −5 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.mechanics.behavior import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Rect Loading @@ -34,19 +35,72 @@ import androidx.compose.ui.util.fastCoerceIn import androidx.compose.ui.util.lerp import kotlin.math.min /** * Draws the background of a vertically container, and applies clipping to it. * * Intended to be used with a [VerticalExpandContainerSpec] motion. */ fun Modifier.verticalExpandContainerBackground( backgroundColor: Color, spec: VerticalExpandContainerSpec, ): Modifier = this.then( if (spec.isFloating) { Modifier.verticalFloatingExpandContainerBackground(backgroundColor, spec) } else { Modifier.verticalEdgeExpandContainerBackground(backgroundColor, spec) } ) /** * Draws the background of an floating container, and applies clipping to it. * * Intended to be used with a [VerticalExpandContainerSpec] motion. */ internal fun Modifier.verticalFloatingExpandContainerBackground( backgroundColor: Color, spec: VerticalExpandContainerSpec, ): Modifier = this.drawWithCache { val targetRadiusPx = spec.radius.toPx() val currentRadiusPx = min(targetRadiusPx, min(size.width, size.height) / 2f) val horizontalInset = targetRadiusPx - currentRadiusPx val shapeTopLeft = Offset(horizontalInset, 0f) val shapeSize = Size(size.width - (horizontalInset * 2f), size.height) val layer = obtainGraphicsLayer().apply { clip = true setRoundRectOutline(shapeTopLeft, shapeSize, cornerRadius = currentRadiusPx) record { drawContent() } } onDrawWithContent { drawRoundRect( color = backgroundColor, topLeft = shapeTopLeft, size = shapeSize, cornerRadius = CornerRadius(currentRadiusPx), ) drawLayer(layer) } } /** * Draws the background of an edge container, and applies clipping to it. * * Intended to be used with a [EdgeContainerExpansionSpec] motion. * Intended to be used with a [VerticalExpandContainerSpec] motion. */ fun Modifier.edgeContainerExpansionBackground( internal fun Modifier.verticalEdgeExpandContainerBackground( backgroundColor: Color, spec: EdgeContainerExpansionSpec, spec: VerticalExpandContainerSpec, ): Modifier = this.then(EdgeContainerExpansionBackgroundElement(backgroundColor, spec)) internal class EdgeContainerExpansionBackgroundNode( var backgroundColor: Color, var spec: EdgeContainerExpansionSpec, var spec: VerticalExpandContainerSpec, ) : Modifier.Node(), DrawModifierNode { private var graphicsLayer: GraphicsLayer? = null Loading Loading @@ -126,7 +180,7 @@ internal class EdgeContainerExpansionBackgroundNode( private data class EdgeContainerExpansionBackgroundElement( val backgroundColor: Color, val spec: EdgeContainerExpansionSpec, val spec: VerticalExpandContainerSpec, ) : ModifierNodeElement<EdgeContainerExpansionBackgroundNode>() { override fun create(): EdgeContainerExpansionBackgroundNode = EdgeContainerExpansionBackgroundNode(backgroundColor, spec) Loading
mechanics/src/com/android/mechanics/behavior/EdgeContainerExpansionSpec.kt→mechanics/src/com/android/mechanics/behavior/VerticalExpandContainerSpec.kt +14 −10 Original line number Diff line number Diff line Loading @@ -34,19 +34,21 @@ import com.android.mechanics.spec.MotionSpec import com.android.mechanics.spec.OnChangeSegmentHandler import com.android.mechanics.spec.SegmentData import com.android.mechanics.spec.SegmentKey import com.android.mechanics.spec.buildDirectionalMotionSpec import com.android.mechanics.spec.builder import com.android.mechanics.spec.reverseBuilder import com.android.mechanics.spring.SpringParameters /** Motion spec for a vertically expandable container. */ class EdgeContainerExpansionSpec( class VerticalExpandContainerSpec( val isFloating: Boolean, val minRadius: Dp = Defaults.MinRadius, val radius: Dp = Defaults.Radius, val visibleHeight: Dp = Defaults.VisibleHeight, val preDetachRatio: Float = Defaults.PreDetachRatio, val detachHeight: Dp = Defaults.DetachHeight, val attachHeight: Dp = Defaults.AttachHeight, val detachHeight: Dp = if (isFloating) radius * 3 else Defaults.DetachHeight, val attachHeight: Dp = if (isFloating) radius * 2 else Defaults.AttachHeight, val widthOffset: Dp = Defaults.WidthOffset, val minRadius: Dp = Defaults.MinRadius, val radius: Dp = Defaults.Radius, val attachSpring: SpringParameters = Defaults.AttachSpring, val detachSpring: SpringParameters = Defaults.DetachSpring, val opacitySpring: SpringParameters = Defaults.OpacitySpring, Loading Loading @@ -99,14 +101,16 @@ class EdgeContainerExpansionSpec( density: Density, ): MotionSpec { return with(density) { MotionSpec.builder( SpringParameters(motionScheme.defaultSpatialSpec()), initialMapping = { input -> if (isFloating) { MotionSpec(buildDirectionalMotionSpec(Mapping.Fixed(intrinsicWidth))) } else { MotionSpec( buildDirectionalMotionSpec({ input -> val fraction = (input / detachHeight.toPx()).fastCoerceIn(0f, 1f) intrinsicWidth - lerp(widthOffset.toPx(), 0f, fraction) }, }) ) .complete() } } } Loading