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

如何结合缩放动画改变View的z坐标实现阴影插值效果?

实现缩放+阴影同步插值的按钮悬停效果

当然可以实现,你需要用属性动画替代当前的补间动画——旧补间动画只修改View的绘制状态,没法联动elevation(对应你说的z坐标)的插值变化,而属性动画能直接修改View的真实属性,支持多属性同步动画,自动完成过渡插值。

下面给两种实现方案:

方案1:XML属性动画实现

  1. 首先创建属性动画文件(注意放在res/animator目录下,不是anim目录):res/animator/anim_hover.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator">

    <!-- 缩放X/Y轴动画 -->
    <objectAnimator
        android:duration="80"
        android:propertyName="scaleX"
        android:valueFrom="1.0"
        android:valueTo="1.031"
        android:valueType="floatType"/>

    <objectAnimator
        android:duration="80"
        android:propertyName="scaleY"
        android:valueFrom="1.0"
        android:valueTo="1.031"
        android:valueType="floatType"/>

    <!-- Elevation(z坐标)动画,根据需求调整起始/结束值 -->
    <objectAnimator
        android:duration="80"
        android:propertyName="elevation"
        android:valueFrom="@dimen/default_btn_elevation"
        android:valueTo="@dimen/hover_btn_elevation"
        android:valueType="floatType"/>
</set>
  1. 在res/values/dimens.xml中定义阴影的尺寸值:
<dimen name="default_btn_elevation">4dp</dimen>
<dimen name="hover_btn_elevation">8dp</dimen>
  1. 给按钮添加触摸监听,触发/反向动画:
button.setOnTouchListener { v, event ->
    when(event.action) {
        MotionEvent.ACTION_DOWN -> {
            val animator = AnimatorInflater.loadAnimator(context, R.animator.anim_hover)
            animator.target = v
            animator.start()
        }
        MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
            val animator = AnimatorInflater.loadAnimator(context, R.animator.anim_hover)
            animator.target = v
            animator.reverse()
        }
    }
    true
}

方案2:代码动态创建属性动画

如果不想写XML,也可以直接在代码中组合动画:

button.setOnTouchListener { v, event ->
    when(event.action) {
        MotionEvent.ACTION_DOWN -> {
            // 缩放动画
            val scaleXAnim = ObjectAnimator.ofFloat(v, "scaleX", 1f, 1.031f)
            val scaleYAnim = ObjectAnimator.ofFloat(v, "scaleY", 1f, 1.031f)
            // 阴影动画
            val elevationAnim = ObjectAnimator.ofFloat(v, "elevation",
                resources.getDimension(R.dimen.default_btn_elevation),
                resources.getDimension(R.dimen.hover_btn_elevation))
            
            // 组合动画并启动
            val animSet = AnimatorSet()
            animSet.interpolator = LinearInterpolator()
            animSet.duration = 80
            animSet.playTogether(scaleXAnim, scaleYAnim, elevationAnim)
            animSet.start()
        }
        MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
            // 反向恢复动画
            val scaleXAnim = ObjectAnimator.ofFloat(v, "scaleX", 1.031f, 1f)
            val scaleYAnim = ObjectAnimator.ofFloat(v, "scaleY", 1.031f, 1f)
            val elevationAnim = ObjectAnimator.ofFloat(v, "elevation",
                resources.getDimension(R.dimen.hover_btn_elevation),
                resources.getDimension(R.dimen.default_btn_elevation))
            
            val animSet = AnimatorSet()
            animSet.interpolator = LinearInterpolator()
            animSet.duration = 80
            animSet.playTogether(scaleXAnim, scaleYAnim, elevationAnim)
            animSet.start()
        }
    }
    true
}

注意事项

  • 属性动画会修改View的真实属性,比如缩放后点击区域会跟着变化(虽然你这个缩放比例很小,影响不大),比旧补间动画更规范。
  • elevation的值可以自行调整,数值越大阴影越明显,根据你的视觉需求来改。
  • 属性动画支持API11及以上,现在大部分项目的minSdk都满足这个要求。

内容的提问来源于stack exchange,提问作者slowcoder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:32:36