Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MotionLayout is crashing #526

Open
robertlevonyan opened this issue Feb 25, 2022 · 6 comments
Open

MotionLayout is crashing #526

robertlevonyan opened this issue Feb 25, 2022 · 6 comments
Assignees
Labels
bug Something isn't working

Comments

@robertlevonyan
Copy link

The motion layout is crashing with this error.

java.lang.IllegalArgumentException: Failed requirement.
        at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure(MeasureAndLayoutDelegate.kt:177)
        at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:228)
        at androidx.compose.ui.node.MeasureAndLayoutDelegate.access$remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:38)
        at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:201)
        at androidx.compose.ui.platform.AndroidComposeView.measureAndLayout(AndroidComposeView.android.kt:662)
        at androidx.compose.ui.node.Owner$DefaultImpls.measureAndLayout$default(Owner.kt:182)
        at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:846)
        at android.view.View.draw(View.java:22648)
        at android.view.View.updateDisplayListIfDirty(View.java:21520)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4512)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4485)
        at android.view.View.updateDisplayListIfDirty(View.java:21476)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4512)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4485)
        at android.view.View.updateDisplayListIfDirty(View.java:21476)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4512)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4485)
        at android.view.View.updateDisplayListIfDirty(View.java:21476)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4512)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4485)
        at android.view.View.updateDisplayListIfDirty(View.java:21476)
        at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:534)
        at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:540)
        at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:616)
        at android.view.ViewRootImpl.draw(ViewRootImpl.java:4438)
        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4166)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3326)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2143)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8665)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1037)
        at android.view.Choreographer.doCallbacks(Choreographer.java:845)
        at android.view.Choreographer.doFrame(Choreographer.java:780)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1022)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7839)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

this is my code

  var sectionsState: Boolean by rememberSaveable { mutableStateOf(false) }

  val collapsedSet = getCollapsedConstraints()
  val expandedSet = getExpandedConstraints()

  val progress by animateFloatAsState(
    targetValue = if (sectionsState) 1f else 0f,
    animationSpec = tween(150)
  )

MotionLayout(
      start = collapsedSet,
      end = expandedSet,
      progress = progress,
      modifier = Modifier.fillMaxSize(),
    ) {
...
}



private fun getCollapsedConstraints(): ConstraintSet = ConstraintSet {
  val title = createRefFor("title")
  val subtitle = createRefFor("subtitle")
  val toggle = createRefFor("toggle")
  val sections = createRefFor("sections")
  val timers = createRefFor("timers")


  constrain(title) {
    width = Dimension.wrapContent
    height = Dimension.wrapContent
    end.linkTo(parent.end)
    start.linkTo(parent.start)
    top.linkTo(parent.top)
  }
  constrain(subtitle) {
    width = Dimension.wrapContent
    height = Dimension.wrapContent
    end.linkTo(parent.end)
    start.linkTo(parent.start)
    top.linkTo(title.bottom)
  }
  constrain(sections) {
    width = Dimension.matchParent
    height = Dimension.wrapContent
    start.linkTo(parent.start)
    end.linkTo(parent.end)
    bottom.linkTo(parent.top)
  }
  constrain(toggle) {
    end.linkTo(parent.end)
    top.linkTo(sections.bottom)
  }
  constrain(timers) {
    width = Dimension.wrapContent
    height = Dimension.wrapContent
    start.linkTo(parent.start)
    end.linkTo(parent.end)
    bottom.linkTo(parent.bottom)
  }
}

