「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」
MotionLayout
MotionLayout是一个非常新的类,它来自ConstraintLayout 2.0库中,主要目的是为了帮助Android开发人员在应用中降低使用手势和组件动画的难度。
MotionLayout
可以在给定两组约束和一个进度开始到结束的情况下,插入其子布局的布局
MotionLayout小基础Jetpack Compose 用MotionLayout打造动画开关 本篇文章用MotionLayout实现文章列表到文章详细的过度动画
MotionLayout实战
首先导入依赖
//约束布局
implementation("androidx.constraintlayout:constraintlayout-compose:2.1.0")
复制代码
写这篇文章时时2.1.0
ConstraintSet
用于布局ConstraintLayout子项的约束的不变描述 分为开始和结束 使用MotionLayout时要传入开始和结束的ConstraintSet
item
item背景开始的ConstraintSet
宽度拉满,高度60吧,布局接着放在底部
background: {
width: "spread",
height: 60,
start: ['parent', 'start', 16],
bottom: ['parent', 'bottom', 16],
end: ['parent', 'end', 16]
},
item背景结束的ConstraintSet
background: {
width: "spread",
height: 100,
start: ['parent', 'start', 0],
end: ['parent', 'end', 0],
top: ['parent', 'top', 0]
},
图片的区域
加个放图片的区域在左侧
图片开始的ConstraintSet
v1: {
width: 100,
height: 60,
start: ['parent', 'start', 16],
bottom: ['parent', 'bottom', 16]
},
图片结束的ConstraintSet
结束之后过渡成标题的背景,所以把它放上面
高度放大点100吧
v1: {
width: "spread",
height: 100,
start: ['parent', 'start', 0],
end: ['parent', 'end', 0],
top: ['parent', 'top', 0]
},
标题
接着实现标题和副标题
文本开始的ConstraintSet
title: {
width: "spread",
start: ['v1', 'end', 8],
top: ['v1', 'top', 8],
end: ['parent', 'end', 8],
custom: {
textSize: 14
}
},
description: {
start: ['v1', 'end', 8],
top: ['title', 'bottom', 0],
custom: {
textSize: 12
}
},
文本结束的ConstraintSet
title: {
width: "spread",
height: 28,
start: ['parent', 'start', 16],
top: ['background', 'tap', 16],
end: ['parent', 'end', 16],
custom: {
textSize: 20
}
},
description: {
width: "spread",
start: ['parent', 'start', 16],
top: ['v1', 'bottom', 8],
end: ['parent', 'end', 16],
custom: {
textSize: 14
}
},
在加一个文章的背景
list: {
width: "spread",
height: 0,
start: ['parent', 'start', 8],
end: ['parent', 'end', 8],
top: ['parent', 'bottom', 0]
},
list: {
width: "spread",
height: 550,
start: ['parent', 'start', 16],
end: ['parent', 'end', 16],
top: ['description', 'bottom', 16]
},
最后加个关闭按钮
close: {
end: ['parent', 'end', 24],
top: ['v1', 'top', 0],
bottom: ['v1', 'bottom', 0]
}
close: {
start: ['parent', 'end', 8],
top: ['v1', 'top', 0],
bottom: ['v1', 'bottom', 0]
}
点击事件 定义开始状态
var animateToEnd by remember { mutableStateOf(false) }
动画的逻辑
持续时间1秒
val progress by animateFloatAsState(
targetValue = if (animateToEnd) 1f else 0f,
animationSpec = tween(1000)
)
绑定MotionLayouy
.layoutId({ConstraintSet的名称})
完整代码
@Composable
fun MotionLayout() {
var animateToEnd by remember { mutableStateOf(false) }
val progress by animateFloatAsState(
targetValue = if (animateToEnd) 1f else 0f,
animationSpec = tween(1000)
)
Column(Modifier.background(Color.White)) {
MotionLayout(
ConstraintSet(
""" {
background: {
width: "spread",
height: 60,
start: ['parent', 'start', 16],
bottom: ['parent', 'bottom', 16],
end: ['parent', 'end', 16]
},
v1: {
width: 100,
height: 60,
start: ['parent', 'start', 16],
bottom: ['parent', 'bottom', 16]
},
title: {
width: "spread",
start: ['v1', 'end', 8],
top: ['v1', 'top', 8],
end: ['parent', 'end', 8],
custom: {
textSize: 14
}
},
description: {
start: ['v1', 'end', 8],
top: ['title', 'bottom', 0],
custom: {
textSize: 12
}
},
list: {
width: "spread",
height: 0,
start: ['parent', 'start', 8],
end: ['parent', 'end', 8],
top: ['parent', 'bottom', 0]
},
close: {
end: ['parent', 'end', 24],
top: ['v1', 'top', 0],
bottom: ['v1', 'bottom', 0]
}
} """
),
ConstraintSet(
""" {
background: {
width: "spread",
height: 100,
start: ['parent', 'start', 0],
end: ['parent', 'end', 0],
top: ['parent', 'top', 0]
},
v1: {
width: "spread",
height: 100,
start: ['parent', 'start', 0],
end: ['parent', 'end', 0],
top: ['parent', 'top', 0]
},
title: {
width: "spread",
height: 28,
start: ['parent', 'start', 16],
top: ['background', 'tap', 16],
end: ['parent', 'end', 16],
custom: {
textSize: 20
}
},
description: {
width: "spread",
start: ['parent', 'start', 16],
top: ['v1', 'bottom', 8],
end: ['parent', 'end', 16],
custom: {
textSize: 14
}
},
list: {
width: "spread",
height: 550,
start: ['parent', 'start', 16],
end: ['parent', 'end', 16],
top: ['description', 'bottom', 16]
},
close: {
start: ['parent', 'end', 8],
top: ['v1', 'top', 0],
bottom: ['v1', 'bottom', 0]
}
} """
),
progress = progress,
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
Box(
modifier = Modifier
.layoutId("background", "box")
.background(Color.Cyan)
.clickable(onClick = { animateToEnd = !animateToEnd })
)
Button(
onClick = { animateToEnd = !animateToEnd },
modifier = Modifier
.layoutId("v1", "box")
.background(Color.Blue),
shape = RoundedCornerShape(0f)
) {}
Text(
text = "MotionLayout",
modifier = Modifier.layoutId("title"),
color = Color.Black,
fontSize = motionProperties("title").value.fontSize("textSize")
)
Text(
text = "jetpack Compose ",
modifier = Modifier.layoutId("description"),
color = Color.Black,
fontSize = motionProperties("description").value.fontSize("textSize")
)
Box(
modifier = Modifier
.layoutId("list", "box")
.background(Color.Gray)
)
Icon(
Icons.Filled.Close,
contentDescription = null,
tint = Color.Black,
modifier = Modifier.layoutId("close")
)
}
}
效果图
部分代码来源Jetpack Compose Playground