编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

android Jetpack Compose 使用MotionLayout做动画效果

wxchong 2024-06-21 14:25:51 开源技术 12 ℃ 0 评论

MotionLayout存在于constraintlayout包中,使用前需要先添加依赖。

implementation 'androidx.constraintlayout:constraintlayout-compose:1.0.0'

查看源码,可以看到MotionLayout的定义:


inline fun MotionLayout(
    start: ConstraintSet,
    end: ConstraintSet,
    transition: androidx.constraintlayout.compose.Transition? = null,
    progress: Float,
    debug: EnumSet<MotionLayoutDebugFlags> = EnumSet.of(MotionLayoutDebugFlags.NONE),
    modifier: Modifier = Modifier,
    optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
    crossinline content: @Composable MotionLayoutScope.() -> Unit
) {
    MotionLayout(
        start = start,
        end = end,
        transition = transition,
        progress = progress,
        debug = debug,
        informationReceiver = null,
        modifier = modifier,
        optimizationLevel = optimizationLevel,
        content = content
    )
}

使用时必须要传的参数有:开始和结束的ConstraintSet、progress、content。

1.使用json来构建ConstraintSet:

//用于控制动画的开启
var animateButton by remember { mutableStateOf(false) }
val buttonAnimationProgress by animateFloatAsState(
    targetValue = if (animateButton) 1f else 0f,
    animationSpec = tween(1000)
)
Spacer(modifier = Modifier.height(16.dp))
MotionLayout(
    ConstraintSet(
        """ {
            button1: { 
              width: "spread",
              height: 60,
              start: ['parent', 'start', 16],
              end: ['parent', 'end', 16],
              top: ['parent', 'top', 16]
            },
            button2: { 
              width: "spread",
              height: 60,
              start: ['parent', 'start', 16],
              end: ['parent', 'end', 16],
              top: ['button1', 'bottom', 16]
            },
            button3: { 
              width: "spread",
              height: 60,
              start: ['parent', 'start', 16],
              end: ['parent', 'end', 16],
              top: ['button2', 'bottom', 16]
            }
        } """
    ),
    ConstraintSet(
        """ {
            button1: { 
              width: 100,
              height: 60,
              start: ['parent', 'start', 16],
              end: ['button2', 'start', 16]
            },
            button2: { 
              width: 100,
              height: 60,
              start: ['button1', 'end', 16],
              end: ['button2', 'start', 16]
            },
            button3: { 
              width: 100,
              height: 60,
              start: ['button2', 'end', 16],
              end: ['parent', 'end', 16]
            }
        } """
    ),
    progress = buttonAnimationProgress,
    modifier = Modifier
        .fillMaxWidth()
        .wrapContentHeight()
) {
    Button(
        onClick = { animateButton = !animateButton },
        modifier = Modifier.layoutId("button1")
    ) {
        Text(text = "按钮一")
    }
    Button(
        onClick = { animateButton = !animateButton },
        modifier = Modifier.layoutId("button2")
    ) {
        Text(text = "按钮二")
    }
    Button(
        onClick = { animateButton = !animateButton },
        modifier = Modifier.layoutId("button3")
    ) {
        Text(text = "按钮三")
    }
}

2.不使用json构建ConstraintSet的方式:

