本文主讲一种动画的实现方式:在自定义View的onDraw()方法的最后调用invalidate()来实现持续绘制更新画面,在onDraw()中根据流逝的时间来计算图像当前的位置、形状,即实现了动画。详见下文

优势:更可控,动画播放速度、方向等等可自由控制、随时变更;可以通过监听触摸事件来实现可触摸交互的动画。(本文以匀速运动为例,如需变速、响应触摸需要自行修改代码)

完整代码见最后

波浪效果图.gif

上图是一个循环的周期性动画,通过如下方式便实现了循环,onDraw方法会被不停地反复调用

@Override

protected void onDraw(Canvas canvas) {

//TODO 根据时间的流逝绘制图像

invalidate();

}

接着是绘制,最终效果图中是两道波浪,先以一道波浪为例

概览

矩形表示view的边框,让波浪持续往右移动,在View的边框内就会形成波浪动画

关键是当每一次onDraw被调用的时候,需要根据当前的时间计算出波浪的位置。如下为匀速运动的计算方法

动画进度 = ( (当前时间 - 起点时间) % 周期时长 )/ 周期时长

% 为java取模运算符

这里用到AnimationUtils.currentAnimationTimeMillis()来获取系统开机后至今的毫秒值。将其保存为静态变量作为起点时间,可以使App内所有的波浪动画的进度同步(因为都根据同一个起点时间、同一个周期长度来计算动画进度)

private static long startTime = AnimationUtils.currentAnimationTimeMillis();

在onDraw中再次调用AnimationUtils.currentAnimationTimeMillis()获得当前时间,即可在每次onDraw被调用时都计算出动画进度。再根据波浪图形的初始起点位置,计算出波浪的位置。

当前位置 = (终点位置 - 起点位置)* 动画进度

在代码中用path.offset()来实现偏移

以下为完整代码,需要注意,前文中是以背景层波浪为例的,即波浪向右移动。前景波浪是向左移动

public class WaveRelativeLayoutView extends RelativeLayout {

//前景波浪的周期时间

private static final float FOREGROUND_PERIODIC_TIME = 5000;

//背景波浪的周期时间

private static final float BACKGROUND_PERIODIC_TIME = 3000;

public WaveRelativeLayoutView(Context context) {

super(context);

init();

}

public WaveRelativeLayoutView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}

private static long startTime = AnimationUtils.currentAnimationTimeMillis();

private Path mForegroundWavePath = new Path();

private Path mBackgroundWavePath = new Path();

private Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

private Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

private void init() {

mForegroundPaint.setColor(Color.parseColor("#d8475b"));

mForegroundPaint.setStyle(Paint.Style.FILL_AND_STROKE);

mBackgroundPaint.setColor(Color.parseColor("#cb4053"));

mBackgroundPaint.setStyle(Paint.Style.FILL_AND_STROKE);

//ViewGroup 在没有背景时不会调用onDraw,所以需要手动设置一个background

if (getBackground() == null) {

setBackgroundColor(Color.TRANSPARENT);

}

}

@Override

protected void onDraw(Canvas canvas) {

float pasedTime = AnimationUtils.currentAnimationTimeMillis() - startTime;

//------前景层的波浪-------

mForegroundWavePath.reset();

int startY = 0;

//此处的waveLen实际为贝塞尔曲线中每一个控制点的间距,修改这个值可以改变波长,但不直接等于波长

float waveLen = getWidth() / 4f;

//此处的WaveHeight实际为贝塞尔曲线中每一个控制点的高度,修改这个值可以改变浪高,但不直接等于浪高

float foregroundWaveHeight = 30;

float backgroundWaveHeight = 40;

mForegroundWavePath.moveTo(-getWidth(), startY);

//初始时,View左侧不可见的波浪

mForegroundWavePath.quadTo(waveLen * -3f, foregroundWaveHeight,waveLen * -2, startY);

mForegroundWavePath.quadTo(waveLen * -1, -foregroundWaveHeight, 0,startY);

//初始时,View内可见波浪

mForegroundWavePath.quadTo(waveLen, foregroundWaveHeight, waveLen *2, startY);

mForegroundWavePath.quadTo(waveLen * 3, -foregroundWaveHeight,waveLen * 4, startY);

mForegroundWavePath.lineTo(getWidth(), getHeight());

mForegroundWavePath.lineTo(-getWidth(), getHeight());

mForegroundWavePath.close();

//根据流逝的时间、周期长短 来计算偏移量,得到‘当前位置’

float currTimeForeground = pasedTime % FOREGROUND_PERIODIC_TIME;

//注意:前景波浪是向左移动的

mForegroundWavePath.offset(getWidth() * (FOREGROUND_PERIODIC_TIME -currTimeForeground) /

FOREGROUND_PERIODIC_TIME, getHeight() / 2 + 10);

//------背景层波浪-------

mBackgroundWavePath.reset();

mBackgroundWavePath.moveTo(-getWidth(), startY);

//初始时,View左侧不可见的波浪

mBackgroundWavePath.quadTo(waveLen * -3f, backgroundWaveHeight,waveLen * -2, startY);

mBackgroundWavePath.quadTo(waveLen * -1, -backgroundWaveHeight, 0,startY);

//初始时,View内可见波浪

mBackgroundWavePath.quadTo(waveLen, backgroundWaveHeight, waveLen* 2, startY);

mBackgroundWavePath.quadTo(waveLen * 3, -backgroundWaveHeight,waveLen * 4, startY);

mBackgroundWavePath.lineTo(getWidth(), getHeight());

mBackgroundWavePath.lineTo(-getWidth(), getHeight());

mBackgroundWavePath.close();

float currTimeBackground = pasedTime % BACKGROUND_PERIODIC_TIME;

//根据流逝的时间、周期长短 来计算偏移量,得到‘当前位置’

mBackgroundWavePath.offset(getWidth() * currTimeBackground /BACKGROUND_PERIODIC_TIME,

getHeight() / 2 - 10);

canvas.drawPath(mBackgroundWavePath, mBackgroundPaint);

canvas.drawPath(mForegroundWavePath, mForegroundPaint);

invalidate();

}

}

