您的位置:首页 > 移动开发 > Android开发

安卓 自己动手实现守望先锋动画

2016-11-11 10:03 399 查看
起因:因为逛CSDN的时候无意间看到这篇博文(传送门),想给自己的项目加上这个加载效果,但是原谅我放荡不羁用不来(不知道为什么是用那个报一堆不知名的错误),于是我决定自己动手,丰衣足食。

先上效果:
















截图不是gif,请见谅。

下面来实现:(绘制一个正六边形我就不再多说)

先来绘制出所有的六边形:

按照上图所示:

六边形在没有x和y的偏移量的情况下,假设我们从左边的第一个定点开始绘制的话,那么

六边形的高等于:Math.sqrt(3)*六边形边长。

第一个出现位置的起始点坐标是:(六边形的高/2,六边形边长/2)。

第二个出现位置的起始点坐标是:((六边形的高/2)*3,六边形的边长/2).

第三个出现位置的起始点坐标是:(六边形的高*2,(六边形的边长/2)*3).

第四个出现位置的起始点坐标是:((六边形的高/2)*3,六边形边长*3).

第五个出现位置的起始点坐标是:(六边形的高/2,六边形边长*3).

第六个出现位置的起始点坐标是:(0,(六边形的边长/2)*3).

第七个出现位置的起始点坐标是:(六边形的高,(六边形的边长/2)*3).

其他点的计算就不一一列举了,都是很简单的数学计算。

先讲动画:

这里有一个动画,一种是显示的,一种隐藏的,但是隐藏的可以用显示的动画reverse()来实现逆向动画。

下面是动画代码:

mShowAni = ValueAnimator.ofFloat(0,1);
mShowAni.setDuration(200);
mShowAni.setInterpolator(new DecelerateInterpolator());
mShowAni.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator animation){
float value = (float)animation.getAnimatedValue();
mScale = 0.5f+value/2;
mPaint.setAlpha((int)(value*255));
invalidate();//更新
}
});


添加动画监听:

mShowAni.addListener(new Animator.AnimatorListener(){
@Override
public void onAnimationStart(Animator animation){

}

@Override
public void onAnimationEnd(Animator animation){
mShowAni.removeAllListeners();
mShowAni = null;
initAni();
if(drawNum!=8) {
backDrawNum = 8;//赋值回退动画的位置
drawNum++;//正向动画的位置自增1
}
if(drawNum==8 && backDrawNum!=0)
{
//开始播放逆向动画
backDrawNum--;
mShowAni.reverse();
}
else if(drawNum==8 && backDrawNum==0)
{
//逆向动画播放完毕,播放正向动画
drawNum = 1;
}
invalidate();
}

@Override
public void onAnimationCancel(Animator animation){

}

@Override
public void onAnimationRepeat(Animator animation){

}
});


现在可以来看看绘画代码了(代码很简单,必要的地方我已经加上了注释):

