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

起因:因为逛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();
	}

源码传送门(传送门


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值