Compose 打造炫酷的星球打卡 App

作者:Watermelon02
https://juejin.cn/post/7093460817500504100

Compose 打造炫酷的星球打卡 App

Focus

Focus是一款帮助你集中的app——为自己的目标建立星球,将时间投入在上面。花在星球上的每一分钟都会被记录,每颗星球可以定制颜色与外观。为了贯彻简单干净不让人分心的设计理念,app采用白灰为主色调。为了不使界面显得单调,所以增加了不少的动画。https://Github.com/Watermelon02/ComposeFocus

预览

先看看目前的所有功能总的预览吧,使用流程主要就是:

  1. 创建星球界面设置星球名字,打卡时间和详细描述
  2. 星球列表界面选中要打卡的星球
  3. 主界面设置要打卡的时间,开始打卡

Compose 打造炫酷的星球打卡 App



功能

主界面

  • 左右滑动 设置倒计时时间
  • 长按星球 当卫星消失再出现并开始逆时针转动的时候开始计时。打卡的时长会被记录进对应的星球中
Compose 打造炫酷的星球打卡 App
img

星球列表界面

双击星球 进入星球列表界面

  • 上拉星球 显示星球颜色的渐变背景,再点击可以删除星球
  • 左右滑动 查看已有星球
  • 上滑界面 查看星球详细信息
  • 点击✨ 选中当前星球为要打卡的星球

Compose 打造炫酷的星球打卡 App


新建星球界面

点击 星球列表界面的最后一个带加号的星球进入新建星球界面

  • 颜色选择 选中新星球的颜色,这些颜色按钮也做了渐变的动画
  • 时间选择 没啥好说的
  • 点击✨ 创建星球

Compose 打造炫酷的星球打卡 App


主要实现

架构

  • MVI

MVI相比MVVM更加强调数据的单向流动唯一数据源项目中将用户所有的操作包装为Action,传入到界面对应的ViewModel中进行处理,在ViewModel中对界面的状态进行统一集中管理。而UI层则订阅ViewState,当界面状态变化时,Compose函数会自动进行更新

Compose 打造炫酷的星球打卡 App
img
//将state的setter设置为私有,使状态只能在dispatch()中修改,保证数据只能单向修改
var mainPageViewStates by mutableStateOf(MainPageViewState())
    private set
    
//主界面ViewModel中统一对事件进行处理
fun dispatch(action: MainPageAction) {
    when (action) {
        is MainPageAction.DegreeUpdate -> degreeUpdate(action.degree)
        is MainPageAction.SelectStar -> selectStar(action.todoStar)
        is MainPageAction.StarChanged -> mainPageViewStates.starChanged.value = false
        is MainPageAction.NewStarPage -> mainPageViewStates.sheetPage.value =
            BottomSheetPage.NewStarPage
        is MainPageAction.BackToStarList -> mainPageViewStates.sheetPage.value =
            BottomSheetPage.StarListPage
        is MainPageAction.AddStar -> mainPageViewStates.addStar.value = true
        is MainPageAction.RefreshStar -> mainPageViewStates.refreshStarList.value++
        is MainPageAction.CountdownStart->countDownStart()
        is MainPageAction.Countdown -> countDown()
        is MainPageAction.InitSelectedStar -> initSelectedStar()
    }
    
//界面事件的密封类
sealed class MainPageAction {
    class DegreeUpdate(val degree: Float) : MainPageAction()
    .......
    }

}

复制代码
  • 依赖注入

通过使用Hilt来对ViewModel和Room数据库的Dao进行依赖注入,可以非常简单地实现解耦

//为ViewModel加上@HiltViewMode注解
@HiltViewModel
class NewStarViewModel constructor() : ViewModel() {...}
//然后直接在Composable函数的参数中使用hiltViewModel()进行依赖注入
@Composable
fun NewStarPage(
    ...
    viewModel: NewStarViewModel = hiltViewModel()

) {...}


复制代码
  • 数据存储

直接使用Room数据库来进行存储,同时,Room数据库支持直接返回Flow,所以也可以使用协程配合Flow来获取查询结果

//刷新星球列表数据,使用Flow来获取返回结果
private fun refreshStarList() {
    viewModelScope.launch {
        starDao.queryAllStar().collect {
            if (it.isNotEmpty()){
                starListPageStates.starList.value = it
            }
        }
    }
}
复制代码

界面

  • 声明式手势api

