- 示例工程
【免费下载链接】views-widgets-samples
Multiple samples showing the best practices in views-widgets on Android.
Interpolator Playground 是 views-widgets-samples 仓库中专门用于演示 Android 平台各类Interpolator(插值器/时间函数)实现差异的示例应用。本文以其官方文档(AnimationsInterpolatorPlayground/README.md)为骨架,结合该模块四个 Java 源文件与布局资源,完整讲解从下拉选择、滑杆调参、拖拽贝塞尔控制点到运行动画的完整链路,并剖析曲线绘制与动画驱动的底层实现,帮助开发者把"看得见"的参数直接翻译成自己的动画代码。
一、示例定位:让插值器从"黑盒"变成"可见曲线"
在 Android 动画体系里,Interpolator负责把动画时间进度(0→1 的归一化时间)映射为实际的值进度(同样是 0→1 的归一化值)。平台内置了多种插值器,每种插值器的"时间—进度"曲线形状不同,动画的加速、减速、回弹、过冲等观感也截然不同。
正如官方文档所述,该应用的核心目的是:
This application shows how the various Interpolator implementations in the platform work.
它允许开发者调整动画时长以及任意可变插值器的构造参数,并直接在界面上观察效果,从而在编写自己的代码前就能确定应该使用哪个插值器、传入什么参数。README 明确给出了核心交互流程:
- 从顶部下拉列表选择任意内置插值器;
- 通过滑杆调整动画时长和/或当前插值器的可变参数;
- 对于 Quadratic(二次)和 Cubic(三次)Path 插值器,直接拖拽绿色手柄调整曲线控制点;
- 点击Run按钮观看动画实际运行效果;
- 记下时长与其他参数值,用于你自己的动画代码。
应用的主入口是 MainActivity.java,它把CurveVisualizer(曲线可视化视图)和TimingVisualizer(动画演示视图)组合在一起,构成完整的"曲线预览 + 参数调节 + 实机演示"闭环。
二、界面骨架:一个 Activity 装下完整实验台
应用的布局定义在 activity_main.xml,整体是一个纵向LinearLayout,从上到下依次是:
| 区域 | 视图 | 作用 |
|---|---|---|
| 选择与运行区 | Spinner(id:spinner)+Button(id:runButton,文本 "Run") | 下拉选择插值器、触发动画运行 |
| 时长调节区 | TextView(durationLabel)+SeekBar(durationSeeker) | 显示并调节动画时长,SeekBar范围max="2000"(毫秒),初始progress="300" |
| 参数动态区 | LinearLayout(id:linearLayout,初始为空) | 运行时动态填充参数化插值器的滑杆 UI |
| 曲线画布区 | LinearLayout(id:linearLayout2,高度 200dp) | 容纳CurveVisualizer自定义视图,绘制 1×1 网格、蓝色曲线与红色小球 |
| 演示动画区 | TimingVisualizer(id:timingVisualizer,layout_weight="1") | 两个红色小球分别向右、向下滑动,直观展示插值效果 |
AndroidManifest.xml(AnimationsInterpolatorPlayground/app/src/main/AndroidManifest.xml)将MainActivity声明为 launcher 入口,应用包名com.example.android.interpolatorplayground。模块构建配置见 app/build.gradle:minSdkVersion 21、targetSdkVersion 29,依赖androidx.appcompat:appcompat:1.1.0,说明其依赖android.view.animation包下平台内置的插值器实现(PathInterpolator 自 API 21 起可用,正好与 minSdk 对齐)。
三、九种内置插值器清单:从线性到回弹
可供选择的插值器定义在 strings.xml 的interpolators字符串数组中,共 9 项:
<string-array name="interpolators"> <item>Linear</item> <item>Accelerate</item> <item>AccelerateDecelerate</item> <item>Decelerate</item> <item>Quadratic Path</item> <item>Cubic Path</item> <item>Bounce</item> <item>Overshoot</item> <item>Anticipate</item> </string-array>对应到MainActivity.populateParametersUI()中的switch分支,各类插值器的行为特征与初始化方式如下:
- Linear(线性):全程匀速,
new LinearInterpolator(); - Accelerate(加速):从慢到快,
new AccelerateInterpolator(factor),factor 为可变参数; - AccelerateDecelerate(先加速后减速):对称的 S 型曲线,无参构造;
- Decelerate(减速):从快到慢,
new DecelerateInterpolator(factor); - Bounce(弹跳):落地后反复回弹,无参构造;
- Overshoot(过冲):冲过终点再回弹,
new OvershootInterpolator(tension); - Anticipate(蓄势):先反向退一段再正向推进,
new AnticipateInterpolator(tension); - Quadratic Path / Cubic Path:基于
PathInterpolator的贝塞尔曲线插值器,控制点可拖拽(详见第五节)。
其中Accelerate、Decelerate、Overshoot、Anticipate四个属于"参数化插值器",它们都有一个接受float构造参数的重载,这也是下方参数滑杆动态生成的依据。
四、参数化插值器的动态调参:反射构造 + 滑杆映射
对于需要构造参数的插值器,populateParametersUI()通过反射拿到对应的float构造器,再调用createParamaterizedInterpolator()动态生成一行"参数名 + SeekBar"的 UI:
Constructor<AccelerateInterpolator> decelConstructor = AccelerateInterpolator.class.getConstructor(float.class); createParamaterizedInterpolator(parent, decelConstructor, "Factor", 1, 5, 1);四个参数化插值器在代码中的取值范围与默认值如下表:
| 插值器 | 参数名 | min | max | 默认值 |
|---|---|---|---|---|
| Accelerate | Factor | 1 | 5 | 1 |
| Decelerate | Factor | 1 | 5 | 1 |
| Overshoot | Tension | 1 | 5 | 1 |
| Anticipate | Tension | 1 | 5 | 1 |
createParamaterizedInterpolator()的实现值得注意:SeekBar的max固定为 100,进度值i首先被归一化为百分比,再线性映射到[min, max]区间:
float percentage = (float) i / 100; float value = min + percentage * (max - min); mVisualizer.setInterpolator((Interpolator) constructor.newInstance(value));也就是说,滑杆拖动时会实时new出对应参数的新插值器实例并交给CurveVisualizer,曲线随之重绘,同时标签上的参数值以两位小数刷新(String.format(" %.2f", value))。这种"反射取构造器 + 滑杆百分比映射"的做法,让新增一个参数化插值器只需在switch中补一行代码,是理解该示例如何做到"动态调参"的关键。
五、PathInterpolator:拖拽绿色控制点定制贝塞尔曲线
Quadratic Path与Cubic Path是全部 9 个选项中交互最复杂的部分,它们底层对应android.view.animation.PathInterpolator:
- 二次曲线:
new PathInterpolator(cx1, cy1),只有一个控制点,代码默认controlX = 0.5f, controlY = 0.2f; - 三次曲线:
new PathInterpolator(cx1, cy1, cx2, cy2),两个控制点,默认值(0.5, 0.2)与(0.9, 0.7)。
在 CurveVisualizer.java 中,控制点不仅会被绘制成绿色圆点(RADIUS * 1.4f),还通过重写onTouchEvent()支持拖拽。触摸坐标经过缩放与翻转转换到 1×1 的归一化坐标系后,与现有控制点距离小于 0.05 即视为命中,随后在ACTION_MOVE中实时更新坐标并调用setupPathInterpolator()重建PathInterpolator:
if (mQuadraticPath) { mInterpolator = new PathInterpolator(mCx1, mCy1); } else if (mCubicPath) { mInterpolator = new PathInterpolator(mCx1, mCy1, mCx2, mCy2); }控制点位置变化通过 ControlPointCallback.java 中定义的onControlPoint1Moved(float cx1, float cy1)与onControlPoint2Moved(float cx2, float cy2)两个抽象方法回传给MainActivity,实时更新 "ControlX1/ControlY1/ControlX2/ControlY2" 的数值标签——这正是 README 中"拖拽绿色手柄来定位曲线控制点"这一操作的完整实现链路。
更贴心的是,三次曲线模式还内置了三个 Material Design 标准动效预设按钮(createMaterialMotionButton()):"L out S in"((0, 0, 0.2, 1))、"F out S in"((0.4, 0, 0.2, 1))、"F out L in"((0.4, 0, 1, 1)),分别对应 linear-out-slow-in、fast-out-slow-in、fast-out-linear-in 三组官方推荐的控制点坐标。点击按钮时,代码会用一段 100ms 的ValueAnimator对四个控制点坐标做线性插值过渡(oldCx1 + t * (cx1 - oldCx1)),让曲线平滑"飞"到预设形状,这本身又是一次"用动画演示动画参数"的巧妙自指。
六、Run 按钮背后的动画驱动:ObjectAnimator + setFraction 回调
点击 Run 后,MainActivity.runAnimation()只做了三件事:
mAnimator.cancel(); mAnimator.setInterpolator(mVisualizer.getInterpolator()); mAnimator.setDuration(mDuration); mAnimator.start();mAnimator在onCreate中创建为ObjectAnimator.ofFloat(this, "fraction", 0, 1),即对 Activity 自身的fraction属性做 0→1 的浮点动画。setFraction(float fraction)是动画驱动的枢纽,它把当前进度同时分发给两个可视化视图:
public void setFraction(float fraction) { mTimingVisualizer.setFraction(fraction); mVisualizer.setFraction(fraction); }这正好解释了 README 中"运行动画时会看到曲线上的红圈以及底部开放区域的动画":mAnimator.cancel()确保连续点击时旧动画先被取消,避免叠加;setInterpolator()在每次运行时才注入当前曲线对应的插值器实例,保证"所见即所得"。
七、两条绘制链路:曲线画布与演示动画区
7.1 CurveVisualizer:把插值函数画成可见曲线
CurveVisualizer的onDraw()是整个示例最有"技术含量"的部分,它把 1×1 的归一化坐标系映射到控件像素:
- 网格:按 10% 步进绘制横竖灰线,构成 11×11 的参考网格;
- 蓝色曲线:从
x = 0到x = 1以 0.01 步进采样mInterpolator.getInterpolation(x),逐段drawLine连接成蓝色曲线(mCurvePaint颜色Color.BLUE,线宽 5f)。这条曲线就是插值器时间函数的可视化本体; - 控制点:PathInterpolator 模式下绘制绿色圆点;
- 红色小球:根据当前动画进度
mFraction,以getInterpolation(mFraction)作为纵坐标、mFraction作为横坐标绘制红色圆球(RADIUS = 30),小球沿曲线滑行即代表动画当前的值进度。
此外,绘制前会执行canvas.translate+canvas.scale(SCALE_FACTOR, SCALE_FACTOR)(SCALE_FACTOR = 0.75f),目的是留出 12.5% 的边距,让 Bounce、Overshoot 这类"越界"曲线(值超出 [0,1] 区间)也能完整显示在画布内。
7.2 TimingVisualizer:真实运动预览
TimingVisualizer.java 负责演示"动画对象在实际运动中的表现":onDraw()中绘制两个红色小球,一个从顶部垂直向下移动(mBallTop + mFraction * mBallHeight),另一个从左向右水平移动(mBallLeft + mFraction * mBallWidth)。同样的mFraction经由当前插值器映射后,小球便呈现出加速、回弹、过冲等真实运动姿态——这是阅读 README 时理解"运行动画显示动画实际效果"的最直观落点。
八、把调好的参数翻译成你自己的动画代码
README 强调"注意时长和其他参数值,以便在你的动画代码中使用"。依据本文对源码的分析,可以从示例中直接提取三种典型写法:
1. 使用平台内置插值器:
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 0f, 200f); animator.setDuration(600); // 来自 Duration 滑杆 animator.setInterpolator(new OvershootInterpolator(1.5f)); // Tension 取滑杆值 animator.start();2. 在 XML 中声明 PathInterpolator(控制点坐标取自拖拽结果):
<animator> <objectAnimator android:duration="600" android:propertyName="translationX" android:valueFrom="0" android:valueTo="200"> <pathInterpolator android:controlX1="0.4" android:controlY1="0" android:controlX2="0.2" android:controlY2="1"/> </objectAnimator> </animator>3. 代码构造 PathInterpolator:
Interpolator interpolator = new PathInterpolator(0.4f, 0f, 0.2f, 1f); // fast-out-slow-in animator.setInterpolator(interpolator);Material Design 动效速查:(0, 0, 0.2, 1)为 linear-out-slow-in,(0.4, 0, 0.2, 1)为 fast-out-slow-in,(0.4, 0, 1, 1)为 fast-out-linear-in,这三组坐标即来自示例内置的预设按钮。
九、如何构建与运行
该模块是独立的 Android Studio 工程,根目录见 AnimationsInterpolatorPlayground/。使用仓库自带的 Gradle Wrapper(版本为 Gradle 6.7.1,见 gradle-wrapper.properties,AGP 4.2.1)即可构建:
# 进入示例目录后 ./gradlew assembleDebug或用 Android Studio 直接打开AnimationsInterpolatorPlayground目录运行到模拟器/真机(minSdk 21)。应用只有一个 Activity,无需额外权限;运行后依次尝试"切换插值器 → 拖时长滑杆 → 拖参数滑杆 → 拖贝塞尔控制点 → 点 Run",即可完整复现 README 描述的全部交互。
总结
Interpolator Playground 虽然只有四个 Java 文件,却完整覆盖了 Android 插值器从"平台 API 认知"到"参数手感调校"再到"代码落地"的全流程:strings.xml定义候选清单,MainActivity负责选择与参数装配,CurveVisualizer把插值函数实时绘制为曲线并支持控制点拖拽,TimingVisualizer提供真实的运动预览,ObjectAnimator + setFraction则把三者串成一次可运行的动画实验。理解这条链路之后,你在自己项目中挑选插值器、定夺 duration 与构造参数时,就能把这篇示例的交互经验直接转化为生产代码。
- 示例工程
【免费下载链接】views-widgets-samples
Multiple samples showing the best practices in views-widgets on Android.
相关推荐
Mac Mouse Fix 鼠标增强完整指南:15分钟给普通鼠标加上平滑滚动、按钮自定义和触控板手势
Mac Mouse Fix 鼠标增强完整指南:15分钟给普通鼠标加上平滑滚动、按钮自定义和触控板手势 Mac Mouse Fix 是一款 macOS 鼠标增强应
桌面应用系统编程终极指南:如何用ESRGAN网络插值实现惊艳的超分辨率效果可视化
终极指南:如何用ESRGAN网络插值实现惊艳的超分辨率效果可视化 ESRGAN(Enhanced Super Resolution Generative Adv
人工智能深度学习计算机视觉图像处理MoviePy 轨迹插值工具详解:Interpolator 与 Trajectory 的使用与源码剖析
MoviePy 轨迹插值工具详解:Interpolator 与 Trajectory 的使用与源码剖析 导读 本篇技术指南聚焦 MoviePy 视频编辑库中负责
音视频视频处理音频处理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考