转载:https://blog.csdn.net/wangpeiming110/article/details/74638916
源码下载
前言:
之前在SurfaceView(一)中提到了SurfaceView的基础实现,然后现在在那个基础之上,开始使用SurfaceView来进行的动画的实现。
SurfaceView的画图部分
private volatile boolean isPause;
private boolean isFirst;
@Override
public void run() {
while (mIsDrawing) {
if (isPause) {
} else {
if (isFirst) {
animManager.updateStartTime();
isFirst=false;
}
animManager.draw();
}
}
}
public void setPause(boolean isPause) {
if(isPause)isFirst=true;
this.isPause = isPause;
}
由于避免重复,之前的那些初始化步骤省略了,详细的可以下面:
surfaceView(入门一):https://blog.csdn.net/qq_35014796/article/details/80783357
具体的动画实现逻辑:
百叶窗效果:
private Path path = new Path();
private float bailine = 5;//百叶窗的行数
private int sum;
private void AnimBaiYeChuang() {
path.reset();
for (int i = 0; i < bailine; i++) {
float top = height / bailine * i;//height:屏幕的高度 bailine: 百叶窗的行数
float bottom = top + height / bailine * rate;//rate 比率 0-1之间的值 float类型
path.addRect(0, top, width, bottom, Path.Direction.CW);//路径添加画的矩形
}
mCanvas.clipPath(path);//按路径进行裁剪
index=index%bitmaps.size();//图片的索引
Log.i(TAG, "AnimBaiYeChuang: "+sum++);//调用了45次
mCanvas.drawBitmap(bitmaps.get(index), null, rect, paint);//画布进行图片的画质
initAnim(1);
}
阶梯动画效果:
private int timeInterval = 200;//每一行阶梯与上一行起跑时间差
private int lineNum=4;//有多少个阶梯
private float timePerLine = animtime - (timeInterval * (lineNum - 1));//为了保证最后一个阶梯能够占满宽度,我们要得出第一个占满宽度的时间
public void AnimJieTi(){
path.reset();
/*
* 原本是 width-(rate*animtime)/animtime*width;这样子得出的是动画时间内left坐标的位置
* 但是这个样子并没有阶梯分层的效果,要有效果就要引入当前阶梯行数(i)和timeIntervald的关系
* 所以更改为 (rate * animtime - i * timeInterval)/animtime
* 然后上面因为添加i*timeInterva所以在原来的基础上也要改的
* 上面说了timePerLine,为第一个阶梯占满宽度的时间,所以更改为
* (rate * animtime - i * timeInterval) / timePerLine
*
* */
float left1 = width - (rate * animtime - 0 * timeInterval) / timePerLine * width;//
float top1 = height / lineNum * 0;
float right1 = width;
float bottom1 = top1 + height / lineNum;
path.addRect(left1, top1, right1, bottom1, Path.Direction.CW);
//计算每一行需要展示的左上右下
for (int i = 1; i < lineNum; i++) {
float left = width - (rate * animtime - i * timeInterval) / timePerLine * width;
Log.i(TAG, "AnimJieTi: left: "+left);
float top = height / lineNum * i;
float right = width;
float bottom = top + height / lineNum;
path.addRect(left, top, right, bottom, Path.Direction.CW);
}
mCanvas.clipPath(path);
index=index%bitmaps.size();
mCanvas.drawBitmap(bitmaps.get(index), null, rect, paint);
initAnim(2);
}
棋盘效果:
int rowNum = 9;//一行有多少个格子
int colNum = 6;//一列有多少个格子
public void AnimQiPan() {
path.reset();
//根据行数和列数计算每一个格子区域,最后剪切出棋盘区域
for (int i = 0; i < rowNum; i++) {
//单数行没有问题,双数行要从第一行-1行和第一行的第一个格子和第三个格子之间开始,除以2是为了配合第二行的第一个格子只占用原来的一半
float leftStart = i % 2 == 0 ? 0 : -(width / colNum) / 2;
for (int j = 0; j < colNum+1 ; j++) {//这里加1因为双数行有比原来多一个
float left = leftStart + j * width / colNum;
float top = height / rowNum * i;
float right = left + width / colNum * rate;
float bottom = top + height / rowNum;
path.addRect(left, top, right, bottom, Path.Direction.CW);
}
}
mCanvas.clipPath(path);
index=index%bitmaps.size();
mCanvas.drawBitmap(bitmaps.get(index), null, rect, paint);
initAnim(3);
}
随机线条效果:
int restNum;//剩余数量的,用于随机线条一开始是高度-1
Random random = new Random();//用于随机线条和溶解
int[] lines;//这个是高的值
public void AnimSuiJiXian() {
path.reset();
//计算这一次需要取得的线条数量
int needNum = (int) ((height - 1) * rate - (height - 1 - restNum));
//循环随机获取线条数组中的线条
//新加的
for (int i = 0; i < needNum; i++) {
//获取到一条随机线条,添加进path中
int r = random.nextInt(restNum - i);
path.addRect(0, lines[r], width, lines[r] + 1, Path.Direction.CW);
//保证之后再r中渠道的线段不是已经用过的
int temp = lines[r];
lines[r] = lines[restNum - i - 1];
lines[restNum - 1 - i] = temp;
}
//以前的
//遍历数组中“之前已取”的线条,全部放在path中
for (int i = 0; i < (height - 1) - restNum; i++) {
path.addRect(0, lines[(int) (height - 2 - i)], width, lines[(int) (height - 2 - i)] + 1, Path.Direction.CW);
}
//剩余线条数量
restNum = restNum - needNum;
mCanvas.clipPath(path);
index=index%bitmaps.size();
mCanvas.drawBitmap(bitmaps.get(index), null, rect, paint);
initAnim(0);
}