Compose的声明式写法和一些手势api让许多控件实现起来更为简单。比如项目主界面中的星球倒计时时钟,这个时钟既需要能够处理用户的手指滑动来设置倒计时时间,还需要能够在用户长按之后开始倒计时。

在原先使用自定义view实现的时候,需要重写其onTouchEvent(),手动计算前后两次手指移动距离,然后旋转view,并回调给时钟View设置的接口来更新倒计时的时间,然后再将更新后的时间传递给上方的TextView。长按事件处理起来同样需要经过类似的步骤。

而使用compose则只需要一个记录滑动度数的state,然后将这个state传入手势(Gesture)api中。这样compose就会自动更新state的数值,而其它使用该state作为参数的compose函数也能自动重组。

  • LazyRow&LazyPage

LazyRowLazyPage类似于RecyclerView,但是不需要再去写adapter,layoutManager等,而且可以方便的将不同类型的item拼接在一起,不需要实现RecyclerViewConcatAdapter或是设置ViewHolder中不同的viewType。(但是好像目前性能不如RV

LazyRow(modifier = Modifier
    .fillMaxHeight(0.35f)
    .fillMaxWidth(), content = {
    //已创建星球列表
    for (star in starList) {item {...}}
    //新增星球Item,点击进入新增星球界面
    item {
        NewStarItem (...)
    }
})
复制代码
  • 动画

compose中自带不少强大的、可扩展的动画 API,可以轻松的实现一些效果。比如———— AnimatedVisibility()配合ModalBottomSheetLayout()实现伸缩列表:

//star的详细资料,开始隐藏,当modalBottomSheet展开时出现
AnimatedVisibility(visible = sheetState.currentValue == ModalBottomSheetValue.Expanded) {
    Card(
        shape = RoundedCornerShape(20.dp),
        modifier = Modifier
            .fillMaxHeight(0.7f)
            .fillMaxWidth(),
    ) {...}
}
复制代码
Compose 打造炫酷的星球打卡 App

再比如InfiniteTransition实现的动态渐变Button (删除星球按钮:

@Composable
fun DeleteButton(color: Color, onClick: () -> Unit) {
    val colorAnimation1 by rememberInfiniteTransition().animateColor(
        initialValue = color.copy(alpha = 0.35f),
        targetValue = color.copy(alpha = 0.75f),
        animationSpec = InfiniteRepeatableSpec(
            animation = tween(
                durationMillis = 4750 + 500 * color.alpha.toInt(),
                easing = FastOutLinearInEasing,
                delayMillis = 2730 * color.alpha.toInt()
            ),
            repeatMode = RepeatMode.Reverse
        )
    )
    val colorAnimation2 by rememberInfiniteTransition().animateColor(类似上面的实现)
    Card(
        modifier = Modifier
            .padding(start = 10.dp, top = 20.dp, end = 10.dp)
            .height(200.dp)
            .width(175.dp),
        shape = RoundedCornerShape(20.dp)
    ) {
        IconButton(onClick = onClick) {
            Canvas(modifier = Modifier
                .padding(start = 10.dp, top = 40.dp, end = 10.dp)
                .height(170.dp)
                .width(175.dp), onDraw = {
                //渐变色块
                drawCircle(
                    brush = Brush.linearGradient(
                        colors = listOf(
                            colorAnimation2,
                            colorAnimation1
                        ),
                        start = Offset(0f,0f),end = Offset(400.dp.value,400.dp.value),
                    ),
                    radius = 300.dp.value,
                    center = Offset(x = size.width / 2, y = size.height / 2)
                )
            })
        }
    }
}
复制代码
Compose 打造炫酷的星球打卡 App

  • 自定义绘制

这方面感觉和原生的写法大同小异,而自定义布局还没来得及了解,这里就不赘述了

总结

首次上手Compose和MVI,项目中的实现可能有不小的问题。Compose在实现许多界面元素的时候感觉比View要更加简单高效,但是用到的许多api都带有实验性注解。而且目前compose的教程不是很多,在遇到问题的时候不太好解决。

因为时间限制所以还有很多想要实现的功能没来得及做,不出意外的话之后会继续修改bug和增加功能。

https://github.com/Watermelon02/ComposeFocus


– FIN –


Compose 博物馆网站:https://jetpackcompose.cn/


原文始发于微信公众号(AndroidPub):Compose 打造炫酷的星球打卡 App

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/57507.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!