Android如何实现TextInputLayout末尾图标可控显隐的持续涟漪动画
可实现方案
完全可以在不改动原有TextInputLayout末尾图标drawable配置的前提下,实现可编程控制显示/隐藏的持续涟漪效果,不需要替换原有图标资源。
实现步骤
- 确保项目引入的Material Components库版本不低于1.2.0,低版本可通过遍历子View的方式获取末尾图标实例:
implementation 'com.google.android.material:material:1.6.0'
- 确保项目引入的Material Components库版本不低于1.2.0,低版本可通过遍历子View的方式获取末尾图标实例:
- 编写自定义持续涟漪Drawable,核心逻辑是循环绘制半径递增、透明度递减的圆形,实现扩散效果:
import android.animation.ValueAnimator import android.graphics.Canvas import android.graphics.Color import android.graphics.ColorFilter import android.graphics.Paint import android.graphics.PixelFormat import android.graphics.drawable.Drawable import android.util.TypedValue import android.view.animation.LinearInterpolator class ContinuousRippleDrawable(private val rippleColor: Int = Color.parseColor("#4D2196F3")) : Drawable() { private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = rippleColor style = Paint.Style.FILL } private var currentRippleRadius = 0f private var currentRippleAlpha = 255 private val rippleAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 1500 // 单轮涟漪动画时长,可按需调整 repeatCount = ValueAnimator.INFINITE interpolator = LinearInterpolator() addUpdateListener { val fraction = it.animatedValue as Float currentRippleRadius = intrinsicWidth / 2f * fraction currentRippleAlpha = (255 * (1 - fraction)).toInt() invalidateSelf() } } override fun draw(canvas: Canvas) { paint.alpha = currentRippleAlpha val centerX = bounds.width() / 2f val centerY = bounds.height() / 2f canvas.drawCircle(centerX, centerY, currentRippleRadius, paint) } override fun setAlpha(alpha: Int) { paint.alpha = alpha } override fun setColorFilter(colorFilter: ColorFilter?) { paint.colorFilter = colorFilter } @Deprecated("Deprecated in Java", ReplaceWith("PixelFormat.TRANSLUCENT")) override fun getOpacity(): Int { return PixelFormat.TRANSLUCENT } /** * 开始显示持续涟漪效果 */ fun showRipple() { if (!rippleAnimator.isRunning) { rippleAnimator.start() } } /** * 隐藏涟漪效果 */ fun hideRipple() { rippleAnimator.cancel() currentRippleRadius = 0f currentRippleAlpha = 255 invalidateSelf() } override fun getIntrinsicWidth(): Int { return TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 48f, resources.displayMetrics ).toInt() } override fun getIntrinsicHeight(): Int = intrinsicWidth }
- 将涟漪效果绑定到TextInputLayout的末尾图标上,通过View的overlay层添加,不会覆盖原有图标:
// 待布局加载完成后执行绑定逻辑 textInputLayout.post { val endIconView = textInputLayout.endIconView val rippleDrawable = ContinuousRippleDrawable() endIconView.overlay.add(rippleDrawable) // 将rippleDrawable存为页面成员变量,后续用于控制显示隐藏 mEndIconRipple = rippleDrawable }
- 编程控制显示隐藏:直接调用对应方法即可,不会影响原有图标的点击、显示逻辑
- 显示涟漪:
mEndIconRipple.showRipple() - 隐藏涟漪:
mEndIconRipple.hideRipple()
适配说明:如果使用的Material库版本低于1.2.0,没有提供
getEndIconView()API,可以通过遍历TextInputLayout子View,查找ID为com.google.android.material.R.id.text_input_end_icon的ImageView实例,后续绑定逻辑完全一致。
实现效果参考:
内容的提问来源于stack exchange,提问作者davidm
相关产品推荐
相关产品推荐

