企业为什么需要手机网站,系统开发工程师是干什么的,wordpress 子主题目录,重庆建设工程信息网三类人员ContentLoadingProgressBar 是 Android 中的一个控件#xff0c;继承自 ProgressBar。它在 ProgressBar 的基础上添加了一些特殊功能#xff0c;主要用于在加载内容时显示进度。它的一些主要特点如下#xff1a;
自动隐藏和显示#xff1a;ContentLoadingProgressBar 会在…ContentLoadingProgressBar 是 Android 中的一个控件继承自 ProgressBar。它在 ProgressBar 的基础上添加了一些特殊功能主要用于在加载内容时显示进度。它的一些主要特点如下
自动隐藏和显示ContentLoadingProgressBar 会在内容加载完成后自动隐藏并在内容开始加载时自动显示。这减少了手动控制进度条显示和隐藏的代码量。延迟显示为了避免在短时间内频繁显示和隐藏进度条ContentLoadingProgressBar 提供了一个延迟显示的功能。如果内容加载时间非常短进度条可能不会显示出来。延迟隐藏类似地ContentLoadingProgressBar 也提供了延迟隐藏的功能以确保进度条在内容加载完成后不会立即消失从而提供更好的用户体验。
这些功能使 ContentLoadingProgressBar 成为一个更智能、更易用的进度条控件特别适合在需要频繁加载内容的应用中使用。
1、ContentLoadingProgressBar 的特性
从注释中可以看出ContentLoadingProgressBar 在 ProgressBar 的基础上添加了以下特性
在显示之前会等待一段时间来被隐藏这意味着在显示之前ContentLoadingProgressBar 会等待一段时间如果在这段时间内被隐藏那么就不会显示出来。一旦显示ContentLoadingProgressBar 会在一段时间内保持可见这确保了进度条不会在短时间内频繁显示和隐藏避免了 UI 视图的“闪烁”现象。
这种“闪烁”现象在项目开发中很常见例如在进行网络请求之前显示 Loading 对话框请求完成之后再隐藏。如果网络请求耗时很短就会导致对话框在短时间内显示和隐藏造成“闪烁”现象。ContentLoadingProgressBar 的这两个特性很好地解决了这个问题。
2、ContentLoadingProgressBar 的实现
ContentLoadingProgressBar 中定义了两个 int 类型的常量 MIN_SHOW_TIME 和 MIN_DELAY分别表示显示的最短时间和延迟显示的时间值都是 500ms。mDelayedShow 和 mDelayedHide 是两个 Runnable 任务分别对应延时显示和延时隐藏。在控制 ContentLoadingProgressBar 的显示和隐藏时不能使用 setVisibility() 方法而是需要使用 show() 和 hide() 方法。
show() 方法
public void show() {mStartTime -1;mPostedHide false;mPostedShow true;removeCallbacks(mDelayedHide);if (!mPostedShow) {postDelayed(mDelayedShow, MIN_DELAY);}
}show() 方法首先会做一些状态的恢复处理将 mStartTime 恢复为 -1mStartTime 记录了 ContentLoadingProgressBar 开始显示的时间接着将延时隐藏任务 mDelayedHide 从任务队列中移除。方法最后会判断 mPostedShow 的值如果为 false 就调用 postDelayed() 方法延迟 MIN_DELAY500ms后执行 mDelayedShow 任务。mPostedShow 用于标记 mDelayedShow 是否已添加到任务队列中防止任务的重复执行。mDelayedShow 任务的逻辑很简单主要就是记录开始显示的时间并执行 setVisibility(View.VISIBLE) 将 ContentLoadingProgressBar 显示出来。
hide() 方法
public void hide() {mPostedHide true;removeCallbacks(mDelayedShow);long diff System.currentTimeMillis() - mStartTime;if (diff MIN_SHOW_TIME || mStartTime -1) {setVisibility(View.GONE);} else {postDelayed(mDelayedHide, MIN_SHOW_TIME - diff);}
}hide() 方法和 show() 方法类似首先将延时显示任务 mDelayedShow 从任务队列中移除因此如果调用 show() 和 hide() 方法之间的间隔时间小于 MIN_DELAY500msmDelayedShow 就不会执行了ContentLoadingProgressBar 也就不会显示了。接下来会计算 System.currentTimeMillis() - mStartTime 的值即此时 ContentLoadingProgressBar 的显示时间如果此时 mStartTime 的值为 -1ContentLoadingProgressBar 还没有显示或者显示时间超过了 MIN_SHOW_TIME500ms直接执行 setVisibility(View.GONE) 隐藏 ContentLoadingProgressBar反之则说明 ContentLoadingProgressBar 的显示时间没有达到最短时间 500ms计算剩余的时间延时执行隐藏任务保证 ContentLoadingProgressBar 最短可以显示 500ms。这里的 mPostedHide 作用同样是防止延时隐藏任务的重复执行。mDelayedHide 任务的逻辑也比较简单将 mStartTime 恢复为 -1执行 setVisibility(View.GONE) 隐藏 ContentLoadingProgressBar。
3、自定义Loading 对话框
ContentLoadingProgressBar 给了我们很好的思路解决 Loading 对话框“闪烁”问题需要做到以下两点
显示 Loading 对话框之前先等待一段时间。隐藏 Loading 对话框时判断显示时间是否达到了最短显示时间如果没有达到就延时执行隐藏任务。
清楚思路后就可以优化 Loading 对话框了直接附上完整代码
package com.jpc.customwidgetstudy.widgetimport android.app.Activity
import android.app.AlertDialog
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import com.jpc.customwidgetstudy.R/*** 自定义Loading Dialog, 用于显示加载中的状态*/
class LoadingDialog(context: Context): AlertDialog(context, R.style.Theme_AppCompat_Dialog){companion object{// 最短显示时间private const val MIN_SHOW_TIME 500L// 最短延迟时间private const val MIN_DELAY_TIME 500L}private var tvMessage: TextViewinit {val parent (context as? Activity)?.findViewByIdViewGroup(android.R.id.content)val loadView LayoutInflater.from(context).inflate(R.layout.dialog_loading, parent, false)setView(loadView)tvMessage loadView.findViewById(R.id.tv_message)}// 记录开始时间private var mStartTime: Long -1// 防止延时隐藏任务的重复执行private var mPostedHide: Boolean false// 防止延时显示任务的重复执行private var mPostedShow: Boolean false// 是否已经消失private var mDismissed: Boolean false// 主线程Handlerprivate val mHandler Handler(Looper.getMainLooper())// 显示private val mDelayedShow: Runnable Runnable {mPostedShow falseif (!mDismissed){mStartTime System.currentTimeMillis()show()}}// 隐藏private val mDelayedHide: Runnable Runnable {mPostedHide falsemStartTime -1dismiss()}// 显示Dialogfun showDialog(message: String){tvMessage.text messagemStartTime -1mDismissed falsemHandler.removeCallbacks(mDelayedHide)mPostedHide falseif (!mPostedShow){mHandler.postDelayed(mDelayedShow, MIN_DELAY_TIME)mPostedShow true}}// 隐藏Dialogfun hideDialog(){mDismissed truemHandler.removeCallbacks(mDelayedShow)mPostedShow falseval diff System.currentTimeMillis() - mStartTimeif (diff MIN_SHOW_TIME || mStartTime -1L){dismiss()}else{if (!mPostedHide){mHandler.postDelayed(mDelayedHide, MIN_SHOW_TIME - diff)mPostedHide true}}}// 从Window移除时移除所有的Callbackoverride fun onDetachedFromWindow() {super.onDetachedFromWindow()mHandler.removeCallbacks(mDelayedHide)mHandler.removeCallbacks(mDelayedShow)}
}可以定义Dialog的大小 style nameTheme.AppCompat.Dialog parentTheme.AppCompat.Light.Dialog!-- Customize your dialog theme here --item nameandroid:windowBackgroundcolor/loading_color/itemitem nameandroid:windowMinWidthMajor30%/itemitem nameandroid:windowMinWidthMinor30%/itemitem nameandroid:padding6dp/item/style!-- Custom ProgressBar style --style nameCustomProgressBar parentWidget.AppCompat.ProgressBaritem nameandroid:indeterminateTintcolor/colorPrimary/item/style?xml version1.0 encodingutf-8?
androidx.constraintlayout.widget.ConstraintLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentxmlns:apphttp://schemas.android.com/apk/res-autoProgressBarandroid:idid/progressBarandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentapp:layout_constraintBottom_toTopOfid/tv_messageapp:layout_constraintStart_toStartOfid/tv_messageapp:layout_constraintEnd_toEndOfid/tv_messagestylestyle/CustomProgressBar/TextViewandroid:idid/tv_messageandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text加载中...app:layout_constraintTop_toTopOfparentapp:layout_constraintBottom_toBottomOfparentapp:layout_constraintStart_toStartOfparentapp:layout_constraintEnd_toEndOfparent //androidx.constraintlayout.widget.ConstraintLayout布局文件就是一个 ProgressBar 和一个 TextView用于展示提示信息。控制 Loading 对话框的显示和隐藏直接使用 showDialog() 和 hideDialog() 方法就可以了。为了简单示例这里自定义的 Dialog 直接继承自 AlertDialog注意要在适当的时机移除延时任务防止内存泄漏。
效果如下
总结
本文通过分析 ContentLoadingProgressBar 的原理引出了项目开发中 Loading 对话框的一种优化方式避免对话框显示和隐藏间隔时间太短导致的“闪烁”现象。