exitfadeduration在selector中不生效,主要是因用在android:background上且旧版statelistdrawable不支持;需改用api 21+的animatedstatelistdrawable并在内配置alpha动画,或用viewpropertyanimator手动控制。

selector 中 exitFadeDuration 不生效的常见原因
Android 的 selector XML 里设了 exitFadeDuration,但按钮状态切换时还是“啪”一下跳变,没淡出效果——大概率是因为你用在了 android:background 上,而该属性只对 android:foreground 或 android:drawable(如 TextView 的 android:drawableStart)起作用。系统级背景动画默认被禁用,且 StateListDrawable 的旧实现根本不读这个字段。
真正能控制淡出时间的写法:用 AnimatedStateListDrawable
想让按钮背景在 pressed → default 切换时淡出,必须升级到 API 21+ 的 AnimatedStateListDrawable,它支持 exitFadeDuration。XML 要拆成两层:animated-selector 定义状态映射,transition 定义进出动画。
-
res/drawable-v21/btn_bg_animated.xml是唯一能生效的位置,低版本会自动 fallback 到普通selector -
exitFadeDuration必须写在<transition></transition>标签内,不是外层<item></item> - 对应动画资源得是
alpha动画(res/anim/fade_out.xml),不能用ValueAnimator或 Lottie
<?xml version="1.0" encoding="utf-8"?><animated-selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:id="@+id/pressed" android:drawable="@drawable/btn_pressed" android:state_pressed="true"></item><item android:id="@+id/default" android:drawable="@drawable/btn_default"></item><transition android:fromid="@+id/pressed" android:toid="@+id/default"><animation-list><item android:duration="150"><alpha android:fromalpha="1.0" android:toalpha="0.0"></alpha></item></animation-list></transition></animated-selector>
替代方案:用 ViewPropertyAnimator 手动控制
如果要兼容 API 16 或需要更精细的时序(比如按住不放时暂停淡出),XML 就不够用了。直接在代码里监听状态变化,用 ViewPropertyAnimator 控制 alpha 更可靠。
- 在
setOnTouchListener里区分ACTION_DOWN和ACTION_UP,避免和点击事件冲突 - 调用
animate().alpha(0.3f).setDuration(100)做按下态,再animate().alpha(1f).setDuration(200)做恢复 - 务必加
.setListener处理中断(比如用户中途滑出按钮区域),否则动画可能卡住
容易被忽略的细节:硬件加速与图层类型
即使动画代码写对了,淡出也可能卡顿或直接不触发——检查 View 是否启用了硬件加速,以及是否设置了正确图层类型。
-
button.setLayerType(View.LAYER_TYPE_HARDWARE, null)在动画期间必须开启,否则alpha动画不走 GPU - 如果按钮有圆角或阴影,
clipToOutline可能干扰 alpha 渲染,临时关掉再开 -
exitFadeDuration设为 0 不代表“立即”,而是跳过淡出;设负数会被忽略,不是反向播放
XML 动画的边界很窄,真要稳定控制淡出节奏,90% 的情况得切到代码层做状态管理。别指望一个属性值解决所有问题。