android波浪动画简书,Android Path绘制贝塞尔曲线波浪动画相关推荐

  1. android波浪动画简书,Android贝塞尔曲线————波浪效果(大波浪)

    Hello大家好,很高兴又一次与大家见面,今天是农历丁酉鸡年(大年初四),现在跟大家拜年有点晚,算是拜晚年,祝大家晚年幸福. 这么快大伙都到了晚年了,Android贝塞尔曲线我也准备以一个大波浪来结束 ...

  2. android自动登录简书,Android开发之简单登录界面

    用户界面基础 Android系统的四大组件分别是活动(Activity).服务(Service).广播接收器(Broadcast Receiver).内容提供器(Content Provider). ...

  3. android 读写文件 简书,Android 中的文件操作

    Android 文件操作 概述 Android 中的文件操作主要涉及到两个部分,一个是内部存储的读写,一个是外部存储的读写两者的主要区别如下表: 内部存储 外部存储 始终可用 它并非始终可用,因为用户 ...

  4. android 开发环境简书,Android Studio 开发环境快速搭建

    目录 - 1.下载JDK.AS - 1.1 JDK下载 - 1.2 AS下载 - 1.3 百度云资源统一下载 - 2.安装JDK - 3.配置JDK及JAVA的环境 - 3.1 打开系统环境 - 3. ...

  5. android运行过程简书,Android系统的启动流程

    Android系统有哪些进程 在Linux系统启动时,会读取init.rc,里面配置了一些需要启动的进程.注意:SystemServer进程不在init.rc里,因为SystemServer进程是由z ...

  6. android 辅助服务 简书,Android AccessibilityService使用

    测试demo主要使用了Android 的无障碍辅助服务(AccessibilityService),主要注意是 1. 开启服务,绑定目标app的监听(demo中根据包命绑定了体积计算的app),需要在 ...

  7. android四大组件 简书,android四大组件

    android有四大组件,分别是Activity, Service(服务),Content Provider(内容提供者),BoadcastReceiver广播接收器. Activity 一个Acti ...

  8. android 存储方式简书,Android的多种数据存储方式

    1. 简介 作为一个完整的应用程序,数据存储操作是必不可少的.现在Android的离线缓存就是通过网络良好状态时将从服务器收到的数据保存到本地.Android系统中主要提供了3种方式进行数据存储,分别 ...

  9. android权限适配 简书,Android动态权限适配

    最近APP里面要添加动态权限,网上找了不少例子并经过一定的测试,基本流程有了一定的认识,需要注意的地方记录下来以备以后查阅. 一 各大手机厂商的适配 依据各大手机Rom的不同表现,可以分为三种不同的模 ...

最新文章

  1. 生物信息学是干啥的?
  2. 二元偏导数存在的条件_高等数学入门——高阶偏导数的概念和计算
  3. Set 的合集 并集 差集
  4. Docker入门系列之三:如何将dockerfile制作好的镜像发布到Docker hub上
  5. 在C++中用虚函数的作用是什么?为什么要用到虚函数
  6. python 状态模式_使用状态模式自由切换登录状态
  7. WP7游戏开发:TweeJump(cocos2d-xna)
  8. php取数组里面数组的值,PHP获取数组的键与值方法小结
  9. 盒子模型之内边距(HTML、CSS)
  10. Luogu3810 三维偏序(陌上花开)
  11. 将Ubuntu从Win7的魔爪中拯救出来
  12. 模2运算_模二除法和CRC循环冗余校验
  13. 情迁机器人Tim_情迁机器人插件-情迁机器人app下载V1.5.0安卓版-西西软件下载
  14. 什么是Web2.0(图解Web2.0)
  15. php计算排名,成绩相同需要并列算法
  16. STM32【H7】理论——综述、HAL库简述
  17. Pytorch-RuntimeError: size mismatch m1: [a x b], m2: [c x d]
  18. 【c++】2020大一下c++期中考前小练习1
  19. BNNVGG2-VGG Net
  20. Python第五周作业

热门文章

  1. 手游直播到底难在哪里?
  2. 降级重新安装低版本flash_player_active_x的方法
  3. 站在巨人的肩膀上,用Node+ChatGPT模块实现一个接口
  4. 采访优秀学长学姐后的感悟与体会
  5. Virtual Reality 那些事
  6. Briefings in bioinformatics2022 | 基于神经网络的分子性质预测通用优化策略
  7. 查询服务器硬盘上电时间,鲁大师检测硬盘通电时间怎么操作?检测硬盘通电时间教程...
  8. 构筑基于物联网操作系统的物联网生态环境
  9. 滑块逃脱_逃脱测试的丛林:从夹具到断言的捷径
  10. 利用Excel批量修改图片名称