Compose Weekly #2:Countdown Timer

onlyloveyd 等级 375 0 0

本文同步发表于我的微信公众号,在微信搜索 OpenCV or Android 即可关注。

前言

最近Android官方发起了Jetpack Compose的推广活动:Jetpack Compose开发者挑战赛。活动时间一个月,每周一题,广大开发者根据官方需求,Clone官方模板工程并使用Jetpack Compose技术结题后按要求提交,即可参与活动。今天抽空完成了第二题,有点丑陋,感兴趣的同学可以做个漂亮点的。

环境

第二周

题目:Countdown Timer

要求:创建一个有效的单屏倒数计时器。

知识点:

思路

简单的计时器操作:设置计时时长,开始计时,等待计时结束或者手动暂停计时。

  • 界面元素:(1)倒计时进度条;(2)时分秒设置计时长度;(3)重置计时按钮、开始计时按钮
  • 可变状态:(1)时长(时分秒);(2)倒计时进度与总时长;(3)计时状态(是否已开始)

倒计时进度条

@Composable
fun counterDown(modifier: Modifier, seconds: Int) {
    ConstraintLayout(
        modifier = modifier
            .fillMaxWidth()
            .fillMaxHeight()
    ) {
        val viewModel: MainViewModel = viewModel()
        val (progressBackground, progress, countdownTimer) = createRefs()

        CircularProgressIndicator(
            1f,
            modifier = Modifier
                .constrainAs(progressBackground) {
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                    end.linkTo(parent.end)
                    bottom.linkTo(parent.bottom)
                }
                .height(300.dp)
                .width(300.dp),
            strokeWidth = 32.dp, color = Color.LightGray
        )

        Progress(
            Modifier
                .constrainAs(progress) {
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                    end.linkTo(parent.end)
                    bottom.linkTo(parent.bottom)
                }
                .height(300.dp)
                .width(300.dp),
            countdownSeconds = viewModel.clock, totalSeconds = viewModel.totalClock
        )

        Row(
            modifier = Modifier
                .fillMaxWidth()
                .constrainAs(countdownTimer) {
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                    end.linkTo(parent.end)
                    bottom.linkTo(parent.bottom)
                },
            horizontalArrangement = Arrangement.Center,
            verticalAlignment = Alignment.CenterVertically
        ) {
            Text(
                text = seconds.div(3600).toString(),
                fontSize = 48.sp,
                fontFamily = FontFamily.Monospace,
                fontStyle = FontStyle.Normal,
                fontWeight = FontWeight.Bold
            )
            Text(
                text = ":",
                fontSize = 48.sp,
                fontFamily = FontFamily.Monospace,
                fontStyle = FontStyle.Normal,
                fontWeight = FontWeight.Bold
            )
            Text(
                text = seconds.rem(3600).div(60).toString(),
                fontSize = 48.sp,
                fontFamily = FontFamily.Monospace,
                fontStyle = FontStyle.Normal,
                fontWeight = FontWeight.Bold
            )
            Text(
                text = ":",
                fontSize = 48.sp,
                fontFamily = FontFamily.Monospace,
                fontStyle = FontStyle.Normal,
                fontWeight = FontWeight.Bold
            )
            Text(
                text = seconds.rem(60).toString(),
                fontSize = 48.sp,
                fontFamily = FontFamily.Monospace,
                fontStyle = FontStyle.Normal,
                fontWeight = FontWeight.Bold
            )
        }
    }
}

设置时长

