iOS 的UI先不管,Compose 都还费劲呢。
1. 预览需要传入参数
比如
- 列表 LazeColumn 需要接收数据
- navigation导航需要提供
navController
“注意:我们强烈建议您不要向生产函数(即使其不带参数)添加 @Preview 注释,而是编写一个封装函数并在其中添加 @Preview 注释。“
—— 安卓开发者官网
前面那种情况,新创建一个方法就行
导航这种,官方推荐的是函数传递,也就是把方法作为参数传递进来
@compose
fun HomeScreen(navigateToDetailScreen: (userId:String)->Unit){
}
2. 预览失败
提示
The following classes could not be found androidx.compose.ui.tooling.ComposeViewAdapter
发现依赖的ui-tool
是preview版本,改成下面就可以了
implementation("androidx.compose.ui:ui-tooling:1.1.1")
3. 系统 insets 适配
- 通过
ViewCompat.setOnApplyWindowInsetsListener
可以拿到 WindowInsets - 导入谷歌的新库
implementation("com.google.accompanist:accompanist-insets:0.23.1")
然后使用ProvideWindowInsets
配合LocalWindowInsets.current.systemBars
获取系统Insets
ProvideWindowInsets(false) {
val inset = LocalWindowInsets.current.systemBars
Box{
}
}
4. Compose 的Padding 如何接受 pixel 而不是 DP
ContentPadding 为内边距
Padding 为外边距(相当于XML那一套的margin)
如果没有特殊需求
导入accompanist-insets后可以直接使用rememberInsetsPaddingValues
来给view设置padding,完成适配
否则,只能通过LocalDensity自己转换
val density = LocalDensity.current
appBarHeight = with(density){size.height.toDp()}
5. 高斯模糊效果
调用Modifier.blur(30.dp)
发现其只作用于当前View及其子View,对兄弟View是不会有类似iOS那种透视效果的
2022-03-02结论,后续待更新
这里是Box内嵌套LazeColumn和TopAppBar,与预期效果有两点不同
- 对 TopAppBar设置的
blur
同时作用了TopAppBar内部的Text
- 对 TopAppBar设置的
- TopAppBar背景色设置为alpha = 0.5f,但是下层元素并没有影响,也就是没有真的像透过一层毛玻璃去看东西的效果。
6. 如何获取Compose View/控件/元素的宽高
使用 Modifier.onSizeChanged
ProvideWindowInsets(false) {
val density = LocalDensity.current
var appBarHeight by remember { mutableStateOf(0.dp) }
Box {
TopAppBar(
modifier = Modifier.blur(4.dp).onSizeChanged { size ->
appBarHeight = with(density){size.height.toDp()}
},
...
),
...
}
7. List多列竖排使间距相同
单列有LazyColumn,多列有还在实验阶段的
LazyVerticalGrid
设置列的数量
- 固定=>
GridCells.Fixed(spanCount)
- 不固定=>
GridCells.Adaptive(minSize.dp)
设置间距
- 子元素间的间距使用
horizontalArrangement
和verticalArrangement
- 子元素与自身的间距使用
contentPadding
LazyVerticalGrid(
// 固定列数为2
cells = GridCells.Fixed(2),
contentPadding = rememberInsetsPaddingValues(
inset,
// 不应用顶部Insets
applyTop = false,
// 顶部手动添加额外 Padding
additionalTop = appBarHeight,
// 左边 Padding
additionalStart = 12.dp,
// 右边 Padding
additionalEnd = 12.dp,
),
// 元素水平间距
horizontalArrangement = Arrangement.spacedBy(12.dp),
// 元素垂直间距
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
items(roomInfoList) { roomInfo ->
RoomItem(roomInfo, nav2Rooms)
}
}
都设置为12.dp后,效果如下:
LazyVerticalGrid 效果8. Compose 实现点击旋转360度的刷新效果
为什么动画结束需要手动重置状态,因为默认的插值器是0增大到360,再从360降到0,动画会顺时针、逆时针交替。
同时确保动画连贯,不会有边界情况。
效果:
// 动画标识,是否已经开始
var animateStart by remember { mutableStateOf(false) }
// 当前 Rotate 角度
val animateRotateDegree by animateFloatAsState(
// 目标角度
if (animateStart) 360f else 0f,
// 动画模式,时长设置
TweenSpec(if (animateStart) 500 else 0),
finishedListener = {
// 结束时重置标志
if (animateStart) animateStart = false
}
)
IconButton(onClick = {
// 点击后动作
animateStart = true
}) {
Icon(
Icons.Default.Refresh,
...
modifier = Modifier.rotate(animateRotateDegree)
)
}
流程分析
- 点击按钮,animateStart = true
- Rotate 角度改变为 360,开始 500ms 的动画,Icon 开始旋转
- 500ms后,动画结束,animateStart = false
- Rotate 角度改变为 0,开始 0ms 的动画,Icon 无需改变
- 边界情况,开始后200ms再次点击,此时animateStart并未改变,无任何UI影响
网友评论