You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android如何实现TextInputLayout末尾图标可控显隐的持续涟漪动画

可实现方案

完全可以在不改动原有TextInputLayout末尾图标drawable配置的前提下,实现可编程控制显示/隐藏的持续涟漪效果,不需要替换原有图标资源。

实现步骤

    1. 确保项目引入的Material Components库版本不低于1.2.0,低版本可通过遍历子View的方式获取末尾图标实例:
      implementation 'com.google.android.material:material:1.6.0'
    1. 编写自定义持续涟漪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
}
    1. 将涟漪效果绑定到TextInputLayout的末尾图标上,通过View的overlay层添加,不会覆盖原有图标:
// 待布局加载完成后执行绑定逻辑
textInputLayout.post {
    val endIconView = textInputLayout.endIconView
    val rippleDrawable = ContinuousRippleDrawable()
    endIconView.overlay.add(rippleDrawable)
    // 将rippleDrawable存为页面成员变量,后续用于控制显示隐藏
    mEndIconRipple = rippleDrawable
}
    1. 编程控制显示隐藏:直接调用对应方法即可,不会影响原有图标的点击、显示逻辑
    • 显示涟漪: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 23:15:47