Android Kotlin:如何实现带红色闪烁背景的错误提示自定义EditText
Android 自定义EditText红色闪烁背景优化方案
一、解决闪烁无法按时停止的问题
你的原实现中,多次调用showErrorBlink()会创建多个独立的Handler和Runnable,导致之前的闪烁任务无法被正确停止;另外局部变量的Runnable也可能因为引用问题导致移除失效。可以通过以下方式修复:
优化后的代码实现
class BlinkingEditText(context: Context, attrs: AttributeSet?) : AppCompatEditText(context, attrs) { private val handler = Handler(Looper.getMainLooper()) private var blinkRunnable: Runnable? = null private var isRed = false fun showErrorBlink() { // 启动新闪烁前先停止已有任务 stopBlink() isRed = false blinkRunnable = object : Runnable { override fun run() { setBackgroundColor(if (isRed) Color.WHITE else Color.RED) isRed = !isRed blinkRunnable?.let { handler.postDelayed(it, 500) } } } blinkRunnable?.let { handler.post(it) } // 3秒后自动停止 handler.postDelayed({ stopBlink() }, 3000) } private fun stopBlink() { blinkRunnable?.let { handler.removeCallbacks(it) } blinkRunnable = null // 停止后恢复白色背景 setBackgroundColor(Color.WHITE) } // View销毁时清理任务,避免内存泄漏 override fun onDetachedFromWindow() { super.onDetachedFromWindow() stopBlink() } }
核心改进点
- 用成员变量保存
Runnable实例,确保能精准移除任务 - 每次启动闪烁前强制停止已有任务,避免多任务冲突
- 在
onDetachedFromWindow中清理资源,防止内存泄漏
二、更高效的实现方案(推荐)
使用Android原生动画框架或XML Drawable,比手动切换背景色更高效、易维护。
方案1:使用ValueAnimator(推荐)
利用Android动画框架的ValueAnimator控制颜色切换,系统会自动优化重绘,控制更精确:
class BlinkingEditText(context: Context, attrs: AttributeSet?) : AppCompatEditText(context, attrs) { private var colorAnimator: ValueAnimator? = null fun showErrorBlink() { stopBlink() // 创建颜色切换动画,循环实现闪烁效果 colorAnimator = ValueAnimator.ofArgb(Color.WHITE, Color.RED, Color.WHITE).apply { duration = 500 // 单次颜色切换时长 repeatCount = 5 // 重复5次,总时长3秒(500ms*6次) repeatMode = ValueAnimator.REVERSE addUpdateListener { animator -> setBackgroundColor(animator.animatedValue as Int) } // 动画结束/取消时恢复背景 addListener(object : Animator.AnimatorListener { override fun onAnimationStart(animation: Animator) {} override fun onAnimationEnd(animation: Animator) { setBackgroundColor(Color.WHITE) colorAnimator = null } override fun onAnimationCancel(animation: Animator) { onAnimationEnd(animation) } override fun onAnimationRepeat(animation: Animator) {} }) start() } } private fun stopBlink() { colorAnimator?.let { it.removeAllListeners() it.cancel() } colorAnimator = null setBackgroundColor(Color.WHITE) } override fun onDetachedFromWindow() { super.onDetachedFromWindow() stopBlink() } }
方案2:使用XML AnimationDrawable
将动画逻辑分离到XML文件中,代码更简洁:
- 创建
res/drawable/blink_error_background.xml:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@color/white" android:duration="500"/> <item android:drawable="@color/red" android:duration="500"/> </animation-list>
- 代码实现:
class BlinkingEditText(context: Context, attrs: AttributeSet?) : AppCompatEditText(context, attrs) { private var blinkDrawable: AnimationDrawable? = null fun showErrorBlink() { stopBlink() // 设置闪烁背景并启动动画 val drawable = resources.getDrawable(R.drawable.blink_error_background, context.theme) as AnimationDrawable background = drawable blinkDrawable = drawable drawable.start() // 3秒后停止动画 Handler(Looper.getMainLooper()).postDelayed({ stopBlink() }, 3000) } private fun stopBlink() { blinkDrawable?.let { if (it.isRunning) it.stop() } blinkDrawable = null // 恢复默认白色背景 setBackgroundColor(Color.WHITE) } override fun onDetachedFromWindow() { super.onDetachedFromWindow() stopBlink() } }
内容的提问来源于stack exchange,提问作者Lily Monta
相关产品推荐
相关产品推荐

