Android中使用BindingAdapter加载XML配置自定义动画问题
问题原因分析
- DataBinding的BindingAdapter仅会解析用
@{}包裹的属性表达式,你示例中不带@{}的两种写法(app:CustomAnimationtoLoad="@anim/slide_top_to_bottom"、app:CustomAnimationtoLoad="R.anim.slide_top_to_bottom")属于普通XML属性赋值,不会触发你写的BindingAdapter逻辑 - 直接在XML中写
app:CustomAnimationtoLoad="R.anim.slide_top_to_bottom"是字符串类型赋值,无法自动转换为Int类型的动画资源ID,会触发类型不匹配异常 - 动画启动时机不合理:BindingAdapter回调时View大概率还未完成测量、未attach到窗口,此时调用
startAnimation不会生效 - 如果你把BindingAdapter写在类、单例类内部,缺少
@JvmStatic注解会导致DataBinding无法反射找到对应方法,逻辑不触发
修复方案
1. 修正BindingAdapter代码
顶层文件写法(推荐)
直接放在独立的Kotlin顶层文件中,无需额外注解:
@BindingAdapter("CustomAnimationtoLoad") fun View.setCustomAnimationtoLoad(@AnimRes animResId: Int) { // 等待View挂载到窗口后再启动动画,避免动画不生效 doOnAttach { val targetAnim = AnimationUtils.loadAnimation(context, animResId) startAnimation(targetAnim) } }
类内部写法
如果放在单例类中,需要添加@JvmStatic注解:
object AnimationBindingAdapter { @JvmStatic @BindingAdapter("CustomAnimationtoLoad") fun View.setCustomAnimationtoLoad(@AnimRes animResId: Int) { doOnAttach { val targetAnim = AnimationUtils.loadAnimation(context, animResId) startAnimation(targetAnim) } } }
如果你没有引入AndroidX Core KTX扩展,可将
doOnAttach替换为原生监听逻辑:addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { val targetAnim = AnimationUtils.loadAnimation(context, animResId) startAnimation(targetAnim) removeOnAttachStateChangeListener(this) } override fun onViewDetachedFromWindow(v: View) = Unit })
2. XML使用规范
首先必须在布局根节点外层包裹<layout>标签,开启DataBinding能力,仅支持两种合法写法:
- 资源引用写法:
app:CustomAnimationtoLoad="@{@anim/slide_top_to_bottom}" - 资源ID写法:
app:CustomAnimationtoLoad="@{R.anim.slide_top_to_bottom}"
如果需要支持不带@{}的普通XML属性写法,需要额外在res/values/attrs.xml中定义自定义属性,并且在自定义View的构造方法中解析属性、加载动画,不属于BindingAdapter的支持范围。
内容的提问来源于stack exchange,提问作者Taimoor Khan
相关产品推荐
相关产品推荐

