概述
1、写这个demo主要是因为一个同事给我看了一个ios的效果,因为感觉好玩所以我就写了android样式的,具体的效果就如下图展示(图是ios的gif不过效果是一样的),有需要的朋友在下面会给出下载地址
首先分析一下我的做法,我是将波浪的部分和头像分开考虑,根据波浪的移动高度将头像画出
一、定义属性
其实我在做的时候我是直接开始画,画完了才去优化自定义属性,然而现在这些过程已经不重要了,我就先介绍下定义的属性分别都是什么含义。
android:id="@+id/cv_waves"
android:layout_width="match_parent"
android:layout_marginTop="100dp"
app:imgSize="50dp"
app:waveHeight="20dp"
app:rollTime="20"
app:rollDistance="5"
android:layout_height="70dp" />
app:imgSize=”50dp”定义的是头像的大小
app:waveHeight=”20dp”波浪的高度
app:rollTime=”20”移动一次的时间
app:rollDistance=”5”移动一次的距离,像素
二、开始画CorrugateView这个控件
(1)获取所有属性的值和初始化所需要的画笔
public void init(Context context, AttributeSet attrs) {
TypedArray attr = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CorrugateView, 0, 0);
try {
imgSize = (int) attr.getDimension(R.styleable.CorrugateView_imgSize, getResources().getDimensionPixelSize(
R.dimen.top_distance));
waveHeight = (int) attr.getDimension(R.styleable.CorrugateView_waveHeight, getResources().getDimensionPixelSize(
R.dimen.top_distance_20));
rollTime = attr.getInteger(R.styleable.CorrugateView_rollTime, 30);
rollDistance = attr.getInteger(R.styleable.CorrugateView_rollDistance, 5);
} finally {
attr.recycle();
}
length = rollDistance;
//保存上面一条曲线的数组
mPointsList = new ArrayList();
//保存下面一条曲线的数组
mPointsListBottom = new ArrayList();
//画上面曲线的画笔和线
mWavePath = new Path();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(getResources().getColor(R.color.white));
//画下面曲线的画笔和线
mWavePathBottom = new Path();
mPaintBottom = new Paint();
mPaintBottom.setAntiAlias(true);
mPaintBottom.setStyle(Paint.Style.FILL);
mPaintBottom.setColor(getResources().getColor(R.color.top_withe));
}
(2)获取控件的宽高和初始化要画的波浪的每个点
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
//控件高度=图片的高度加上波浪的高度
mHeight = waveHeight + imgSize;
//初始化每个点
initPoint();
invalidate();
//开启一个计时器
if (timer == null)
start();
}
initPoint();这个方法就是画二阶贝塞尔曲线的每个点,具体看代码,因为有点长就不贴进来了
start();开启一个计时器,主要作用是在一定时间按一定的距离将曲线向右移动
(3)画曲线
@Override
protected void onDraw(Canvas canvas) {
//画两条曲线
mWavePath.reset();
mWavePathBottom.reset();
mWavePathBottom.moveTo(mPointsListBottom.get(0).x, mPointsListBottom.get(0).y);
mWavePathBottom.quadTo(mPointsListBottom.get(1).x, mPointsListBottom.get(1).y, mPointsListBottom.get(2).x, mPointsListBottom.get(2).y);
mWavePathBottom.quadTo(mPointsListBottom.get(3).x, mPointsListBottom.get(3).y, mPointsListBottom.get(4).x, mPointsListBottom.get(4).y);
mWavePathBottom.quadTo(mPointsListBottom.get(5).x, mPointsListBottom.get(5).y, mPointsListBottom.get(6).x, mPointsListBottom.get(6).y);
mWavePathBottom.quadTo(mPointsListBottom.get(7).x, mPointsListBottom.get(7).y, mPointsListBottom.get(8).x, mPointsListBottom.get(8).y);
mWavePathBottom.quadTo(mPointsListBottom.get(9).x, mPointsListBottom.get(9).y, mPointsListBottom.get(10).x, mPointsListBottom.get(10).y);
mWavePathBottom.lineTo(mPointsListBottom.get(10).x, mHeight);
mWavePathBottom.lineTo(mPointsListBottom.get(0).x, mHeight);
mWavePathBottom.lineTo(mPointsListBottom.get(0).x, mPointsListBottom.get(0).y);
mWavePathBottom.close();
canvas.drawPath(mWavePathBottom, mPaintBottom);
mWavePath.moveTo(mPointsList.get(0).x, mPointsList.get(0).y);
mWavePath.quadTo(mPointsList.get(1).x, mPointsList.get(1).y, mPointsList.get(2).x, mPointsList.get(2).y);
mWavePath.quadTo(mPointsList.get(3).x, mPointsList.get(3).y, mPointsList.get(4).x, mPointsList.get(4).y);
mWavePath.quadTo(mPointsList.get(5).x, mPointsList.get(5).y, mPointsList.get(6).x, mPointsList.get(6).y);
mWavePath.quadTo(mPointsList.get(7).x, mPointsList.get(7).y, mPointsList.get(8).x, mPointsList.get(8).y);
mWavePath.lineTo(mPointsList.get(8).x, mHeight);
mWavePath.lineTo(mPointsList.get(0).x, mHeight);
mWavePath.lineTo(mPointsList.get(0).x, mPointsList.get(0).y);
mWavePath.close();
canvas.drawPath(mWavePath, mPaint);
//画头像
Bitmap bitmap = BitmapFactory.decodeResource(this.getContext()
.getResources(), R.mipmap.icon_2017);
drawImage(canvas, bitmap, (mWidth - imgSize) / 2, (int) getHeigthIcon() - imgSize,
imgSize, imgSize, 0, 0, mPaint);
//当移动的长度大于等于屏幕宽度重置点的坐标
if (allLength >= mWidth) {
resetPoints();
allLength = 0;
}
}
getHeigthIcon()这个方法比较重要,控制着头像的上下移动,主要运用贝塞尔曲线的二阶公式计算头像的高度,下图所示
/** * 获取头像中心的x对应的曲线的y值 *@return */
private float getHeigthIcon() {
//移动的比率
float t = (float) allHeight * 2 / mWidth;
float y;
//ismHeight为true表示向下移动 false表示向上移动
if (ismHeight) {
//二价的贝塞尔曲线公式计算下面的曲线的根据t变化的高度
y = mPointsList.get(2).y * (1 - t) * (1 - t)
+ 2 * mPointsList.get(3).y * t * (1 - t)
+ mPointsList.get(4).y * t * t;
} else {
//二价的贝塞尔曲线公式计算上面的曲线的根据t变化的高度
y = mPointsList.get(0).y * (1 - t) * (1 - t)
+ 2 * mPointsList.get(1).y * t * (1 - t)
+ mPointsList.get(2).y * t * t;
}
return y;
}
drawImage(Canvas canvas, Bitmap blt, int x, int y, int w,int h, int bx, int by, Paint paint)画图片的方法,具体看代码,至此一个波浪的头像就算完成啦!感兴趣的下demo去看啦!
哦!差点忘了还有一个三阶的爱心,demo的LoveLayout.java这个文件哟!感兴趣的自己去看哟!
效果效果图,我又忘了!如下所示,里面使用了透明度的渐变,所以越高就越透明了,每个爱心的路径都是一条随机的三阶贝塞尔曲线,demo中只要点界面就会抛出一个爱心,自己去欣赏吧!
demo下载地址:https://github.com/972242736/BubblingDemo.git
最后
以上就是耍酷胡萝卜为你收集整理的android 爱心动画,Android之二阶贝塞尔曲线的波浪头像(三阶的爱心飞出)的全部内容,希望文章能够帮你解决android 爱心动画,Android之二阶贝塞尔曲线的波浪头像(三阶的爱心飞出)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复