wordpress网站无法访问,宁波网站制作出售,seo查询百科,建一个在线商城网站效果 倒计时View视频 背景
业务场景需要显示带有毫秒级别的倒计时#xff0c;于是自己封装一个通用的倒计时组件
源码分析
核心倒计时逻辑#xff0c;主要是每隔100毫秒计算一次从开始倒计时到现在的剩余时间#xff0c;并通过process接口返回出去Handler每次设置100毫秒…效果 倒计时View视频 背景
业务场景需要显示带有毫秒级别的倒计时于是自己封装一个通用的倒计时组件
源码分析
核心倒计时逻辑主要是每隔100毫秒计算一次从开始倒计时到现在的剩余时间并通过process接口返回出去Handler每次设置100毫秒的延迟将返回出来的时间解析出来
private fun formatTimeToView(remainTime: Long) {val lengthSec remainTime / 1000val hours lengthSec / 3600val rem lengthSec % 3600val minutes rem / 60val seconds rem % 60val milliseconds remainTime % 1000tvMill.text String.format(%03d, milliseconds)tvHour.text String.format(%02d, hours)tvMin.text String.format(%02d, minutes)tvSecond.text String.format(%02d, seconds)
}完整源码
class MillCountdownView JvmOverloads constructor(context: Context, attrs: AttributeSet? null
) : LinearLayout(context, attrs) {private val root LayoutInflater.from(context).inflate(R.layout.view_count_down, this, true)private val countDownTask: CountDownRunnableprivate val tvHour: TextViewprivate val tvMin: TextViewprivate val tvSecond: TextViewprivate val tvMill: TextViewinit {background context.getDrawable(R.drawable.count_down_item_bg)orientation HORIZONTALgravity Gravity.CENTER_VERTICALtvHour root.findViewById(R.id.tvHour)tvMin root.findViewById(R.id.tvMin)tvSecond root.findViewById(R.id.tvSecond)tvMill root.findViewById(R.id.tvMill)countDownTask CountDownRunnable(1).apply {listener object : TaskListener {override fun finish() {tvHour.text 00tvMin.text 00tvSecond.text 00tvMill.text 000Toast.makeText(context, 倒计时结束, Toast.LENGTH_SHORT).show()}override fun process(remainTime: Long) {if (remainTime 1) {tvHour.text 00tvMin.text 00tvSecond.text 00tvMill.text 000return}formatTimeToView(remainTime)}}}}private fun formatTimeToView(remainTime: Long) {val lengthSec remainTime / 1000val hours lengthSec / 3600val rem lengthSec % 3600val minutes rem / 60val seconds rem % 60val milliseconds remainTime % 1000tvMill.text String.format(%03d, milliseconds)tvHour.text String.format(%02d, hours)tvMin.text String.format(%02d, minutes)tvSecond.text String.format(%02d, seconds)}/*** 预先展示倒计时文本* param remainTime 倒计时时间单位毫秒*/fun preShowRemainSecs(remainTime: Long) {countDownTask.totalCountDownTime remainTimeformatTimeToView(remainTime)}/*** 开始倒计时* param remainTime 倒计时时间单位毫秒*/fun startCountdown(remainTime: Long) {countDownTask.destroy()countDownTask.totalCountDownTime remainTimecountDownTask.start()}fun destroyCountdown() {countDownTask.destroy()}
}class CountDownRunnable(IntRange(from 1)var totalCountDownTime: Long) : Runnable {private val mHandler Handler(Looper.getMainLooper())var listener: TaskListener? nullprivate var startCountDownTime 0L //开始时当前系统时间private var isTaskExecuting falseoverride fun run() {if (!isTaskExecuting) {return}val dur SystemClock.elapsedRealtime() - startCountDownTimeval remainTime totalCountDownTime - durval mill remainTime % 1000if (remainTime 0) {listener?.finish()isTaskExecuting falsereturn} else {listener?.process(remainTime)}mHandler.postDelayed(this, 100)}fun start() {startCountDownTime SystemClock.elapsedRealtime()mHandler.post(this)isTaskExecuting true}fun resume() {val remainTime totalCountDownTime - ((SystemClock.elapsedRealtime() - startCountDownTime) / 1000).toInt()if (remainTime 0) {listener?.finish()return}mHandler.removeCallbacks(this)isTaskExecuting truemHandler.post(this)}fun pause() {isTaskExecuting falsemHandler.removeCallbacks(this)}fun destroy() {isTaskExecuting falsemHandler.removeCallbacks(this)}
}interface TaskListener {fun finish()fun process(remainTime: Long)
}?xml version1.0 encodingutf-8?
merge xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:gravitycenter_verticalandroid:orientationhorizontaltools:parentTagLinearLayoutandroidx.appcompat.widget.AppCompatTextViewandroid:idid/tvHourandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:minWidth30dpandroid:gravitycenterandroid:textColor#000android:textSize25spandroid:textStyleboldandroid:layout_marginStart10dpandroid:layout_marginVertical5dptools:text1 /androidx.appcompat.widget.AppCompatTextViewandroid:idid/divider1android:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginHorizontal4dpandroid:gravitycenterandroid:text:android:textColor#000android:textSize25spandroid:textStylebold /androidx.appcompat.widget.AppCompatTextViewandroid:idid/tvMinandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginStart5dpandroid:gravitycenterandroid:textColor#000android:minWidth30dpandroid:textSize25spandroid:textStyleboldtools:text8 /androidx.appcompat.widget.AppCompatTextViewandroid:idid/divider2android:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginHorizontal4dpandroid:gravitycenterandroid:text:android:textColor#000android:textSize25spandroid:textStylebold /androidx.appcompat.widget.AppCompatTextViewandroid:idid/tvSecondandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:gravitycenterandroid:textColor#000android:textSize25spandroid:textStyleboldandroid:minWidth30dptools:text3 /androidx.appcompat.widget.AppCompatTextViewandroid:idid/divider3android:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginHorizontal4dpandroid:gravitycenterandroid:text:android:textColor#000android:textSize25spandroid:textStylebold /androidx.appcompat.widget.AppCompatTextViewandroid:idid/tvMillandroid:layout_widthwrap_contentandroid:minWidth49dpandroid:layout_heightwrap_contentandroid:layout_marginStart5dpandroid:gravitycenterandroid:textColor#a00android:textSize25spandroid:textStyleboldtools:text000android:layout_marginEnd10dp//merge