private fun getExpandedConstraints(): ConstraintSet = ConstraintSet {
  val title = createRefFor("title")
  val subtitle = createRefFor("subtitle")
  val toggle = createRefFor("toggle")
  val sections = createRefFor("sections")
  val timers = createRefFor("timers")


  constrain(title) {
    width = Dimension.wrapContent
    height = Dimension.wrapContent
    end.linkTo(parent.end)
    start.linkTo(parent.start)
    top.linkTo(parent.top)
  }
  constrain(subtitle) {
    width = Dimension.wrapContent
    height = Dimension.wrapContent
    end.linkTo(parent.end)
    start.linkTo(parent.start)
    top.linkTo(title.bottom)
  }
  constrain(sections) {
    width = Dimension.matchParent
    height = Dimension.wrapContent
    start.linkTo(parent.start)
    end.linkTo(parent.end)
    top.linkTo(parent.top)
  }
  constrain(toggle) {
    end.linkTo(parent.end)
    top.linkTo(sections.bottom)
  }
  constrain(timers) {
    width = Dimension.wrapContent
    height = Dimension.wrapContent
    start.linkTo(parent.start)
    end.linkTo(parent.end)
    bottom.linkTo(parent.bottom)
  }
}
@robertlevonyan robertlevonyan added the bug Something isn't working label Feb 25, 2022
@oscar-ad
Copy link
Collaborator

Which Compose version is this?

Haven't been able to repro on 1.0.0 or even 1.1.0.

I'm using a very simple setup:

@OptIn(ExperimentalMotionApi::class)
@Preview
@Composable
fun CrashTest() {
    var sectionsState: Boolean by rememberSaveable { mutableStateOf(false) }

    val collapsedSet = getCollapsedConstraints()
    val expandedSet = getExpandedConstraints()

    val progress by animateFloatAsState(
        targetValue = if (sectionsState) 1f else 0f,
        animationSpec = tween(150)
    )

    Column {
        MotionLayout(
            start = collapsedSet,
            end = expandedSet,
            progress = progress,
            modifier = Modifier.fillMaxWidth().weight(1.0f, true),
        ) {
            Text(
                text = "My Title",
                Modifier
                    .layoutId("title")
                    .background(Color.Red))
            Text(
                text = "My subtitle",
                Modifier
                    .layoutId("subtitle")
                    .background(Color.Blue))
            Text(
                text = "TOGGLE",
                Modifier
                    .layoutId("toggle")
                    .background(Color.Cyan))
            Text(
                text = "Sections",
                Modifier
                    .layoutId("sections")
                    .background(Color.Yellow))
            Text(
                text = "Timers:",
                Modifier
                    .layoutId("timers")
                    .background(Color.Gray))
        }
        Button(onClick = { sectionsState = !sectionsState }) {
            Text(text = "Run")
        }
    }
}

@oscar-ad
Copy link
Collaborator

Any chance one of the Composables in MotionLayout has a size Modifier? (size, sizeIn, defaultMin, fillMaxSize, etc)

Does it still crash with Dimension.fillToConstraints instead of Dimension.matchParent?

@Eric-Cen
Copy link

Here is an example that shows the same error message, https://github.com/jipariz/ComposeMotion from the article, https://www.strv.com/blog/collapsing-toolbar-using-jetpack-compose-motion-layout-engineering.

Based on this ComposeMotion project, update the followings:

  1. compose_version = '1.1.1'
  2. classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
  3. distributionUrl=https://services.gradle.org/distributions/gradle-7.3-bin.zip

Then compile and run. The exact same code works on older Compose versions, 1.0.1 and 1.04. However, it doesn't work with 1.1.1 with the error message. Thanks.

@smithc42
Copy link

Also had this issue today using the repo @Eric-Cen linked. @oscar-ad do you know if there's any workaround for this?

@oscar-ad
Copy link
Collaborator

No workaround other than sticking to 1.0.x

It's a hard check that prevents us from remeasuring Composables during animation in some cases.

I'll close this once we work out a solution with the rest of the Compose team.

@oscar-ad
Copy link
Collaborator

Issue seems to be resolved when using 1.2.0-alpha08
Tho I see issues with custom properties.

I'll keep this open until 1.2.0 hits stable or I'm able to guarantee no regressions from there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants