Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MotionLayout in Jetpack Compose

This might be a little soon, but there should be a workaround for this

TL;DR

Is there any way to use Composable components of Jetpack Compose in MotionLayout?
Is such combination in the road map of MotionLayout or Compose?


Is there an alternative for it in Jetpack compose that can do the same?

Since any view that wants to be modified in the motion scene, compose functions can not be modified in a motion scene.

Problem

I want to animate an Image in the center of a Surface and scale it up and down in a specific duration.

Using motion, you can define keyframes in each step.

The Ui is made using Composable function. How can I do what I could with MotionLayout in Compose?


Jetpack compose: v1.0.0-alpha02

like image 533
Mahdi-Malv Avatar asked Mar 03 '23 01:03

Mahdi-Malv


2 Answers

You should use transitionDefinition, check below example and adopt it based on your needs.

enum class State {
    A, B
}

private val scale = FloatPropKey()
private val definition = transitionDefinition {
    state(State.A) {
        this[scale] = 1f
    }
    state(State.B) {
        this[scale] = 5f
    }
    transition(fromState = State.A, toState = State.B) {
        scale using tween(
            durationMillis = 3000,
            easing = FastOutSlowInEasing
        )
    }
}

@Composable
fun AnimateComponentScale() {
    var initialState by remember { mutableStateOf(State.A) }
    var toState by remember { mutableStateOf(State.B) }

    val state = transition(
        definition = definition,
        initState = initialState,
        toState = toState
    ) { state ->
        when (state) {
            State.A -> {
                initialState = State.A
                toState = State.B
            }
            State.B -> {
                initialState = State.B
                toState = State.A
            }
        }
    }
    Box(
        modifier = Modifier.fillMaxSize(),
        gravity = ContentGravity.Center,
        backgroundColor = Color.Cyan
    ) {
        Canvas(modifier = Modifier.preferredSize(50.dp)) {
            scale(scaleX = state[scale], scaleY = state[scale]) {
                drawRect(color = Color(255, 138, 128))
            }
        }
    }
}
like image 167
Mohammad Sianaki Avatar answered Mar 11 '23 08:03

Mohammad Sianaki


You can now use a subset of MotionLayout features direction within Compose using the latest release of constraintlayout-compose (1.0.0-beta02 at the time of writing).

The instructions from the documentaion show you can add it to your project with:

dependencies {
    implementation("androidx.constraintlayout:constraintlayout-compose:1.0.0-beta02")
}

The documentation also provides a simple example of transitioning between two constraint sets:

@Preview(group = "motion8")
@Composable
public fun AttributesRotationXY() {
    var animateToEnd by remember { mutableStateOf(false) }

    val progress by animateFloatAsState(
        targetValue = if (animateToEnd) 1f else 0f,
        animationSpec = tween(6000)
    )
    Column {
        MotionLayout(
            modifier = Modifier
                .fillMaxWidth()
                .height(400.dp)
                .background(Color.White),
            motionScene = MotionScene("""{
                ConstraintSets: {   // all ConstraintSets
                  start: {          // constraint set id = "start"
                    a: {            // Constraint for widget id='a'
                      width: 40,
                      height: 40,
                      start: ['parent', 'start', 16],
                      bottom: ['parent', 'bottom', 16]
                    }
                  },
                  end: {         // constraint set id = "start"
                    a: {
                      width: 40,
                      height: 40,
                      //rotationZ: 390,
                      end: ['parent', 'end', 16],
                      top: ['parent', 'top', 16]
                    }
                  }
                },
                Transitions: {            // All Transitions in here 
                  default: {              // transition named 'default'
                    from: 'start',        // go from Transition "start"
                    to: 'end',            // go to Transition "end"
                    pathMotionArc: 'startHorizontal',  // move in arc 
                    KeyFrames: {          // All keyframes go here
                      KeyAttributes: [    // keyAttributes key frames go here
                        {
                          target: ['a'],              // This keyAttributes group target id "a"
                          frames: [25,50,75],         // 3 points on progress 25% , 50% and 75%
                          rotationX: [0, 45, 60],     // the rotationX angles are a spline from 0,0,45,60,0
                          rotationY: [60, 45, 0],     // the rotationX angles are a spline from 0,60,45,0,0
                        }
                      ]
                    }
                  }
                }
            }"""),
            debug = EnumSet.of(MotionLayoutDebugFlags.SHOW_ALL),
            progress = progress) {
            Box(modifier = Modifier
                .layoutId("a")
                .background(Color.Red))
        }

        Button(onClick = { animateToEnd = !animateToEnd }) {
            Text(text = "Run")
        }
    }
}

You can read more and follow the progress in this wiki and the constraint layout repository.

like image 34
Jesse Hill Avatar answered Mar 11 '23 08:03

Jesse Hill