你好,我是朱涛。这是「沉思录」的第四篇文章。
最近工作有点忙的,趁着端午节3天小长假,我来写个 Compose 快速入门的教程吧!我们的目标是:「2小时入门 Compose」!
怎么学?
学习 Compose 最快的方式是什么?当然是写代码呀!可是,Google 官方给出的开源项目太复杂了,初学者看了就头疼。我举个例子,Google 官方最简单的教学 App:Jetsnack,都有将近5000行代码,这怎能不让人望而却步?
因此,我们需要找一个更简单的项目,代码量还要再小一点。我个人比较喜欢 Google 官方的架构案例:TodoApp,它的功能足够简单,也比较贴近我们的实际生活。
不过,可惜的是,这个官方仓库并没有完整的 Compose 实现,GitHub上面类似的实现又太复杂了。怎么办呢?那我就仿着它来写一个吧。Logo 资源什么的,我也给扒过来了。
开始吧!
To Do App
整个项目的代码我已经写完了,它的结构非常简单,一共就只有三个页面:
- 第一个页面:开屏的 Splash 页面,也就是文章开头我放的动图,这里我们用 Compose 的动画 API 就能轻松实现。
- 第二个页面:首页,也就是代处理任务的列表。
- 第三个页面:任务详情。
整个工程的代码量,我统计了一下,只有1400多行。
对于一个功能完整的 App,这样的代码量已经算上很小的了,想想我们工作中的一个 Presenter 代码量都不止1400行代码吧?
到这里,你会不会觉得,这个代码量实在太小了呢?这App会不会是个 Hello World 级别的呢?让我来带你看看它的功能。
工程介绍
总的来说,核心的 UI 只有这么几个文件:
开屏页面
其中,最简单的,就是 Splash 页面,它的作用只有一个:展示 Logo,接着等待一小会,进入首页。在这里,我们会实现一个动画。
这个动画分为两个部分:Logo 的「透明度」动画,还有文字的「透明度」+「位移」动画。
首页
接着,我们来看看首页的功能,它会展示当前所有的任务和状态。
这里,我写了一个进场动效,这个在 Compose 当中实现起来真没什么难度。
总的来说,就是:Index 越大的 Item,它的初始位移越大,进场的时候,再把所有 Item 挪回原处即可。
拖拽删除
然后,我还实现了一下拖拽删除功能。
拖拽删除本身没什么难度,不过,在拖拽的过程中,做一些其他的事情,还是比较有意思的。这里有两个细节:
- 第一,手指拖动到一定范围的时候,弹出一个 Toast,告诉用户,可以松手删除了。如果你看过我的博客《揭秘 Compose 原理》的话,你一定能体会到其中的难处:如何避免 Toast 反复弹出。
- 第二,手指拖动到一定范围后,垃圾桶图标还做了一个:倾倒的动画。
以上这两个细节,我也会在后面的博客详细介绍。
任务详情页面
详情页,这个页面反而没什么特殊东西,就是两个输入框,分别是:任务标题、任务详情,还有一个 CheckBox,代表任务是否已经完成。
这里的输入框的动画效果,是 TextField 自带的,也不需要我们自己实现虽然有点丑,但也能用了。
Splash 代码
OK,工程介绍完了,我们就可以上代码了!这篇文章,我们先从最简单的 Splash 页面开始吧!
@Composable
fun Splash(offsetState: Dp, alphaState: Float) {
// 1
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.splashBackground),
contentAlignment = Alignment.Center
) {
// 2
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
// 3
Image(
modifier = Modifier
.size(LOGO_HEIGHT)
.alpha(alpha = alphaState),
painter = painterResource(id = getLogo()),
contentDescription = stringResource(id = R.string.to_do_logo)
)
// 4
Text(
modifier = Modifier
.offset(y = offsetState)
.alpha(alpha = alphaState),
text = stringResource(id = R.string.app_name),
color = MaterialTheme.colors.splashText,
style = MaterialTheme.typography.h5,
fontWeight = FontWeight.Bold,
maxLines = 1,
)
}
}
}
复制代码
整个 Splash 的 UI 元素其实很简单,我标记了4个注释,我们一起看看:
- 注释1,它是一个撑满屏幕的 Box,它相当于 Android 当中的 FrameLayout。
- 注释2,Column,它相当于 Android 当中的 LinearLayout,并且是纵向布局。
- 注释3,Image,它其实就是开屏当中的 LOGO。
- 注释4,Text,它其实就是开屏当中的文字:To Do。
OK,UI 元素写出来了,动画怎么搞?
@Composable
fun Splash(
gotoHomeScreen: () -> Unit
) {
// 1
var start by remember { mutableStateOf(false) }
// 2
val offset by animateDpAsState(
targetValue = if (start) 0.dp else 100.dp,
animationSpec = tween(
durationMillis = 1000
)
)
val alpha by animateFloatAsState(
targetValue = if (start) 1f else 0f,
animationSpec = tween(
durationMillis = 2000
)
)
// 3
LaunchedEffect(key1 = Unit) {
start = true
delay(SPLASH_DELAY)
gotoHomeScreen()
}
Splash(offsetState = offset, alphaState = alpha)
}
复制代码
其实,动画也很简单,我们通过注释来看:
- 注释1,start 标记动画的状态。
- 注释2,使用 animateDpAsState、animateFloatAsState 生成对应的 alpha、offset,并且,将它们传入 Splash 页面当中去使用。你可以回过头看看 Splash 页面是如何使用者两个参数的。
- 注释3,LaunchedEffect,这里传入参数 Unit,代表它只会执行一次。它的作用,就是启动一个协程,并且在协程当中改变 start 的状态,接着延迟一小会,就可以进入首页了。
最终的效果就是这样的:
结束语
OK,恭喜你,你已经完成了一个 Compose 页面!
考虑到篇幅限制,首页、详情页,我们留到后面的博客再讲具体代码实现吧。
关于源代码,后续我会在我的公众号“朱涛的自习室”放出来,敬请关注。
好了,不多说,马上周一了,我要给公司搬砖去了。感谢你的阅读,我们下周……下个月……还是明年……再见?[逃]。(PS:点赞评论
越多,博客更新越快哦。)