@@ -20,6 +20,7 @@ import android.graphics.Matrix
2020import androidx.compose.foundation.Canvas
2121import androidx.compose.foundation.layout.Box
2222import androidx.compose.foundation.layout.BoxScope
23+ import androidx.compose.foundation.layout.LayoutScopeMarker
2324import androidx.compose.runtime.*
2425import androidx.compose.ui.Modifier
2526import androidx.compose.ui.geometry.Offset
@@ -35,9 +36,7 @@ import androidx.compose.ui.layout.MeasureScope
3536import androidx.compose.ui.layout.MultiMeasureLayout
3637import androidx.compose.ui.layout.layoutId
3738import androidx.compose.ui.semantics.semantics
38- import androidx.compose.ui.unit.Constraints
39- import androidx.compose.ui.unit.IntSize
40- import androidx.compose.ui.unit.LayoutDirection
39+ import androidx.compose.ui.unit.*
4140import androidx.constraintlayout.core.state.Dimension
4241import androidx.constraintlayout.core.state.WidgetFrame
4342import androidx.constraintlayout.core.widgets.Optimizer
@@ -57,9 +56,10 @@ inline fun MotionLayout(
5756 debug : EnumSet <MotionLayoutDebugFlags > = EnumSet .of(MotionLayoutDebugFlags .NONE ),
5857 modifier : Modifier = Modifier ,
5958 optimizationLevel : Int = Optimizer .OPTIMIZATION_STANDARD ,
60- noinline content : @Composable () -> Unit
59+ crossinline content : @Composable MotionLayoutScope . () -> Unit
6160) {
6261 val measurer = remember { MotionMeasurer () }
62+ val scope = remember { MotionLayoutScope (measurer) }
6363 val progressState = remember { mutableStateOf(0f ) }
6464 SideEffect { progressState.value = progress }
6565 val measurePolicy =
@@ -70,7 +70,7 @@ inline fun MotionLayout(
7070 (MultiMeasureLayout (
7171 modifier = modifier.semantics { designInfoProvider = measurer },
7272 measurePolicy = measurePolicy,
73- content = content
73+ content = { scope. content() }
7474 ))
7575 with (measurer) {
7676 drawDebug()
@@ -81,11 +81,78 @@ inline fun MotionLayout(
8181 (MultiMeasureLayout (
8282 modifier = modifier.semantics { designInfoProvider = measurer },
8383 measurePolicy = measurePolicy,
84- content = content
84+ content = { scope. content() }
8585 ))
8686 }
8787}
8888
89+ @LayoutScopeMarker
90+ class MotionLayoutScope @PublishedApi internal constructor(measurer : MotionMeasurer ) {
91+ private var myMeasurer = measurer
92+
93+ class MotionProperties internal constructor(id : String , tag : String? , measurer : MotionMeasurer ) {
94+ private var myId = id
95+ private var myTag = null
96+ private var myMeasurer = measurer
97+
98+ fun id () : String {
99+ return myId
100+ }
101+
102+ fun tag () : String? {
103+ return myTag
104+ }
105+
106+ fun color (name : String ) : Color {
107+ return myMeasurer.getCustomColor(myId, name)
108+ }
109+
110+ fun float (name : String ) : Float {
111+ return myMeasurer.getCustomFloat(myId, name)
112+ }
113+
114+ fun int (name : String ): Int {
115+ return myMeasurer.getCustomFloat(myId, name).toInt()
116+ }
117+
118+ fun distance (name : String ): Dp {
119+ return myMeasurer.getCustomFloat(myId, name).dp
120+ }
121+
122+ fun fontSize (name : String ) : TextUnit {
123+ return myMeasurer.getCustomFloat(myId, name).sp
124+ }
125+ }
126+
127+ fun motionProperties (id : String ): MotionProperties {
128+ return MotionProperties (id, null , myMeasurer)
129+ }
130+
131+ fun motionProperties (id : String , tag : String ): MotionProperties {
132+ return MotionProperties (id, tag, myMeasurer)
133+ }
134+
135+ fun motionColor (id : String , name : String ): Color {
136+ return myMeasurer.getCustomColor(id, name)
137+ }
138+
139+ fun motionFloat (id : String , name : String ): Float {
140+ return myMeasurer.getCustomFloat(id, name)
141+ }
142+
143+ fun motionInt (id : String , name : String ): Int {
144+ return myMeasurer.getCustomFloat(id, name).toInt()
145+ }
146+
147+ fun motionDistance (id : String , name : String ): Dp {
148+ return myMeasurer.getCustomFloat(id, name).dp
149+ }
150+
151+ fun motionFontSize (id : String , name : String ): TextUnit {
152+ return myMeasurer.getCustomFloat(id, name).sp
153+ }
154+ }
155+
89156enum class MotionLayoutDebugFlags {
90157 NONE ,
91158 SHOW_ALL
@@ -126,6 +193,8 @@ internal class MotionMeasurer : Measurer() {
126193 var framesStart = ArrayList <WidgetFrame >()
127194 var framesEnd = ArrayList <WidgetFrame >()
128195
196+ fun getProgress () : Float { return motionProgress }
197+
129198 private fun measureConstraintSet (optimizationLevel : Int , constraintSetStart : ConstraintSet ,
130199 measurables : List <Measurable >, constraints : Constraints
131200 ) {
@@ -329,6 +398,62 @@ internal class MotionMeasurer : Measurer() {
329398 fun clear () {
330399 frameCache.clear()
331400 }
401+
402+ private fun interpolateColor (start : WidgetFrame .Color , end : WidgetFrame .Color , progress : Float ) : Color {
403+ if (progress < 0 ) {
404+ return Color (start.r, start.g, start.b, start.a)
405+ }
406+ if (progress > 1 ) {
407+ return Color (end.r, end.g, end.b, end.a)
408+ }
409+ val r = (1f - progress) * start.r + progress * (end.r)
410+ val g = (1f - progress) * start.g + progress * (end.g)
411+ val b = (1f - progress) * start.b + progress * (end.b)
412+ return Color (r, g, b)
413+ }
414+
415+ fun findChild (id : String ) : Int {
416+ if (root.children.size == 0 ) {
417+ return - 1
418+ }
419+ val ref = state.constraints(id)
420+ val cw = ref.constraintWidget
421+ var index = 0 ;
422+ for (child in root.children) {
423+ if (cw == child) {
424+ return index
425+ }
426+ index++
427+ }
428+ return - 1
429+ }
430+
431+ fun getCustomColor (id : String , name : String ): Color {
432+ val index = findChild(id)
433+ if (index == - 1 ) {
434+ return Color .Black
435+ }
436+ val startFrame = framesStart[index]
437+ val endFrame = framesEnd[index]
438+ val startColor = startFrame.getCustomColor(name)
439+ val endColor = endFrame.getCustomColor(name)
440+ if (startColor != null && endColor != null ) {
441+ return interpolateColor(startColor, endColor, motionProgress)
442+ }
443+ return Color .Black
444+ }
445+
446+ fun getCustomFloat (id : String , name : String ): Float {
447+ val index = findChild(id)
448+ if (index == - 1 ) {
449+ return 0f ;
450+ }
451+ val startFrame = framesStart[index]
452+ val endFrame = framesEnd[index]
453+ val startFloat = startFrame.getCustomFloat(name)
454+ val endFloat = endFrame.getCustomFloat(name)
455+ return (1f - motionProgress) * startFloat + motionProgress * endFloat
456+ }
332457}
333458
334459private val DEBUG = false
0 commit comments