fromXDelta 和 toXDelta 是以父容器 content area 左上角为原点的绝对像素偏移量,非相对自身位置;单位默认 px,支持 dp,不支持 %;负值合法;fillAfter 仅保留视觉效果,不改变实际布局位置;真位移需用属性动画(如 ObjectAnimator 或 ViewPropertyAnimator)。

translate 动画的 fromXDelta 和 toXDelta 是相对父容器左上角的像素偏移
Android XML 位移动画里,fromXDelta 和 toXDelta 不是相对于自身位置,而是以父容器左上角为原点计算的绝对像素偏移量。比如设 fromXDelta="100",控件会从「父容器左边界向右 100px」的位置开始动画,而不是“向右平移 100px”。
- 单位默认是
px;支持dp(如fromXDelta="100dp"),但不支持%或%p(那些只在ScaleAnimation或RotateAnimation中有效) - 负值合法:比如
toXDelta="-50"表示终点在父容器左边界左侧 50px 处(可能完全移出屏幕) - 如果父容器有 padding,位移起点仍以父容器 content area 左上角为准,不受 padding 影响
XML 中用 android:fillAfter="true" 无法真正保留最终位置
很多人以为加了 android:fillAfter="true" 就能让 View 停在动画终点,结果点击区域、布局测量还是回到原始位置——这是 View 动画(Animation)固有限制:它只改绘制坐标,不改 LayoutParams 或实际 bound。
- 真实生效的只有视觉效果,View 的
getLeft()/getTop()、触摸响应、RecyclerView 滚动定位等全按原始位置算 - 要真正移动并固定位置,必须用属性动画:
ObjectAnimator.ofFloat(view, "translationX", 0f, 200f) - XML 动画 +
fillAfter仅适合纯视觉过渡(比如弹窗入场),别用于需要交互或后续 layout 依赖的场景
translate 在 AnimationSet 中叠加时,delta 值是直接相加而非覆盖
多个 translate 动画套在同一个 AnimationSet 里,它们的 fromXDelta/toXDelta 会线性叠加执行,不是“后一个覆盖前一个”。比如一个动画从 0→100,另一个从 0→-30,同时运行时,实际 X 方向位移是两者的和。
- 典型误用:想让 View 先右移再左移,却写成两个并行 translate —— 结果是净位移 70px,不是回到原点
- 正确做法:用
startOffset错开时间,或拆成两个独立Animation分别 setStartOffset - 注意:
AnimationSet的android:interpolator会影响所有子动画,但每个子动画也可单独设 interpolator,后者优先级更高
API 21+ 推荐用 ViewPropertyAnimator 替代 XML translate 动画
XML 的 translate 属于旧式 View Animation,API 21(Lollipop)起,系统对属性动画做了底层优化,ViewPropertyAnimator 直接操作 translationX/translationY,既保留最终位置,又避免重绘整层 ViewGroup。
- 简单替代写法:
view.animate().translationX(200f).setDuration(300),无需 XML 文件,也不依赖 Animation 对象生命周期 - 兼容性:用
ViewCompat.animate()可向下兼容到 API 14 - 关键区别:XML translate 改的是 Canvas 绘制矩阵;
translationX是 View 的属性,参与 layout 测量(虽然不触发 requestLayout,但影响getHitRect等行为)
坐标系统本身没变,但“谁在动”和“动完算不算数”,才是决定你该用哪套方案的核心。别被 XML 里看着顺眼的 toXDelta 带偏了方向。










