一对一免费咨询: 13913005726 025-66045668

营销型小程序 海口网站建设公司 企业网站建设

这还只是张图片

本文由hadisi5216原创,这篇可不能匿名转载。

背景:我一哥们公司做智能设备的,该动画用在手机和家中网络连接时用,他让我看了下需求。刚看到这动画时感觉产品\UI设计的不错,想着试试。昨天开始做的,本来感觉很简单,但做起来貌似没那么简单;最后花了近一天时间终于搞定了。看看效果还行!

niceloading.gif

如果有想直接用的同道中人,看前半部分就行;如果想批评指正我的思考的看看后半部分

1.直接上代码(NiceLoadingView)

packagecom.hadisi.niceloading;

importandroid.animation.ValueAnimator;

importandroid.content.Context;

importandroid.graphics.Bitmap;

importandroid.graphics.BitmapFactory;

importandroid.graphics.Canvas;

importandroid.graphics.Paint;

importandroid.graphics.Rect;

importandroid.util.AttributeSet;

importandroid.view.View;

importandroid.view.animation.LinearInterpolator;

/**

*Createdbyhadisi5216on2016/7/12.

*/

publicclassNiceLoadingViewextendsView{

privateContextmContext;

privatePaintmPaint;

privateintwidthSpecSize;

privateintheightSpecSize;

privateintradiusSmall=38;

privateintradiusbig=76;

privateintmoveX;

privateintXPoint;

privateintmState=-1;//0失败,1成功,-1默认

privatebooleanmflag;

privateValueAnimatoranimator;

publicNiceLoadingView(Contextcontext){

super(context);

}

publicNiceLoadingView(Contextcontext,AttributeSetattrs){

super(context,attrs);

}

publicNiceLoadingView(Contextcontext,AttributeSetattrs,intdefStyleAttr){

super(context,attrs,defStyleAttr);

mContext=context;

}

@Override

protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){

super.onMeasure(widthMeasureSpec,heightMeasureSpec);

widthSpecSize=MeasureSpec.getSize(widthMeasureSpec);

heightSpecSize=MeasureSpec.getSize(heightMeasureSpec);

}

@Override

