Android如何高效实现低开销的加载旋转动效?
安卓轻量加载旋转动效实现方案
问题背景
开发包含大量远程视图加载逻辑的应用时,需要在内容加载完成前展示旋转加载动效作为占位。此前为了加载存放在res/raw下的spinner.gif动图,引入了体积较大的Glide依赖,属于过度实现;曾尝试使用ProgressBar,但因未正确配置样式仅能展示水平进度条,无法满足旋转加载提示需求。
注:需求不局限于GIF形式,任何可标识「加载中」状态的旋转视图/动画均可使用
原有Glide实现代码
val gif = findViewById<ImageView>(rr.id.gif) Glide.with(context) .asGif() .load(rr.raw.spinner) .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.NONE)) .listener(object : RequestListener<GifDrawable?> { override fun onLoadFailed( e: GlideException?, model: Any?, target: Target<GifDrawable?>, isFirstResource: Boolean ): Boolean { return false } override fun onResourceReady( resource: GifDrawable?, model: Any?, target: Target<GifDrawable?>, dataSource: DataSource?, isFirstResource: Boolean ): Boolean { resource?.setLoopCount(999999999) return false } }) .into(gif)
零依赖替代方案
以下方案均不需要引入任何第三方库,包体积增量为0,性能远高于GIF解码播放的实现方式:
方案1:使用原生环形ProgressBar(成本最低)
你之前使用ProgressBar仅展示水平进度条,是因为没有指定环形不确定进度的样式,系统原生已经提供了成熟的无限旋转加载控件,不需要额外写动画逻辑。
布局中直接引入即可:
<ProgressBar android:id="@+id/loading_spinner" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/Widget.AppCompat.ProgressBar" android:indeterminate="true" <!-- 如需自定义颜色,添加这行即可 --> android:indeterminateTint="@color/your_brand_color" />
业务代码中只需要在加载开始时设置loading_spinner.visibility = View.VISIBLE,加载完成后设置为View.GONE即可,动效循环、帧率调度全由系统原生实现,内存占用最低。
方案2:静态资源+旋转动画(支持自定义图标)
如果你需要使用自定义样式的加载图标(比如品牌相关的旋转标识),不需要使用GIF,直接给静态图标(png/矢量图均可)加系统旋转动画即可,比GIF流畅度更高、没有帧压缩导致的锯齿问题。
实现步骤:
- 将自定义加载静态图标放入
res/drawable目录 - 在
res/anim目录下创建旋转动画配置rotating_spinner.xml:
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1200" android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%" android:repeatCount="infinite" android:interpolator="@android:anim/linear_interpolator" />
- 布局中使用普通ImageView承载:
<ImageView android:id="@+id/custom_spinner" android:layout_width="32dp" android:layout_height="32dp" android:src="@drawable/your_custom_spinner_icon" />
- 代码中启动/停止动画:
// 加载开始时启动动画 val rotateAnim = AnimationUtils.loadAnimation(context, R.anim.rotating_spinner) custom_spinner.startAnimation(rotateAnim) // 加载完成时停止动画 custom_spinner.clearAnimation() custom_spinner.visibility = View.GONE
方案3:AnimatedVectorDrawable矢量动效(体验最优)
如果应用minSdkVersion在21以上(覆盖99%以上的现役设备),可以使用矢量动画实现加载动效,整个资源体积只有几KB,支持任意缩放不会失真,还可以实现更复杂的组合动效,不需要依赖任何第三方库。
方案选型建议
- 无自定义样式需求:直接选原生环形ProgressBar,接入成本为0,性能最好
- 需要自定义加载图标:选静态资源+旋转动画,实现简单,效果优于GIF
- 需要精致无损动效:选AnimatedVectorDrawable,体积极小,流畅度最高
内容的提问来源于stack exchange,提问作者Yurowitz
相关产品推荐
相关产品推荐

