@@ -13,10 +13,14 @@ import androidx.compose.foundation.layout.ColumnScope
1313import androidx.compose.foundation.layout.Row
1414import androidx.compose.foundation.layout.RowScope
1515import androidx.compose.foundation.layout.Spacer
16+ import androidx.compose.foundation.layout.fillMaxHeight
1617import androidx.compose.foundation.layout.height
18+ import androidx.compose.foundation.layout.heightIn
1719import androidx.compose.foundation.layout.padding
1820import androidx.compose.foundation.layout.size
1921import androidx.compose.foundation.layout.width
22+ import androidx.compose.foundation.layout.widthIn
23+ import androidx.compose.foundation.layout.wrapContentSize
2024import androidx.compose.animation.AnimatedContent
2125import androidx.compose.animation.animateColorAsState
2226import androidx.compose.animation.core.AnimationSpec
@@ -893,16 +897,7 @@ internal fun ViewNode.composeModifiers(): Modifier {
893897 }
894898 }
895899
896- " frame" -> {
897- val width = entry.args.double(" width" )
898- val height = entry.args.double(" height" )
899- when {
900- width != null && height != null -> modifier.size(animatedDp(width.dp, spec), animatedDp(height.dp, spec))
901- width != null -> modifier.width(animatedDp(width.dp, spec))
902- height != null -> modifier.height(animatedDp(height.dp, spec))
903- else -> modifier
904- }
905- }
900+ " frame" -> foldFrame(modifier, entry, spec)
906901
907902 " background" -> {
908903 val argb = entry.args.long(" color" ) ? : 0
@@ -961,6 +956,56 @@ internal fun ViewNode.composeModifiers(): Modifier {
961956 return modifier
962957}
963958
959+ // Folds a frame entry: fixed size, fill (maxWidth/Height .infinity), bounded
960+ // (widthIn/heightIn), and content alignment within the resulting box.
961+ @Composable
962+ private fun foldFrame (base : Modifier , entry : ModifierNode , spec : AnimSpec ? ): Modifier {
963+ var m = base
964+ val fixedW = entry.args.double(" width" )
965+ val fixedH = entry.args.double(" height" )
966+ val minW = entry.args.double(" minWidth" )
967+ val maxW = entry.args.double(" maxWidth" )
968+ val minH = entry.args.double(" minHeight" )
969+ val maxH = entry.args.double(" maxHeight" )
970+ val fillW = entry.args.bool(" fillWidth" ) == true
971+ val fillH = entry.args.bool(" fillHeight" ) == true
972+
973+ when {
974+ fixedW != null -> m = m.width(animatedDp(fixedW.dp, spec))
975+ fillW -> m = m.fillMaxWidth()
976+ minW != null || maxW != null -> m = m.widthIn(
977+ min = minW?.dp ? : Dp .Unspecified ,
978+ max = maxW?.dp ? : Dp .Unspecified ,
979+ )
980+ }
981+ when {
982+ fixedH != null -> m = m.height(animatedDp(fixedH.dp, spec))
983+ fillH -> m = m.fillMaxHeight()
984+ minH != null || maxH != null -> m = m.heightIn(
985+ min = minH?.dp ? : Dp .Unspecified ,
986+ max = maxH?.dp ? : Dp .Unspecified ,
987+ )
988+ }
989+ val h = entry.args.string(" horizontal" )
990+ val v = entry.args.string(" vertical" )
991+ if (h != null || v != null ) {
992+ m = m.wrapContentSize(frameAlignment(h ? : " center" , v ? : " center" ))
993+ }
994+ return m
995+ }
996+
997+ private fun frameAlignment (horizontal : String , vertical : String ): Alignment = when (vertical to horizontal) {
998+ " top" to " leading" -> Alignment .TopStart
999+ " top" to " center" -> Alignment .TopCenter
1000+ " top" to " trailing" -> Alignment .TopEnd
1001+ " center" to " leading" -> Alignment .CenterStart
1002+ " center" to " trailing" -> Alignment .CenterEnd
1003+ " bottom" to " leading" -> Alignment .BottomStart
1004+ " bottom" to " center" -> Alignment .BottomCenter
1005+ " bottom" to " trailing" -> Alignment .BottomEnd
1006+ else -> Alignment .Center
1007+ }
1008+
9641009// Always-called animated wrappers: the underlying Animatable persists across
9651010// recompositions, so a later tween eases from wherever the value currently is.
9661011
0 commit comments