Android Studio波浪式字母滚动条动画优化求助

我在LinearLayout中放置了一组字母TextView,希望点击任意字母时,能实现如图所示的波浪式位置移动动画,该效果与Niagra启动器的应用抽屉滚动条类似。目前我的代码能实现类似效果,但动画流畅度不如该启动器的滚动条,恳请帮忙优化!
当前实现代码
private fun moveTextViewsToLeft1(index: Int) { val adjacentViews = mutableListOf<Pair<View, Float>>() val touchedViewTranslationX = -100f val neighborTranslationX = -80f val extraNeighborTranslationX1 = -45f val extraNeighborTranslationX2 = -10f // Add touched textView val touchedView = getChildAt(index) adjacentViews.add(touchedView to touchedViewTranslationX) // Add top neighbors for (i in index - 1 downTo 0) { val view = getChildAt(i) val translationX = when (index - i) { 1 -> neighborTranslationX 2 -> extraNeighborTranslationX1 3 -> extraNeighborTranslationX2 else -> 0f } adjacentViews.add(view to translationX) } // Add bottom neighbors for (i in index + 1 until childCount) { val view = getChildAt(i) val translationX = when (i - index) { 1 -> neighborTranslationX 2 -> extraNeighborTranslationX1 3 -> extraNeighborTranslationX2 else -> 0f } adjacentViews.add(view to translationX) } val animators = mutableListOf<ObjectAnimator>() for ((view, translationXValue) in adjacentViews) { val animator = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, translationXValue) animator.duration = ANIMATION_DURATION animator.interpolator = AccelerateDecelerateInterpolator() animators.add(animator) } val set = AnimatorSet() set.playTogether(animators as Collection<Animator>?) set.addListener(object : Animator.AnimatorListener { override fun onAnimationStart(animation: Animator) { isAnimating = true } override fun onAnimationEnd(animation: Animator) { isAnimating = false } override fun onAnimationCancel(animation: Animator) { isAnimating = false } override fun onAnimationRepeat(animation: Animator) {} }) set.start() }
优化方案及实现
核心优化点
- 减少Animator实例数量:原代码给每个View单独创建ObjectAnimator,会导致系统同时处理多个动画任务,改用单个
ValueAnimator统一更新所有View的偏移量,降低系统开销。 - 优化遍历逻辑:只处理点击位置前后各3个View(超过3个偏移量为0),避免不必要的循环遍历。
- 替换插值器:用
PathInterpolator自定义更贴合波浪效果的动画曲线,比默认的AccelerateDecelerateInterpolator更自然。 - 减少对象创建:缓存动画参数和插值器,避免每次触发动画都重复创建。
优化后的代码
// 作为成员变量缓存,避免每次创建 private val waveOffsetMap = mapOf( 0 to -100f, // 点击的View偏移量 1 to -80f, // 相邻1级偏移量 2 to -45f, // 相邻2级偏移量 3 to -10f // 相邻3级偏移量 ) private val waveInterpolator = PathInterpolator(0.3f, 0.0f, 0.2f, 1.0f) // 可根据效果微调控制点 private fun moveTextViewsToLeftOptimized(index: Int) { val touchedView = getChildAt(index) ?: return isAnimating = true ValueAnimator.ofFloat(0f, 1f).apply { duration = ANIMATION_DURATION interpolator = waveInterpolator addUpdateListener { animator -> val progress = animator.animatedValue as Float // 更新点击的View touchedView.translationX = waveOffsetMap[0]!! * progress // 更新上方最多3个邻居 for (level in 1..3) { val targetIndex = index - level if (targetIndex < 0) break getChildAt(targetIndex).translationX = waveOffsetMap[level]!! * progress } // 更新下方最多3个邻居 for (level in 1..3) { val targetIndex = index + level if (targetIndex >= childCount) break getChildAt(targetIndex).translationX = waveOffsetMap[level]!! * progress } } addListener(object : Animator.AnimatorListener { override fun onAnimationEnd(animation: Animator) { isAnimating = false // 若需要动画结束后重置位置,可在此处遍历相关View设置translationX=0f } override fun onAnimationStart(animation: Animator) {} override fun onAnimationCancel(animation: Animator) { isAnimating = false } override fun onAnimationRepeat(animation: Animator) {} }) start() } }
额外优化建议
- 开启硬件加速:在包含TextView的LinearLayout布局中添加
android:hardwareAccelerated="true",或在代码中给目标View设置view.setLayerType(View.LAYER_TYPE_HARDWARE, null),提升动画渲染性能。 - 动画中断处理:如果用户在动画未结束时再次点击,可先取消当前动画再启动新动画,避免动画冲突。
内容的提问来源于stack exchange,提问作者Ashique
相关产品推荐
相关产品推荐