protectedvoidonDraw(Canvascanvas){

super.onDraw(canvas);

mPaint=newPaint();

mPaint.setColor(0xFFFFBC53);

mPaint.setAntiAlias(true);

if(Math.abs(moveX)widthSpecSize*5/4)

{

XPoint=(moveX0)?XPoint=widthSpecSize*7/4

-Math.abs(moveX):widthSpecSize-widthSpecSize*7/4

+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

if(Math.abs(moveX)widthSpecSize&&Math.abs(moveX)widthSpecSize*3/2)

{

XPoint=(moveX0)?XPoint=widthSpecSize*3/2-Math.abs(moveX)

:widthSpecSize-widthSpecSize*3/2+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

if(Math.abs(moveX)widthSpecSize*3/4&&Math.abs(moveX)widthSpecSize*5/4)

{

XPoint=(moveX0)?XPoint=widthSpecSize*5/4-Math.abs(moveX):

widthSpecSize-widthSpecSize*5/4+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

if(Math.abs(moveX)widthSpecSize/2&&Math.abs(moveX)widthSpecSize){

XPoint=(moveX0)?XPoint=widthSpecSize-Math.abs(moveX):

widthSpecSize-widthSpecSize+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

if(Math.abs(moveX)widthSpecSize/4&&Math.abs(moveX)widthSpecSize*3/4){

XPoint=(moveX0)?XPoint=widthSpecSize*3/4-Math.abs(moveX):

widthSpecSize-widthSpecSize*3/4+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

if(Math.abs(moveX)0&&Math.abs(moveX)widthSpecSize/2){

XPoint=(moveX0)?XPoint=widthSpecSize/2-Math.abs(moveX):

widthSpecSize-widthSpecSize/2+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

//中间大圆

if(Math.abs(moveX)0&&Math.abs(moveX)widthSpecSize*5/4){

radiusbig=2*radiusSmall-radiusSmall*

(Math.abs(moveX))/(widthSpecSize*5/4);

radiusbig=(radiusbigradiusSmall)?radiusbig:radiusSmall;

canvas.drawCircle(widthSpecSize/2,heightSpecSize/2,radiusbig,mPaint);

}

if(Math.abs(moveX)12&&mState=0){

if(mState==0){

canvas.drawCircle(widthSpecSize/2,heightSpecSize/2,radiusbig,mPaint);

Bitmapbitmap=BitmapFactory.decodeResource(getContext().getResources(),

R.mipmap.connect_failed);

canvas.drawBitmap(bitmap,null,newRect(widthSpecSize/

2-radiusbig,heightSpecSize/2-radiusbig,widthSpecSize/

2+radiusbig,heightSpecSize/2+radiusbig),mPaint);

}

if(mState==1){

canvas.drawCircle(widthSpecSize/2,heightSpecSize/2,radiusbig,mPaint);

Bitmapbitmap=BitmapFactory.decodeResource(getContext().getResources(),

R.mipmap.connect_success);

canvas.drawBitmap(bitmap,null,newRect(widthSpecSize/

2-radiusbig,heightSpecSize/2-radiusbig,widthSpecSize/

2+radiusbig,heightSpecSize/2+radiusbig),mPaint);

}

}

}

publicvoidstart(){

if(animator!=null)

animator.cancel();

moveX=widthSpecSize*(-9/4);

mState=-1;

mflag=true;

post(newRunnable(){

@Override

publicvoidrun(){

animator=ValueAnimator.ofFloat(0f,1.0f);

animator.setDuration(3000);//没啥用

animator.setRepeatMode(ValueAnimator.RESTART);

animator.setRepeatCount(ValueAnimator.INFINITE);

animator.setInterpolator(newLinearInterpolator());

animator.addUpdateListener(newValueAnimator.AnimatorUpdateListener(){

@Override

publicvoidonAnimationUpdate(ValueAnimatoranimation){

if(mState0){

moveX=(moveXwidthSpecSize*7/4)

?widthSpecSize*(-9/4):moveX+12;

if(Math.abs(moveX)12)

try{

Thread.sleep(1000);

}catch(InterruptedExceptione){

e.printStackTrace();

}

}else{

if(moveX0)

moveX=(moveXwidthSpecSize*7/4)

?widthSpecSize*(-9/4):moveX+12;

elseif(moveX0&&mflag){

moveX+=12;

if(Math.abs(moveX)12)

mflag=false;

}

}

postInvalidate();

}

});

animator.start();

}

});

}

publicvoidsuccess(){

mState=1;

}

publicvoidfailed(){

mState=0;

}

}

项目已上传到github,戳着

2.怎么用?

布局文件中

com.hadisi.niceloading.NiceLoadingView

android:id="@+id/nice_loading"

android:layout_width="match_parent"

android:layout_height="100dp"/

你要用的地方

NiceLoadingViewniceLoading=(NiceLoadingView)findViewById(R.id.nice_loading);

……

//开始连接时

niceLoading.start();

……

//连接成功时

niceLoading.success();

……

//连接失败时

niceLoading.failed();

3.我怎么实现的!

仔细看效果图可以得出:

1、有6个小圆依次从屏幕左侧移入屏幕中间,然后又依次从屏幕中间移出屏幕右侧。

2、中间有个大圆在随着小球的依次靠近慢慢变大,离开慢慢变小;注意在左侧第一个小圆到达中间时才出现大圆,在最后一个小圆准备向右侧移动时消失;大圆的半径在小圆半径和大圆半径之间。

3、不管何时得到成功和失败的状态,动画终止时都是在小圆依次从左边进入中间后。

4、动画完成后显示成功/失败图片和大圆。

1. 6个小圆的运动

我是这样想的:当第1个小圆移动到widthSpecSize/4(widthSpecSize 为控件的宽度)时第2个小圆开始移动、当第2个小圆移动到widthSpecSize/4时第3个小圆开始移动......当第5个小圆移动到widthSpecSize/4 时第6个小圆开始移动、第6个小圆移动到widthSpecSize/2 时继续移动、当第6个小圆移动到widthSpecSize 3/4时第5个小圆开始移动......当第2个小圆移动到widthSpecSize 3/4时第一个小圆开始移动、最后第1个小球移出屏幕右侧,到此为一个循环。

假设有一个位移变量moveX,moveX在不断增加,其变化范围为(a,b);可以看出按照我的想法,第1个小圆在范围的两边时开始移动、第6个小球在变化范围的中间部分开始移动。

我们可以继续假设变化范围为(-a,a),这样第1个小圆在范围的绝对值大时开始移动、第6个小球在变化范围的绝对值小时开始移动;其实这种重复的动作很容易想到绝对值控制

找张纸画下很容易得到moveX的变化范围在(-widthSpecSize 7/4 , widthSpecSize 7/4)之间。

自己画的图,有点丑

对照图很快可以得出下面代码

if(Math.abs(moveX)widthSpecSize*5/4){

XPoint=(moveX0)?XPoint=widthSpecSize*7/4-Math.abs(moveX):

widthSpecSize-widthSpecSize*7/4+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

if(Math.abs(moveX)widthSpecSize&&Math.abs(moveX)widthSpecSize*3/2)

{

XPoint=(moveX0)?XPoint=widthSpecSize*3/2-Math.abs(moveX):

widthSpecSize-widthSpecSize*3/2+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

if(Math.abs(moveX)widthSpecSize*3/4&&Math.abs(moveX)widthSpecSize*5/4)

{

XPoint=(moveX0)?XPoint=widthSpecSize*5/4-Math.abs(moveX):

widthSpecSize-widthSpecSize*5/4+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

if(Math.abs(moveX)widthSpecSize/2&&Math.abs(moveX)widthSpecSize)

{

XPoint=(moveX0)?XPoint=widthSpecSize-Math.abs(moveX):

widthSpecSize-widthSpecSize+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

if(Math.abs(moveX)widthSpecSize/4&&Math.abs(moveX)widthSpecSize*3/4)

{

XPoint=(moveX0)?XPoint=widthSpecSize*3/4-Math.abs(moveX):

widthSpecSize-widthSpecSize*3/4+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

if(Math.abs(moveX)0&&Math.abs(moveX)widthSpecSize/2){

XPoint=(moveX0)?XPoint=widthSpecSize/2-Math.abs(moveX):

widthSpecSize-widthSpecSize/2+Math.abs(moveX);

canvas.drawCircle(XPoint,heightSpecSize/2,radiusSmall,mPaint);

}

中间变化的大圆在左侧第1个小圆到达中间时才出现大圆,在第1个小圆准备向右侧移动时消失,变化范围(-widthSpecSize 5/4 , widthSpecSize 5/4)之间。大圆的半径在小圆半径和大圆半径之间,我们用radiusbig = radiusbig - radiusSmall (Math.abs(moveX)) / (widthSpecSize 5/4)计算大圆半径,可以得到慢慢变大和变小的效果,然后控制在小于radiusSmall时用radiusSmall。

if(Math.abs(moveX)0&&Math.abs(moveX)widthSpecSize*5/4){

radiusbig=radiusbig-radiusSmall*(Math.abs(moveX))/(widthSpecSize*5/4);

radiusbig=(radiusbigradiusSmall)?radiusbig:radiusSmall;

canvas.drawCircle(widthSpecSize/2,heightSpecSize/2,radiusbig,mPaint);

}

3. 动画终止的控制

正常当一个循环结束时我们需要重新给moveX赋值为widthSpecSize * (-7/4),当收到成功或失败状态时需要判断当前的状态,等到动画进行到结束状态(小圆依次从左边进入中间后)。见下面代码,mState为当前状态(0失败,1成功,-1默认)。

我重新赋值时将moveX设为 widthSpecSize * (-9/4),因为一个循环结束后有点停顿会感觉舒服点,这个无所谓,自己感觉而已

if(mState0){

moveX=(moveXwidthSpecSize*7/4)

?widthSpecSize*(-9/4):moveX+12;

}else{

if(moveX0)

moveX=(moveXwidthSpecSize*7/4)

?widthSpecSize*(-9/4):moveX+12;

elseif(moveX0&&mflag){

moveX+=12;

if(Math.abs(moveX)12)

mflag=false;

}

}

4. 显示成功/失败图片

这个简单,在收到成功或失败状态,待动画完成时先画一个大圆,再画一个bitmap

if(Math.abs(moveX)12&&mState=0){

if(mState==0){

canvas.drawCircle(widthSpecSize/2,

heightSpecSize/2,radiusbig,mPaint);

Bitmapbitmap=BitmapFactory.decodeResource(getContext().getResources(),R.mipmap.connect_failed);

canvas.drawBitmap(bitmap,null,newRect(widthSpecSize

/2-radiusbig,heightSpecSize/2-radiusbig,

widthSpecSize/2+radiusbig,heightSpecSize/2+radiusbig),mPaint);

}

if(mState==1){

canvas.drawCircle(widthSpecSize/2,heightSpecSize/2,radiusbig,mPaint);

Bitmapbitmap=BitmapFactory.decodeResource(getContext().getResources(),R.mipmap.connect_success);

canvas.drawBitmap(bitmap,null,newRect(widthSpecSize/2

-radiusbig,heightSpecSize/2-radiusbig,widthSpecSize

/2+radiusbig,heightSpecSize/2+radiusbig),mPaint);

}

}

5.优化

可以优化,将paint的颜色等属性、大小圆的半径、优化画小圆的逻辑,使小圆个数可变..........

其实核心的就是想法,随便怎么优化。反正我就弄到这了,油而不腻,我觉得挺好,不需要太多优化。吼吼....


 


 南京牧狼文化传媒有限公司简介:


      牧狼传媒,牧者之心,狼者之性,以牧之谦卑宽容之心待人,以狼之团结无畏之性做事!


  公司注册资金100万,主营众筹全案服务、网站营销全案服务、网站建设、微信小程序开发、电商网店设计、H5页面设计、腾讯社交广告投放以及电商营销推广全案等相关业务,致力于为客户提供更有价值的服务,创造让用户满意的效果!


  为百度官方及其大客户、苏宁易购、金山WPS秀堂、美的、创维家电、新东方在线、伊莱克斯、宝丽莱等国内国外知名品牌服务过,服务经验丰富!同时,公司也是南京电子商务协会会员单位、猪八戒网官方认证签约服务商、江苏八戒服务网联盟、南京浦口文化产业联合会会员单位,可以为您提供更好的服务!


  主营项目:众筹全案服务、网站营销全案服务、网站建设、微信小程序开发、电商网店设计、H5页面设计、腾讯社交广告投放、竞价托管、网站优化、电商代运营等


  合作客户:百度、苏宁易购、饿了么、美的、创维家电、新东方在线、宝丽莱、金山WPS秀堂、伊莱克斯


  资质荣誉:百度商业服务市场2017年度最佳图片服务商、南京电子商务协会会员单位、猪八戒网官方认证签约服务商、江苏八戒服务网联盟、南京浦口文化产业联合会会员单位、八戒通TOP服务商、"易拍即合杯"H5创意大赛"三等奖"。



致力于为客户创造更多价值
13913005726 025-66045668
需求提交
电话咨询
在线咨询