Android 基于Kotlin Flow实现一个倒计时功能
文章目录
- 前情提要
- 实现倒计时功能
- 注意事项
- 完整代码地址
前情提要
上一篇 Android Kotlin之Flow数据流 中介绍了协程Flow
,我们知道Flow
数据流可以按顺序发送多个值,一个倒计时功能刚好符合这种场景,本文就尝试使用Flow
来实现一个倒计时功能。
上文中举过一个简单示例:
flow { log("send hello")emit("hello") //发送数据log("send world")emit("world") //发送数据}.flowOn(Dispatchers.IO).onEmpty { log("onEmpty") }.onStart { log("onStart") }.onEach { log("onEach: $it") }.onCompletion { log("onCompletion") }.catch { exception -> exception.message?.let { log(it) } }.collect {//接收数据流log("collect: $it")}
执行结果:
2021-09-27 19:51:54.433 7240-7240/ E/TTT: onStart
2021-09-27 19:51:54.439 7240-7325/ E/TTT: send hello
2021-09-27 19:51:54.440 7240-7325/ E/TTT: send world2021-09-27 19:51:54.451 7240-7240/ E/TTT: onEach: hello
2021-09-27 19:51:54.451 7240-7240/ E/TTT: collect:hello
2021-09-27 19:51:54.452 7240-7240/ E/TTT: onEach: world
2021-09-27 19:51:54.452 7240-7240/ E/TTT: collect:world
2021-09-27 19:51:54.453 7240-7240/ E/TTT: onCompletion
onStart
:上游flow{}
开始发送数据之前执行onCompletion
:flow
数据流取消或者结束时执行onEach
:上游向下游发送数据之前调用,每一个上游数据发送后都会经过onEach()
使用上面几个操作符,将传入的数据在flow{}
中每隔1s(通过delay(1000)
实现)发射出去,下游对接收的数据进行处理,即是一个倒计时功能,如下:
/*** 使用Flow实现一个倒计时功能*/private fun countDownByFlow(max: Int,scope: CoroutineScope,onTick: (Int) -> Unit,onFinish: (() -> Unit)? = null,): Job {return flow {for (num in max downTo 0) {emit(num)if (num != 0) delay(1000)}}.flowOn(Dispatchers.Main).onEach { onTick.invoke(it) }.onCompletion { cause -> if (cause == null) onFinish?.invoke() }.launchIn(scope) //保证在一个协程中执行}
实现倒计时功能
先上效果图:
主要代码逻辑:
class CountDownCircleView @JvmOverloads constructor(context: Context,attrs: AttributeSet? = null,defStyleAttr: Int = 0,
) : View(context, attrs, defStyleAttr) {private val mPaint: Paint = Paint().apply {isAntiAlias = trueisDither = truestyle = Paint.Style.STROKEstrokeCap = Paint.Cap.ROUNDstrokeWidth = 8.dp2px().toFloat()color = Color.parseColor("#F7F9FA")}private val mCirclePaint: Paint = Paint().apply {isAntiAlias = trueisDither = truestyle = Paint.Style.FILLcolor = Color.WHITE}private val mTextPaint: TextPaint = TextPaint().apply {isAntiAlias = trueisDither = truecolor = Color.parseColor("#A1EA42")textAlign = Paint.Align.CENTER //绘制方向 居中绘制textSize = 50.sp2px().toFloat()typeface = Typeface.DEFAULT_BOLD}private val mRect = RectF()private var mCenterX: Float = 0fprivate var mCenterY: Float = 0fprivate var mRadius: Float = 0fprivate var mMinWH: Float = 0fprivate val colorArr = intArrayOf(Color.parseColor("#BAF900"), Color.parseColor("#84F000"))//设置渐变色private val mLinearShader =LinearGradient(0f, 0f, mMinWH, mMinWH, colorArr, null, Shader.TileMode.MIRROR)private var mMaxCount: Int = 0 //最大数private var mSweepAngle: Float = 360f //扫描过的度数private var mCountDown: Job? = nullprivate var mText = ""/*** 开始倒计数*/fun startCountDown(count: Int, finishFuc: () -> Unit) {if (context !is FragmentActivity) returnthis.mMaxCount = countmCountDown = countDownByFlow(mMaxCount, (context as FragmentActivity).lifecycleScope,onTick = {if (it == 0) mCountDown?.cancel()mText = it.toString()mSweepAngle = (it / mMaxCount.toFloat()) * 360invalidate()}, onFinish = {finishFuc.invoke()})}override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {mCenterX = (w / 2).toFloat()mCenterY = (h / 2).toFloat()mMinWH = min(w, h).toFloat()mRadius = (mMinWH - mPaint.strokeWidth) / 2//设置矩形范围val strokeHalf = mPaint.strokeWidth / 2mRect.set(strokeHalf, strokeHalf, mMinWH - strokeHalf, mMinWH - strokeHalf)}override fun onDraw(canvas: Canvas?) {canvas?.let {mPaint.shader = null//绘制白色背景圆canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint)//绘制灰色背景圆canvas.drawCircle(mCenterX, mCenterY, mRadius, mPaint)//绘制渐变色弧形 从12点方向开始绘制mPaint.shader = mLinearShadercanvas.drawArc(mRect, -90f, mSweepAngle, false, mPaint)//绘制中间倒计时数字//如果设置的 Align = LEFT,那么baseX = (mMinWH - mTextPaint.measureText(mText)) / 2val baseX = mCenterX// 计算Baseline绘制的Y坐标 ,计算方式:画布高度的一半 - 文字总高度的一半val baseY =(mCenterY - (mTextPaint.descent() + mTextPaint.ascent()) / 2).toInt()// 居中画一个文字canvas.drawText(mText, baseX, baseY.toFloat(), mTextPaint)}}/*** 使用Flow实现一个倒计时功能*/private fun countDownByFlow(max: Int,scope: CoroutineScope,onTick: (Int) -> Unit,onFinish: (() -> Unit)? = null,): Job {return flow {for (num in max downTo 0) {emit(num)if (num != 0) delay(1000)}}.flowOn(Dispatchers.Main).onEach { onTick.invoke(it) }.onCompletion { cause -> if (cause == null) onFinish?.invoke() }.launchIn(scope) //保证在一个协程中执行}override fun onDetachedFromWindow() {super.onDetachedFromWindow()mCountDown?.cancel()}}
Activity中:
mBtnStart.setOnClickListener {mCountDownView.startCountDown(10) {showToast("倒计时结束")}
}
注意事项
- 这里实现的倒计时功能是基于
协程Flow
实现的,所以必须保证项目里是支持Kotlin
协程的才能使用; - 如果未使用协程
Flow
,将这里的倒计时逻辑改成CountDownTimer
或者Timer
来实现即可。
完整代码地址
完整代码地址:Kotlin Flow实现一个倒计时功能
Android 基于Kotlin Flow实现一个倒计时功能相关推荐
- android欢迎页圆形倒计时,android 欢迎页圆形进度条倒计时功能
常见app欢迎页圆形进度条倒计时功能,可设置显示文字,进度条颜色,宽度,倒计时时间,内圆颜色.设置进度条类型 顺数进度条(0-100)还是倒数进度条(100-0): 先上效果图: 下面介绍实现逻辑: ...
- Flutter StreamBuilder 实现的一个倒计时功能
题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精. Flutter是谷歌推出的最新的移动开发框架. [x1]微信公众号的每日提醒 随时随记 每日积累 随心而过 [x2]各种系列的视频教程 ...
- Android手摸手实现一个画板功能(一)——View的拖拽
一.概述 从之前项目中抽取出来的一个"画板"功能模块,就是可以在一个空白布局上,添加不同的元素,实现自由组合,暂时没想到啥好名字,姑且叫它"画板"吧. ...
- Android基于NSD实现网络服务发现功能
一. 简介 网络服务发现:一般是指通过此功能,在局域网内来发现同样支持此功能的设备,并跟其他设备建立连接. Android 提供了一个网络服务发现(NSD),可让应用访问其他设备在本地网路上提供的服务 ...
- Android中kotlin Flow的资源浪费/ANR问题
1.前提 一开始用Flow,主要用来替代LiveData,用来观察. 然后发现了StateFlow和SharedFlow这两个主要就是用来替代LiveData的. 两者区别: StateFlow: 1 ...
- Android Kotlin Flow 如何使用callbackflow
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/121840157 本文出自[赵彦军的博客] callbackFlow 原理 call ...
- QT-日期倒计时功能的小坑
想用QT做一个倒计时功能 参考这篇博客 遇到小坑记录一下 正确用法 void ctrl::timeUpDate() {QDateTime time=QDateTime::currentDateTime ...
- android 10 数字健康,Android P 的「数字健康」功能,实际体验如何?
Android P 的「数字健康」功能,实际体验如何? 2019-04-10 15:43:52 2点赞 5收藏 1评论 入手三星S10e也有一段时间,很多功能还没有细细体验,最近发现系统设置里有个「数 ...
- Android开发:基于Kotlin编写一个简易计算器
目录 前言 Kotlin学习tips 界面绘制及控件绑定 UI界面绘制 控件绑定 Button点击事件 运算逻辑 整体逻辑 边界情况 输入展示 点击数字键 点击运算符键 点击"=" ...
最新文章
- VS2010 重命名文件:源文件名和目标文件名相同 的解决方案
- matplotlib中文乱码
- sqlserver2008r2升级到2012的问题
- 关于stm32启动文件的选择
- 如何进行.NET高效开发
- Android Studio 下使用git -- 个人,本地版本控制
- python实现一个简单的加法计算器_Python简易项目 加减计算器的实现
- 9206 1225 mybank系统 随堂笔记
- Ceph保证数据安全的机制
- tfs2015 生成与发布 配置
- 生成器 Generators
- CoffeeScript、TypeScript 、 JavaScript 之间
- 想法独特 上半年最具特色摄像头集锦
- 抓包分析数据帧中IP数据包的一些关键字段【南邮网课例题】
- Ubuntu批量转换图片格式
- PowerShell,AnkhSVN和Subversion
- mysql创建唯一非聚集索引_创建聚集索引、非聚集索引、唯一索引、唯一键约束...
- 超详细从零记录Hadoop2.7.3完全分布式集群部署过程
- 使用intel编译器编译WRF4.4
- 差分放大电路及动态分析
热门文章
- 漆学军:MT4平台量化交易故事
- 苦七学习群提问内容整理210729
- 计算机二级考试剩30秒提交,计算机二级考试倒计时4天,四个方法教你高效备战...
- 从MediaRecord录像中读取H264参数
- 360安卓_有解商城安卓版App上架360及百度手机助手
- 《淘宝网开店 拍摄 修图 设计 装修 实战150招》一一1.14 如何掌握拍摄角度
- Global Usings 和 Implicit Usings
- java打印线程堆栈_Java问题定位之Java线程堆栈分析
- 你看,你看,月亮的笑脸!
- Rey英文版主题-时尚与服装商城主题-WordPress响应式