Android心率曲线平移动画自定义控件实现详解,并附上GitHub完整实现仓库资源。
项目上需要实现一个心率曲线波动的自定义动画,网上找了很多开源控件,没有想要的效果,综合网上已有的实现,改造实现了一个比较简单的心率波动动画,每个点之间用贝塞尔曲线连接,从左到右逐个绘制,满屏之后开始平移心率波动动画,以下是实现效果截图,GitHub上有实现效果GIF。
一、实现原理详解
1. 心率曲线的绘制
如果是绘制折线,只需要把数据点使用Path对象lineTo方法把所有数据点连接绘制即可,绘制曲线则使用cubicTo方法绘制贝塞尔曲线,让曲线连接点更平滑。每次绘制前重置Path对象,所有数据点连接完毕之后即可刷新绘制。
private void generateNewPath(float offset) { mPath.reset(); for (int i = 0; i < mSourceData.size(); i++) { // x,y表示当前点 x4,y4表示下一个点 x2,x3都是属于中间的点 x = mMarginLeft + mHearRateItemMargin * i - offset; y = getHearRateValueToViewHeight(mSourceData.get(i)); if (i == mSourceData.size() - 1) { x4 = x; y4 = y; } else { x4 = mMarginLeft + mHearRateItemMargin * (i + 1) - offset; y4 = getHearRateValueToViewHeight(mSourceData.get(i + 1)); } x2 = x3 = (x + x4) / 2; y2 = y; y3 = y4; if (i == 0) { mPath.moveTo(x, y); mPath.lineTo(x, y); } if (i != mSourceData.size() - 1) { mPath.cubicTo(x2, y2, x3, y3, x4, y4); } } }
2. 平移动画实现
在曲线还没超过绘制控件宽度的时候,逐个绘制数据点连线,当数据点超过控件宽度的时候,才进行从右往左的X轴平移动画。这边平移的动画使用属性动画的刷新,来更新曲线每个数据点的X轴坐标来实现。
这边需要注意的是:属性函数回调参数的类型不能写成Float,而是float,否则会导致setShiftXRatio没执行,放置自定义控件的地方也要加防混淆处理,混淆之后会导致找不到回调函数。
ObjectAnimator.ofFloat(this, "shiftXRatio", 0f, 1f);
/** * setShiftXRatio * * @param shiftRatio float */ public void setShiftXRatio(float shiftRatio) { invalidatePath(mHearRateItemMargin * shiftRatio); }
同时设置属性动画为无限循环,如果是配置属性动画只执行一次,每新增一个数据点再启动属性动画,会有大概一秒的延迟,导致实现的动画效果不平滑,会有明显的顿挫。
setRepeatCount(ValueAnimator.INFINITE)
在属性动画的执行监听中,用onAnimationRepeat接口来触发下一个数据点的平移动画执行,设置属性动画为无限循环之后,监听onAnimationRepeat接口而不是onAnimationEnd接口。
private Animator.AnimatorListener mAnimListener = new Animator.AnimatorListener() { @Override public void onAnimationStart(@NonNull Animator animator) { } @Override public void onAnimationEnd(@NonNull Animator animator) { } @Override public void onAnimationCancel(@NonNull Animator animator) { } @Override public void onAnimationRepeat(@NonNull Animator animator) { startNextAnim(); } };
3. 渲染问题导致绘制异常
在MUMU虚拟机上运行动画,测试了几分钟之后绘制不出来画面,报以下异常信息:
E/EGL_emulation: tid 1442: eglSurfaceAttrib(1101): error 0x3009 (EGL_BAD_MATCH) W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x7f51eb168a40, error=EGL_BAD_MATCH W/OpenGLRenderer: Path too large to be rendered into a texture W/OpenGLRenderer: Shape too large to be rendered into a texture (16391x514, max=16384x16384)
在布局控件中配置software属性解决。
android:layerType="software"
二、GitHub仓库链接地址
https://github.com/wenguan0927/HeartRateAnimView
三、其他心率动画开源资源参考
Snake View 也是心率动画,只是动画是蛇形变化。
LuckyEcgDemo 心电图表格自定义控件实现,正式的医院心电图效果。
扩展阅读:
转载请注明出处:陈文管的博客 – Android 心率动画自定义控件实现
扫码或搜索:文呓
微信公众号 扫一扫关注