MotionLayout(
    ConstraintSet {
        val btn4 = createRefFor("btn4")
        val btn5 = createRefFor("btn5")
        val btn6 = createRefFor("btn6")
        constrain(btn4) {
            width = Dimension.matchParent
            linkTo(
                start = parent.start,
                top = parent.top,
                end = parent.end,
                bottom = btn5.top,
                topMargin = 4.dp,
                bottomMargin = 4.dp,
                startMargin = 16.dp,
                endMargin = 16.dp
            )
        }
        constrain(btn5) {
            width = Dimension.matchParent
            linkTo(
                start = parent.start,
                top = btn4.bottom,
                end = parent.end,
                bottom = btn6.top,
                topMargin = 4.dp,
                bottomMargin = 4.dp,
                startMargin = 16.dp,
                endMargin = 16.dp
            )
        }
        constrain(btn6) {
            width = Dimension.matchParent
            linkTo(
                start = parent.start,
                top = btn5.bottom,
                end = parent.end,
                bottom = parent.bottom,
                topMargin = 4.dp,
                bottomMargin = 4.dp,
                startMargin = 16.dp,
                endMargin = 16.dp
            )
        }
    },
    ConstraintSet {
        val btn4 = createRefFor("btn4")
        val btn5 = createRefFor("btn5")
        val btn6 = createRefFor("btn6")
        constrain(btn4) {
            width = Dimension.preferredWrapContent
            height = Dimension.wrapContent
            top.linkTo(parent.top, 8.dp)
            bottom.linkTo(parent.bottom, 8.dp)
            absoluteLeft.linkTo(parent.absoluteLeft, 16.dp)
            absoluteRight.linkTo(btn5.absoluteLeft, 4.dp)
        }
        constrain(btn5) {
            width = Dimension.preferredWrapContent
            height = Dimension.wrapContent
            top.linkTo(parent.top, 8.dp)
            bottom.linkTo(parent.bottom, 8.dp)
            absoluteLeft.linkTo(btn4.absoluteRight, 4.dp)
            absoluteRight.linkTo(btn6.absoluteLeft, 4.dp)
        }
        constrain(btn6) {
            width = Dimension.preferredWrapContent
            height = Dimension.wrapContent
            top.linkTo(parent.top, 8.dp)
            bottom.linkTo(parent.bottom, 8.dp)
            absoluteLeft.linkTo(btn5.absoluteRight, 4.dp)
            absoluteRight.linkTo(parent.absoluteRight, 16.dp)
        }
    },
    progress = buttonAnimationProgress,
    modifier = Modifier
        .fillMaxWidth()
        .wrapContentHeight()
) {
    Button(
        onClick = { animateButton = !animateButton },
        modifier = Modifier.layoutId("btn4")
    ) {
        Text(text = "按钮四")
    }
    Button(
        onClick = { animateButton = !animateButton },
        modifier = Modifier.layoutId("btn5")
    ) {
        Text(text = "按钮五")
    }
    Button(
        onClick = { animateButton = !animateButton },
        modifier = Modifier.layoutId("btn6")
    ) {
        Text(text = "按钮六")
    }
}

另一个例子:

var animateImage by remember { mutableStateOf(false) }
val imageAnimationProgress by animateFloatAsState(
    targetValue = if (animateImage) 1f else 0f,
    animationSpec = tween(1000)
)
MotionLayout(
    ConstraintSet(
        """ {
            image1: { 
              width: 150,
              height: 150,
              start: ['parent', 'start', 16]
            },
            image2: { 
              width: 150,
              height: 150,
              start: ['parent', 'start', 32]
            },
            image3: { 
              width: 150,
              height: 150,
              start: ['parent', 'start', 48]
            },
            image4: { 
              width: 150,
              height: 150,
              start: ['parent', 'start', 64]
            }
        } """
    ),
    ConstraintSet(
        """ {
            image1: { 
              width: 150,
              height: 150,
              start: ['parent', 'start', 16]
            },
            image2: { 
              width: 150,
              height: 150,
              start: ['image1', 'end', 16]
            },
            image3: { 
              width: 150,
              height: 150,
              start: ['parent', 'start', 16],
              top: ['image1', 'bottom', 16]
            },
            image4: { 
              width: 150,
              height: 150,
              start: ['image1', 'end', 16],
              top: ['image1', 'bottom', 16]
            }
        } """
    ),
    progress = imageAnimationProgress,
    modifier = Modifier
        .fillMaxSize()
) {
    Image(
        painter = painterResource(id = R.mipmap.ic_sds_01),
        contentDescription = "",
        modifier = Modifier
            .layoutId("image1")
            .clickable { animateImage = !animateImage })
    Image(
        painter = painterResource(id = R.mipmap.ic_sds_02),
        contentDescription = "",
        modifier = Modifier
            .layoutId("image2")
            .clickable { animateImage = !animateImage })
    Image(
        painter = painterResource(id = R.mipmap.ic_sds_03),
        contentDescription = "",
        modifier = Modifier
            .layoutId("image3")
            .clickable { animateImage = !animateImage })
    Image(
        painter = painterResource(id = R.mipmap.ic_sds_04),
        contentDescription = "",
        modifier = Modifier
            .layoutId("image4")
            .clickable { animateImage = !animateImage })
}


Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表