先来看看效果图
跳动的小球做这个动画,需掌握:
1、属性动画
2、Path类、Canvas类
3、贝塞尔曲线
4、SurfaceVIEw用法
5、自定义attr属性
6 、架构: 状态模式,控制器
7 、自由落体,抛物线等概念
不多说了,直接上码
1.DancingVIEw.java
public class DancingVIEw extends SurfaceVIEw implements SurfaceHolder.Callback { public static final int STATE_DOWN = 1;//向下状态 public static final int STATE_UP = 2;//向上状态 public static final int DEFAulT_POINT_RADIUS = 10; public static final int DEFAulT_BALL_RADIUS = 13; public static final int DEFAulT_liNE_WIDTH = 200; public static final int DEFAulT_liNE_HEIGHT = 2; public static final int DEFAulT_liNE_color = color.parsecolor("#FF9800"); public static final int DEFAulT_POINT_color = color.parsecolor("#9C27B0"); public static final int DEFAulT_BALL_color = color.parsecolor("#FF4081"); public static final int DEFAulT_DOWN_DURATION = 600;//ms public static final int DEFAulT_UP_DURATION = 600;//ms public static final int DEFAulT_FREEDOWN_DURATION = 1000;//ms public static final int MAX_OFFSET_Y = 50;//水平下降最大偏移距离 public int PONIT_RADIUS = DEFAulT_POINT_RADIUS;//小球半径 public int BALL_RADIUS = DEFAulT_BALL_RADIUS;//小球半径 private Paint mPaint; private Path mPath; private int mlinecolor; private int mPonitcolor; private int mBallcolor; private int mlinewidth; private int mlineHeight; private float mDowndistance; private float mUpdistance; private float freeBalldistance; private ValueAnimator mDownController;//下落控制器 private ValueAnimator mUpController;//上d控制器 private ValueAnimator mFreeDownController;//自由落体控制器 private AnimatorSet animatorSet; private int state; private boolean ismUpControllerDIEd = false; private boolean isAnimationShowing = false; private boolean isBounced = false; private boolean isBallFreeUp = false; public DancingVIEw(Context context) { super(context); init(context,null); } public DancingVIEw(Context context,AttributeSet attrs) { super(context,attrs); init(context,attrs); } public DancingVIEw(Context context,AttributeSet attrs,int defStyleAttr) { super(context,attrs,defStyleAttr); init(context,attrs); } private voID init(Context context,AttributeSet attrs) { initAttributes(context,attrs); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setstrokeWIDth(mlineHeight); mPaint.setstrokeCap(Paint.Cap.ROUND); mPath = new Path(); getHolder().addCallback(this); initController(); } private voID initAttributes(Context context,AttributeSet attrs) { TypedArray typeArray = context.obtainStyledAttributes(attrs,R.styleable.DancingVIEw); mlinecolor = typeArray.getcolor(R.styleable.DancingVIEw_linecolor,DEFAulT_liNE_color); mlinewidth = typeArray.getDimensionPixelOffset(R.styleable.DancingVIEw_linewidth,DEFAulT_liNE_WIDTH); mlineHeight = typeArray.getDimensionPixelOffset(R.styleable.DancingVIEw_lineHeight,DEFAulT_liNE_HEIGHT); mPonitcolor = typeArray.getcolor(R.styleable.DancingVIEw_pointcolor,DEFAulT_POINT_color); mBallcolor = typeArray.getcolor(R.styleable.DancingVIEw_ballcolor,DEFAulT_BALL_color); typeArray.recycle(); } private voID initController() { mDownController = ValueAnimator.offloat(0,1); mDownController.setDuration(DEFAulT_DOWN_DURATION); mDownController.setInterpolator(new DecelerateInterpolator()); mDownController.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @OverrIDe public voID onAnimationUpdate(ValueAnimator animation) { mDowndistance = MAX_OFFSET_Y * (float) animation.getAnimatedValue(); postInvalIDate(); } }); mDownController.addListener(new Animator.AnimatorListener() { @OverrIDe public voID onAnimationStart(Animator animation) { state = STATE_DOWN; } @OverrIDe public voID onAnimationEnd(Animator animation) { } @OverrIDe public voID onAnimationCancel(Animator animation) { } @OverrIDe public voID onAnimationRepeat(Animator animation) { } }); mUpController = ValueAnimator.offloat(0,1); mUpController.setDuration(DEFAulT_UP_DURATION); mUpController.setInterpolator(new DancingInterpolator()); mUpController.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @OverrIDe public voID onAnimationUpdate(ValueAnimator animation) { mUpdistance = MAX_OFFSET_Y * (float) animation.getAnimatedValue(); if (mUpdistance >= MAX_OFFSET_Y) { //进入自由落体状态 isBounced = true; if (!mFreeDownController.isRunning() && !mFreeDownController.isstarted() && !isBallFreeUp) { mFreeDownController.start(); } } postInvalIDate(); } }); mUpController.addListener(new Animator.AnimatorListener() { @OverrIDe public voID onAnimationStart(Animator animation) { state = STATE_UP; } @OverrIDe public voID onAnimationEnd(Animator animation) { ismUpControllerDIEd = true; } @OverrIDe public voID onAnimationCancel(Animator animation) { } @OverrIDe public voID onAnimationRepeat(Animator animation) { } }); mFreeDownController = ValueAnimator.offloat(0,8f); mFreeDownController.setDuration(DEFAulT_FREEDOWN_DURATION); mFreeDownController.setInterpolator(new DecelerateInterpolator()); mFreeDownController.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @OverrIDe public voID onAnimationUpdate(ValueAnimator animation) { //该公式解决上升减速 和 下降加速 float t = (float) animation.getAnimatedValue(); freeBalldistance = 40 * t - 5 * t * t; if (ismUpControllerDIEd) {//往上抛,到临界点 postInvalIDate(); } } }); mFreeDownController.addListener(new Animator.AnimatorListener() { @OverrIDe public voID onAnimationStart(Animator animation) { isBallFreeUp = true; } @OverrIDe public voID onAnimationEnd(Animator animation) { isAnimationShowing = false; //循环第二次 startAnimations(); } @OverrIDe public voID onAnimationCancel(Animator animation) { } @OverrIDe public voID onAnimationRepeat(Animator animation) { } }); animatorSet = new AnimatorSet(); animatorSet.play(mDownController).before(mUpController); animatorSet.addListener(new Animator.AnimatorListener() { @OverrIDe public voID onAnimationStart(Animator animation) { isAnimationShowing = true; } @OverrIDe public voID onAnimationEnd(Animator animation) { } @OverrIDe public voID onAnimationCancel(Animator animation) { } @OverrIDe public voID onAnimationRepeat(Animator animation) { } }); } /** * 启动动画,外部调用 */ public voID startAnimations() { if (isAnimationShowing) { return; } if (animatorSet.isRunning()) { animatorSet.end(); animatorSet.cancel(); } isBounced = false; isBallFreeUp = false; ismUpControllerDIEd = false; animatorSet.start(); } @OverrIDe protected voID onDraw(Canvas canvas) { super.onDraw(canvas); // 一条绳子用左右两部分的二阶贝塞尔曲线组成 mPaint.setcolor(mlinecolor); mPath.reset(); //起始点 mPath.moveto(getWIDth() / 2 - mlinewidth / 2,getHeight() / 2); if (state == STATE_DOWN) {//下落 /**************绘制绳子开始*************/ //左部分 的贝塞尔 mPath.quadTo((float) (getWIDth() / 2 - mlinewidth / 2 + mlinewidth * 0.375),getHeight() / 2 + mDowndistance,getWIDth() / 2,getHeight() / 2 + mDowndistance); //右部分 的贝塞尔 mPath.quadTo((float) (getWIDth() / 2 + mlinewidth / 2 - mlinewidth * 0.375),getWIDth() / 2 + mlinewidth / 2,getHeight() / 2); mPaint.setStyle(Paint.Style.stroke); canvas.drawPath(mPath,mPaint); /**************绘制绳子结束*************/ /**************绘制d跳小球开始*************/ mPaint.setStyle(Paint.Style.FILL); mPaint.setcolor(mBallcolor); canvas.drawCircle(getWIDth() / 2,getHeight() / 2 + mDowndistance - BALL_RADIUS,BALL_RADIUS,mPaint); /**************绘制d跳小球结束*************/ } else if (state == STATE_UP) { //向上d /**************绘制绳子开始*************/ //左部分的贝塞尔 mPath.quadTo((float) (getWIDth() / 2 - mlinewidth / 2 + mlinewidth * 0.375),getHeight() / 2 + 50 - mUpdistance,getHeight() / 2 + (50 - mUpdistance)); //右部分的贝塞尔 mPath.quadTo((float) (getWIDth() / 2 + mlinewidth / 2 - mlinewidth * 0.375),mPaint); /**************绘制绳子结束*************/ mPaint.setStyle(Paint.Style.FILL); mPaint.setcolor(mBallcolor); //d性小球,自由落体 if (!isBounced) { //上升 canvas.drawCircle(getWIDth() / 2,getHeight() / 2 + (MAX_OFFSET_Y - mUpdistance) - BALL_RADIUS,mPaint); } else { //自由落体 canvas.drawCircle(getWIDth() / 2,getHeight() / 2 - freeBalldistance - BALL_RADIUS,mPaint); } } mPaint.setcolor(mPonitcolor); mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(getWIDth() / 2 - mlinewidth / 2,getHeight() / 2,PONIT_RADIUS,mPaint); canvas.drawCircle(getWIDth() / 2 + mlinewidth / 2,mPaint); } @OverrIDe public voID surfaceCreated(SurfaceHolder holder) { Canvas canvas = holder.lockCanvas();//锁定整个SurfaceVIEw对象,获取该Surface上的Canvas. draw(canvas); holder.unlockCanvasAndPost(canvas);//释放画布,提交修改 } @OverrIDe public voID surfaceChanged(SurfaceHolder holder,int format,int wIDth,int height) { } @OverrIDe public voID surfaceDestroyed(SurfaceHolder holder) { }}
2.DancingInterpolator.java
public class DancingInterpolator implements Interpolator { @OverrIDe public float getInterpolation(float input) { return (float) (1 - Math.exp(-3 * input) * Math.cos(10 * input)); }}
3.自定义属性 styles.xml
<declare-styleable name="DancingVIEw"> <attr name="linewidth" format="dimension" /> <attr name="lineHeight" format="dimension" /> <attr name="pointcolor" format="reference|color" /> <attr name="linecolor" format="reference|color" /> <attr name="ballcolor" format="reference|color" /></declare-styleable>
注意:颜色、尺寸、参数可以自己测试,调整。
以上就是本文的全部内容,希望对大家的学习和工作能有所帮助哦。
总结以上是内存溢出为你收集整理的Android实现跳动的小球加载动画效果全部内容,希望文章能够帮你解决Android实现跳动的小球加载动画效果所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)