public void DrawSix(Canvas canvas,Paint paint,int mLength,float Xoffset,float Yoffset,float scale)
{
Path mPath = new Path();
float height = (float)(Math.sqrt(3)*mLength);
mPath.moveTo(Xoffset,Yoffset+mLength/2);//初始点
mPath.lineTo(Xoffset+height/2,Yoffset);
mPath.lineTo(Xoffset+height,Yoffset+mLength/2);
mPath.lineTo(Xoffset+height,Yoffset+(mLength/2)*3);
mPath.lineTo(Xoffset+height/2,Yoffset+mLength*2);
mPath.lineTo(Xoffset,Yoffset+(mLength/2)*3);
mPath.lineTo(Xoffset,Yoffset+mLength/2);
mPath.close();//闭合路径
//Log.i("动画里","mScale:"+mScale);
if(scale!=-1) {//防止动画重复播放
if(mShowAni != null && ! mShowAni.isRunning()) {
mShowAni.start();
}
canvas.save();
canvas.scale(scale,scale,Xoffset + height / 2,Yoffset + mLength);
canvas.drawPath(mPath,paint);
canvas.restore();
}
else
{
//==-1的时候不播放动画,不处理会导致画面闪动
canvas.save();
canvas.scale(1,1,Xoffset + height / 2,Yoffset + mLength);
canvas.drawPath(mPath,paint);
canvas.restore();
}
}
/**
* 画守望六边形
* @param canvas
* @param paint
* @param mLength 半径
* @param Xoffset 偏移量
* @param Yoffset Y偏移量
* @param drawNum 绘画的位置
*/
public void DrawOWSix(Canvas canvas,Paint paint,int mLength,float Xoffset,float Yoffset,int drawNum,int backNum)
{
float height = (float)(Math.sqrt(3)*mLength);
float XoffsetZero = Xoffset;
float XoffsetOne = Xoffset+height/2;
float YoffsetOne = Yoffset;
float XoffsetTwo = Xoffset+(height/2)*3;
float XoffsetThree = Xoffset+height*2;
float YoffsetTwo = Yoffset+(mLength/2)*3;
float YoffsetThree = Xoffset+mLength*3;
float XoffsetCenter = Xoffset+height;
Paint defaultPaint = paint;//用来绘制已经播放完成动画的六边形
paint.setAlpha(255);
if(drawNum==8)
{
drawNum = backNum;
}
//画六边形,里面的-1赋值是用来让动画不再播放的
switch(drawNum) {
case 1:
DrawSix(canvas,paint,mLength,XoffsetOne,YoffsetOne,mScale);
break;
case 2:
DrawSix(canvas,defaultPaint,mLength,XoffsetOne,YoffsetOne,-1);
DrawSix(canvas,paint,mLength,XoffsetTwo + 3,YoffsetOne,mScale);
break;
case 3:
DrawSix(canvas,defaultPaint,mLength,XoffsetOne,YoffsetOne,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetTwo + 3,YoffsetOne,-1);
DrawSix(canvas,paint,mLength,XoffsetThree + 6,YoffsetTwo + 3,mScale);
break;
case 4:
DrawSix(canvas,defaultPaint,mLength,XoffsetOne,YoffsetOne,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetTwo + 3,YoffsetOne,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetThree + 6,YoffsetTwo + 3,-1);
DrawSix(canvas,paint,mLength,XoffsetTwo + 6,YoffsetThree + 6,mScale);
break;
case 5:
DrawSix(canvas,defaultPaint,mLength,XoffsetOne,YoffsetOne,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetTwo + 3,YoffsetOne,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetThree + 6,YoffsetTwo + 3,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetTwo + 6,YoffsetThree + 6,-1);
DrawSix(canvas,paint,mLength,XoffsetOne + 3,YoffsetThree + 6,mScale);
break;
case 6:
DrawSix(canvas,defaultPaint,mLength,XoffsetOne,YoffsetOne,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetTwo + 3,YoffsetOne,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetThree + 6,YoffsetTwo + 3,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetTwo + 6,YoffsetThree + 6,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetOne + 3,YoffsetThree + 6,-1);
DrawSix(canvas,paint,mLength,XoffsetZero,YoffsetTwo + 3,mScale);
break;
case 7:
DrawSix(canvas,defaultPaint,mLength,XoffsetOne,YoffsetOne,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetTwo + 3,YoffsetOne,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetThree + 6,YoffsetTwo + 3,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetTwo + 6,YoffsetThree + 6,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetOne + 3,YoffsetThree + 6,-1);
DrawSix(canvas,defaultPaint,mLength,XoffsetZero,YoffsetTwo + 3,-1);
DrawSix(canvas,paint,mLength,XoffsetCenter + 3,YoffsetTwo + 3,mScale);
break;
default:
break;
}
}


接下来就要实现ondraw()方法了:

@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
this.canvas = canvas;
DrawOWSix(this.canvas,mPaint,mLength,XOffset,YOffset,drawNum,backDrawNum);
}


实现构造方法(在这里对画笔,绘画大小,动画等进行初始化):

public DrawStar(Context context,AttributeSet attrs){
super(context,attrs);
final TypedArray array = context.getTheme().obtainStyledAttributes(attrs,R.styleable.OverWatchLoadingView, 0, 0);
mColor = array.getColor(R.styleable.OverWatchLoadingView_view_color, Color.parseColor("#FFCC00"));
array.recycle();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setAlpha(0);
mPaint.setColor(mColor);
View = this;
mScale = 0;
initAni();
}

public DrawStar(Context context,AttributeSet attrs,int defStyleAttr,Paint mPaint){
super(context,attrs,defStyleAttr);
this.mPaint = mPaint;
View = this;
mScale = 0;
initAni();
}

public DrawStar(Context context,AttributeSet attrs,int defStyleAttr,int defStyleRes,Paint mPaint){
super(context,attrs,defStyleAttr,defStyleRes);
this.mPaint = mPaint;
View = this;
mScale = 0;
initAni();
}


当然,我们需要外部可以控制这些动画的播放,加上几个方法应该就可以了(并没有测试)。

public void pauseLoading()
{
mShowAni.pause();
}
public void continueLoading()
{
mShowAni.start();
}
public void cancelLoading()
{
mShowAni.cancel();
}

源码传送门(传送门
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息