前言:
好像是从简书看到一个IOS的双曲线波浪的动画,刚好最近把Cavans重新复习了一遍,那么就用这个来巩固好了,而且这个效果确实挺好玩的。如果大家对android中的三次贝塞尔曲线不太理解,对API也不太熟的,可以去这个博客看看[置顶] Android自定义控件三部曲文章索引,这是我读过总结的最详细的博文,很适合摸索阶段和温习阶段去阅读,这里感谢启舰大神,非常细致的博文。
上图:
颜色搭配有点丑,wave的波长也不是很完美,大家将就着看下就是了,看是来看代码好了。
代码通杀一切:
DoubleWaveView
package cjh.doublewave;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
/**
* Created by chenjiahuan on 16/7/1.
*/
public class DoubleWaveView extends View {
private Paint mPaint;
private Path mPath;
private int width, height;
private int dx;
public DoubleWaveView(Context context, int width, int height) {
super(context);
this.width = width;
this.height = height;
init();
}
public DoubleWaveView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DoubleWaveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init() {
mPath = new Path();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
mPaint.setColor(Color.parseColor("#65ff0000"));
mPath.moveTo(-width + dx, height / 5 * 4);
for (int i = 0; i < 3; i++) {
mPath.rQuadTo(width / 4, -70, width / 2, 0);
mPath.rQuadTo(width / 4, 70, width / 2, 0);
}
mPath.lineTo(width, height);
mPath.lineTo(0, height);
mPath.close();
canvas.drawPath(mPath, mPaint);
mPath.reset();
mPaint.setColor(Color.parseColor("#6500ff00"));
mPath.moveTo(-width + dx, height / 5 * 4);
for (int i = 0; i < 3; i++) {
mPath.rQuadTo(width / 4, 70, width / 2, 0);
mPath.rQuadTo(width / 4, -70, width / 2, 0);
}
mPath.lineTo(width, height);
mPath.lineTo(0, height);
mPath.close();
canvas.drawPath(mPath, mPaint);
}
public void startAnimation() {
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, width);
valueAnimator.setDuration(2000);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
dx = (int) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
}
}
先看onDraw部分,其实只需要看其中一个wave的代码就OK了:
mPath.reset();
mPaint.setColor(Color.parseColor("#65ff0000"));
mPath.moveTo(-width + dx, height / 5 * 4);
for (int i = 0; i < 3; i++) {
mPath.rQuadTo(width / 4, -70, width / 2, 0);
mPath.rQuadTo(width / 4, 70, width / 2, 0);
}
mPath.lineTo(width, height);
mPath.lineTo(0, height);
mPath.close();
canvas.drawPath(mPath, mPaint);
既然是画一条占满屏幕宽度的wave,肯定是使用rQuadTo这个API了,和quadTo的API绝对位置不同的是rQuadTo的参数都是相对位置的值,这个两个API我想还是稍微说下好了,看图:
OK,说完了,有点粗糙和暴力,不过应该能看懂就是了,如果还是不懂,可以看开头介绍的那篇博客。
代码中mPath.moveTo(-width + dx, height / 5 * 4);
这一行x轴的起始点不是固定的,dx是跟着属性动画走的,如果不清楚属性动画可以看我的文章Android动画-Property Animation(一),在博文的最后稍微介绍了抛物线的动画,其实就是使用的拦截器,一个道理。
我整个wave的波长其实就是屏幕的宽度,所以我在画wave的时候小小的偷了个懒,因为我知道我想画的wave其实就是屏幕的三倍长,所以循环了三次,如果是不知道自己到底的wave的最终具体波长的可以这么写:
if(int i = -wavewidth; i<= screenwidth + wavewidth; i+=wavewidth ){
}
这里循环的意思,其实就是我从屏幕左侧一个波长的点开始,每次增长一个wave的长度,最后想要到达屏幕右侧一个波长的点。
OK,属性动画这里就不需要多讲了吧,很简单的一个值得变化,另外注意下,在MainActivity中,动态添加的时候需要,设置LayoutParams
private void initWaveView() {
rootView = (FrameLayout) findViewById(R.id.rootView);
waveView = new DoubleWaveView(this, width, height);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
rootView.addView(waveView, params);
waveView.startAnimation();
}
这样一个很简单的双曲线动画就OK了,当然了我看到的双曲线动画,比这个要精致很多,那是下一篇博客的内容了。