@Composable
fun timePicker(modifier: Modifier) {
    val viewModel: MainViewModel = viewModel()
    Row(
        modifier = modifier
            .fillMaxWidth(),
        horizontalArrangement = Arrangement.SpaceAround
    ) {
        Column(
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            IconButton(
                onClick = { viewModel.incHour() },
                Modifier
                    .background(
                        Color.LightGray,
                        shape = shapes.large
                    )
                    .size(32.dp, 32.dp),
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_inc),
                    contentDescription = null,
                    modifier = Modifier
                        .size(18.dp),
                    tint = Color.Black
                )
            }
            Text(
                text = viewModel.hours.toString(),
                fontSize = 32.sp,
                fontFamily = FontFamily.Serif,
                fontStyle = FontStyle.Normal,
                fontWeight = FontWeight.Bold,
                modifier = Modifier.padding(0.dp, 8.dp)
            )
            IconButton(
                onClick = { viewModel.decHour() },
                Modifier
                    .background(
                        Color.LightGray,
                        shape = shapes.large
                    )
                    .size(32.dp, 32.dp),
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_dec),
                    contentDescription = null,
                    modifier = Modifier
                        .size(18.dp),
                    tint = Color.Black
                )
            }
        }
        Column(
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            IconButton(
                onClick = { viewModel.incMinute() },
                Modifier
                    .background(
                        Color.LightGray,
                        shape = shapes.large
                    )
                    .size(32.dp, 32.dp),
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_inc),
                    contentDescription = null,
                    modifier = Modifier
                        .size(18.dp),
                    tint = Color.Black
                )
            }
            Text(
                text = viewModel.minutes.toString(),
                fontSize = 32.sp,
                fontFamily = FontFamily.Serif,
                fontStyle = FontStyle.Normal,
                fontWeight = FontWeight.Bold,
                modifier = Modifier.padding(0.dp, 8.dp)
            )
            IconButton(
                onClick = { viewModel.decMinute() },
                Modifier
                    .background(
                        Color.LightGray,
                        shape = shapes.large
                    )
                    .size(32.dp, 32.dp),
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_dec),
                    contentDescription = null,
                    modifier = Modifier
                        .size(18.dp),
                    tint = Color.Black
                )
            }
        }
        Column(
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            IconButton(
                onClick = { viewModel.incSecond() },
                Modifier
                    .background(
                        Color.LightGray,
                        shape = shapes.large
                    )
                    .size(32.dp, 32.dp),
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_inc),
                    contentDescription = null,
                    modifier = Modifier
                        .size(18.dp),
                    tint = Color.Black
                )
            }
            Text(
                text = viewModel.seconds.toString(),
                fontSize = 32.sp,
                fontFamily = FontFamily.Serif,
                fontStyle = FontStyle.Normal,
                fontWeight = FontWeight.Bold,
                modifier = Modifier.padding(0.dp, 8.dp)
            )
            IconButton(
                onClick = { viewModel.decSecond() },
                Modifier
                    .background(
                        Color.LightGray,
                        shape = shapes.large
                    )
                    .size(32.dp, 32.dp),
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_dec),
                    contentDescription = null,
                    modifier = Modifier
                        .size(18.dp),
                    tint = Color.Black
                )
            }
        }
    }
}

重置计时、开始计时

@Composable
fun bottomMenu(modifier: Modifier) {
    val viewModel: MainViewModel = viewModel()
    Row(
        modifier = modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.SpaceEvenly,
        verticalAlignment = Alignment.CenterVertically
    ) {
        IconButton(onClick = { viewModel.reset() }) {
            Icon(
                painter = painterResource(id = R.drawable.ic_reset), contentDescription = null,
                modifier = Modifier
                    .size(32.dp),
                tint = Color.Black
            )
        }

        if (!viewModel.started) {
            IconButton(onClick = { viewModel.startCountdown() }) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_start), contentDescription = null,
                    modifier = Modifier
                        .size(32.dp),
                    tint = Color.Black
                )
            }
        }
    }
}

效果

Compose Weekly #2:Countdown Timer

Compose Weekly #2:Countdown Timer

源码

https://github.com/onlyloveyd/Jetpack-Compose-CountdownTimer

收藏
评论区

相关推荐

2. web前端开发分享-css,js进阶篇
2. web前端开发分享css,js进阶篇 一,css进阶篇:   等css哪些事儿看了两三遍之后,需要对看过的知识综合应用,这时候需要大量的实践经验, 简单的想法:把qq首页全屏另存为jpg然后
2021年前端趋势预测
淘系前端团队 2021年前端趋势预测 作者: 发布于: 知乎上,有人提问《2021前端会有什么新的变化?》 狼叔的回答二天超过6.1万阅读量,目前444个赞同,2个专业徽章,整体上看,这篇回答大家还是相当认可的。 (https://imghelloworld.osscnbeijing.aliyuncs.com/d2fa7c39e3e0
一文搞懂什么是HTTP与HTTPS
(https://blog.csdn.net/petterp/article/details/102779257)Http与Https的区别。 在最近的开发中,深感网络相关基础知识薄弱,于是趁周末好好总结一
金三银四了,掌握 JS 这 36 个概念,助你一臂之力
作者:Mahdhi Rezvi 译者:前端小智 来源:dmitripavlutin 点赞再看,微信搜索【大迁世界(https://mp.weixin.qq.com/s/sY9ufGGKfcdaAQ7KJQs3HA)】,B站关注【前端小智(https://space.bilibili.com/31089477)】这个没有大厂背景,但有着
20 张图彻底弄懂 HTTPS 的原理
前言 近年来各大公司对信息安全传输越来越重视,也逐步把网站升级到 HTTPS 了,那么大家知道 HTTPS 的原理是怎样的吗,到底是它是如何确保信息安全传输的?网上挺多介绍 HTTPS,但我发现总是或多或少有些点有些遗漏,没有讲全,今天试图由浅入深地把 HTTPS 讲明白,相信大家看完一定能掌握 HTTPS 的原理,本文大纲如下: HTTP 为什么不安全
Compose Weekly #1: 小狗领养应用
本文同步发表于我的微信公众号,在微信搜索 OpenCV or Android 即可关注。 前言 最近Android官方发起了Jetpack Compose的推广活动:Jetpack Compose开发者挑战赛。活动时间一个月,每周一题,广大开发者根据官方需求,Clone官方模板工程并使用Jetpack Compose技术结题后按要求提交,即可参与活动。
Compose Weekly #2:Countdown Timer
本文同步发表于我的微信公众号,在微信搜索 OpenCV or Android 即可关注。 前言 最近Android官方发起了Jetpack Compose的推广活动:Jetpack Compose开发者挑战赛。活动时间一个月,每周一题,广大开发者根据官方需求,Clone官方模板工程并使用Jetpack Compose技术结题后按要求提交,即可参与活动。
7个关于"this"面试题,你能回答上来吗?
作者:Shadeed 译者:前端小智 来源:dmitripavlutin 点赞再看,微信搜索【大迁世界(https://mp.weixin.qq.com/s/sY9ufGGKfcdaAQ7KJQs3HA)】,B站关注【前端小智(https://space.bilibili.com/31089477)】这个没有大厂背景,但有着一股向上积
Vue | 路由守卫面试常考
前言 最近在整理基础,欢迎掘友们一起交流学习,关注公众号<a href"https://z3.ax1x.com/2021/03/27/6zmqSI.jpg"前端自学社区</a <br/ 结尾有彩蛋哦! 🎉🎉🎉 Vue Router 路由守卫 导图目录 1. 路由守卫分类 2. 全局路由守卫 3. 单个路由守卫
Android创建定时器的一般方法
Android定时器今天就来细数一下Android是如何创建定时器的,一般有五种常用方法。请看下文。 一、利用Timer TimerTask就像它的名字一样,一看就知道可以用来做定时器。直接看代码: javaTimer timer new Timer();timer.schedule(new TimerTask() { @Ove
Compose Weekly #3:Bloom
本文同步发表于我的微信公众号,在微信搜索 OpenCV or Android 即可关注。 前言第三周挑战赛是速度比拼,按照官方发出的设计图最快完成且符合所有设计规范者胜出。不仅要做得快,还要做得好,奖品自然不会少。这一期的奖品是:Google Pixel 5。深知干不过业界大佬们,花个半天纯当练手完成题目。 设计图 设计风格 界面导航 界面标注 完整设计图:
Compose Weekly #4:Weather App
本文同步发表于我的微信公众号,在微信搜索 OpenCV or Android 即可关注。 前言 It's raining... Compose! Pull out all the stops for this final challenge. Build a beautiful weather app for a chance to win a Pixel
前端进阶:细数2年内我做的15个开源项目
从19年到21年,笔者利用空余时间陆陆续续做了一些开源项目, 大部分开源项目都立足于企业实际业务需求, 所以笔者觉得有必要做一个总结和复盘,在复盘的过程中希望也能对大家有所帮助.今后笔者的开源项目都会放在这篇文章中,如果想学习的可以多交流.1\. 基于indexedDB封装的轻量级缓存库github地址: 学习资料:](https://zhuanlan.zh
https://cloud.tencent.com/developer/article/write/1830331
一、目标今天的目标是这个sign和appcode 二、步骤 Jadx没法上了app加了某梆的企业版,Jadx表示无能为力了。 FRIDADEXDumpDexDump出来,木有找到有效的信息。 Wallbreaker葫芦娃的Wallbreaker可以做些带壳分析,不过这个样本,用Frida的Spawn模式可以载入,Attach模式会失败。而直接用Objecti
vue项目中使用element-ui实现excel表格上传
恰逢项目中要实现excel表格上传,度娘甚久,得此一文,留之。原文:https://blog.csdn.net/qq36718999/article/details/95387542 需求 vuecli 搭建前端项目,并使用elementui实现本地excel表格上传。(1) 限制上传文件只能是 xls、xlsx格式;(2) 限制上传文件大小不能超过 2MB