animation之objectAnimator

这次借助github上的开源项目ShapeLoadingView来学习下ObjectAnimator和animatorSet. 代码结构目录:

ShapeLoadingView.javaLoadingView.java LoadingView是绘制三个基本图形的类。 ShapeLoadingView初始化图形并操作图形进行动画。 下面上加了注释的代码:package com.mingle.widget;import android.annotation.TargetApi;import android.content.Context;import android.content.res.TypedArray;import android.os.Build;import android.text.TextUtils;import android.util.AttributeSet;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.animation.AccelerateInterpolator;import android.view.animation.DecelerateInterpolator;import android.widget.FrameLayout;import android.widget.ImageView;import android.widget.TextView;import com.mingle.shapeloading.R;import com.nineoldandroids.animation.Animator;import com.nineoldandroids.animation.AnimatorSet;import com.nineoldandroids.animation.ObjectAnimator;/** * Created by zzz40500 on 15/4/6. */{ANIMATION_DURATION = 500;mDistance = 200;private ShapeLoadingView mShapeLoadingView;private ImageView mIndicationIm;private TextView mLoadTextView;private int mTextAppearance;private String mLoadText;public LoadingView(Context context) {super(context);}public LoadingView(Context context, AttributeSet attrs) {//构造函数super(context, attrs, 0);init(context, attrs);}(Context context, AttributeSet attrs) {//这里是通过自定义属性来显示字符串TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LoadingView);mLoadText = typedArray.getString(R.styleable.LoadingView_loadingText);mTextAppearance = typedArray.getResourceId(R.styleable.LoadingView_loadingTextAppearance, -1);typedArray.recycle();}public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {//构造函数super(context, attrs, defStyleAttr);init(context, attrs);}//这里定义了一个针对LL版本的构造函数,我这可能因为sdk版本这里会报错,如果报错注释掉就行了@TargetApi(Build.VERSION_CODES.LOLLIPOP)public LoadingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);init(context, attrs);}(float dipValue) {final float scale = getContext().getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}() {super.onFinishInflate();View view = LayoutInflater.from(getContext()).inflate(R.layout.load_view, null);mDistance = dip2px(54f);LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);layoutParams.gravity = Gravity.CENTER;mShapeLoadingView = (ShapeLoadingView) view.findViewById(R.id.shapeLoadingView);mIndicationIm = (ImageView) view.findViewById(R.id.indication);mLoadTextView = (TextView) view.findViewById(R.id.promptTV);if (mTextAppearance != -1) {mLoadTextView.setTextAppearance(getContext(), mTextAppearance);}setLoadingText(mLoadText);//显示绘画布局addView(view, layoutParams);//这里是设计一个延时 每隔900调用一次跌落,相当于900ms是一次动画的周期this.postDelayed(new Runnable() {() {freeFall();}}, 900);}(CharSequence loadingText) {if (TextUtils.isEmpty(loadingText)) {mLoadTextView.setVisibility(GONE);} else {mLoadTextView.setVisibility(VISIBLE);}mLoadTextView.setText(loadingText);}/*** 上抛,上抛是动画的核心,,上抛是两个组合动作:1,图形进行旋转;2,图形向上平移,同时还有下面阴影部分随着图形位置变化* 进行的跟随变化。这里使用了ObjectAnimator来控制每个动画的动作,最后使用AnimatorSet将三个部分组合在一起。* 看一下具体的动作*/() {//mShapeLoadingView就是LoadingView里面绘制的图形买第一个objectAnimator控制它进行平移//使用objectAnimator.ofFloat及参数translationY来进行纵向的平移ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mShapeLoadingView, “translationY”, mDistance, 0);//动画下部的阴影这里使用ofFloat及参数scaleX来进行X轴的缩放,02f-1是缩放比例 阴影在20%到100%之间变化ObjectAnimator scaleIndication = ObjectAnimator.ofFloat(mIndicationIm, “scaleX”, 0.2f, 1);//这段是对图形做一个旋转的动作ObjectAnimator objectAnimator1 = null;switch (mShapeLoadingView.getShape()) {case SHAPE_RECT:objectAnimator1 = ObjectAnimator.ofFloat(mShapeLoadingView, “rotation”, 0, -120);break;case SHAPE_CIRCLE:objectAnimator1 = ObjectAnimator.ofFloat(mShapeLoadingView, “rotation”, 0, 180);break;case SHAPE_TRIANGLE:objectAnimator1 = ObjectAnimator.ofFloat(mShapeLoadingView, “rotation”, 0, 180);break;}//设置animation的持续时间,通过setDuration.objectAnimator.setDuration(ANIMATION_DURATION);objectAnimator1.setDuration(ANIMATION_DURATION);//设置一个减速插值器objectAnimator.setInterpolator(new DecelerateInterpolator(factor));objectAnimator1.setInterpolator(new DecelerateInterpolator(factor));AnimatorSet animatorSet = new AnimatorSet();animatorSet.setDuration(ANIMATION_DURATION);//animatorSet的方法playtogther让三个动画同时运行animatorSet.playTogether(objectAnimator, objectAnimator1, scaleIndication);animatorSet.addListener(new Animator.AnimatorListener() {(Animator animation) {}(Animator animation) {freeFall();}(Animator animation) {}(Animator animation) {}});animatorSet.start();}public float factor = 1.2f;/*** 下落*/() {//主要的点和上抛一致不讲了ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mShapeLoadingView, “translationY”, 0, mDistance);ObjectAnimator scaleIndication = ObjectAnimator.ofFloat(mIndicationIm, “scaleX”, 1, 0.2f);objectAnimator.setDuration(ANIMATION_DURATION);objectAnimator.setInterpolator(new AccelerateInterpolator(factor));AnimatorSet animatorSet = new AnimatorSet();animatorSet.setDuration(ANIMATION_DURATION);animatorSet.playTogether(objectAnimator, scaleIndication);animatorSet.addListener(new Animator.AnimatorListener() {(Animator animation) {}(Animator animation) {//下落到底端改变图形mShapeLoadingView.changeShape();upThrow();}(Animator animation) {}(Animator animation) {}});animatorSet.start();}}package com.mingle.widget;import android.annotation.TargetApi;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Path;import android.os.Build;import android.util.AttributeSet;import android.view.View;import com.mingle.shapeloading.R;/** * Created by zzz40500 on 15/4/4. */{genhao3 = 1.7320508075689f;mTriangle2Circle =0.25555555f;private Shape mShape = Shape.SHAPE_CIRCLE;/*** 用贝赛尔曲线画圆*/private float mMagicNumber = 0.55228475f;public ShapeLoadingView(Context context) {super(context);init();}public ShapeLoadingView(Context context, AttributeSet attrs) {super(context, attrs);init();}public ShapeLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@TargetApi(Build.VERSION_CODES.LOLLIPOP)public ShapeLoadingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);init();}() {mPaint = new Paint();mPaint.setColor(getResources().getColor(R.color.triangle));mPaint.setAntiAlias(true);//看到网上说这个FILL_AND_STROKE有去锯齿的作用mPaint.setStyle(Paint.Style.FILL_AND_STROKE);setBackgroundColor(getResources().getColor(R.color.view_bg));}public boolean mIsLoading = false;private Paint mPaint;private float mControlX = 0;private float mControlY = 0;private float mAnimPercent;(Canvas canvas) {super.onDraw(canvas);//绘制三个图形的三角形方框圆形的位置,作者在这里标记动画可以优化,估计会有后续修改if(getVisibility()==GONE){return;}// FIXME: 15/6/15 动画待优化switch (mShape) {case SHAPE_TRIANGLE:if (mIsLoading) {mAnimPercent += 0.1611113;// triangle to circlePath path = new Path();path.moveTo(relativeXFromView(0.5f), relativeYFromView(0f));if (mAnimPercent >= 1) {mShape = Shape.SHAPE_CIRCLE;mIsLoading = false;mAnimPercent=1;}float controlX = mControlX – relativeXFromView(mAnimPercent* mTriangle2Circle)* genhao3;float controlY = mControlY – relativeYFromView(mAnimPercent* mTriangle2Circle);path.quadTo(relativeXFromView(1) – controlX, controlY, relativeXFromView(0.5f + genhao3 / 4), relativeYFromView(0.75f));path.quadTo(relativeXFromView(0.5f), relativeYFromView(0.75f + 2 * mAnimPercent* mTriangle2Circle), relativeXFromView(0.5f – genhao3 / 4), relativeYFromView(0.75f));path.quadTo(controlX, controlY, relativeXFromView(0.5f), relativeYFromView(0f));path.close();canvas.drawPath(path, mPaint);invalidate();} else {Path path = new Path();mPaint.setColor(getResources().getColor(R.color.triangle));path.moveTo(relativeXFromView(0.5f), relativeYFromView(0f));path.lineTo(relativeXFromView(1), relativeYFromView(genhao3 / 2f));path.lineTo(relativeXFromView(0), relativeYFromView(genhao3/2f));mControlX = relativeXFromView(0.5f – genhao3 / 8.0f);mControlY = relativeYFromView(3 / 8.0f);mAnimPercent = 0;path.close();canvas.drawPath(path, mPaint);}break;case SHAPE_CIRCLE:if (mIsLoading) {float magicNumber = mMagicNumber + mAnimPercent;mAnimPercent += 0.12;if (magicNumber + mAnimPercent >= 1.9f) {mShape = Shape.SHAPE_RECT;mIsLoading = false;}Path path = new Path();path.moveTo(relativeXFromView(0.5f), relativeYFromView(0f));path.cubicTo(relativeXFromView(0.5f + magicNumber / 2), relativeYFromView(0f),relativeXFromView(1), relativeYFromView(0.5f – magicNumber / 2),relativeXFromView(1f), relativeYFromView(0.5f));path.cubicTo(relativeXFromView(1), relativeXFromView(0.5f + magicNumber / 2),relativeXFromView(0.5f + magicNumber / 2), relativeYFromView(1f),relativeXFromView(0.5f), relativeYFromView(1f));path.cubicTo(relativeXFromView(0.5f – magicNumber / 2), relativeXFromView(1f),relativeXFromView(0), relativeYFromView(0.5f + magicNumber / 2),relativeXFromView(0f), relativeYFromView(0.5f));path.cubicTo(relativeXFromView(0f), relativeXFromView(0.5f – magicNumber / 2),relativeXFromView(0.5f – magicNumber / 2), relativeYFromView(0),relativeXFromView(0.5f), relativeYFromView(0f));path.close();canvas.drawPath(path, mPaint);invalidate();} else {mPaint.setColor(getResources().getColor(R.color.circle));Path path = new Path();float magicNumber = mMagicNumber;path.moveTo(relativeXFromView(0.5f), relativeYFromView(0f));path.cubicTo(relativeXFromView(0.5f + magicNumber / 2), 0,relativeXFromView(1), relativeYFromView(magicNumber / 2),relativeXFromView(1f), relativeYFromView(0.5f));path.cubicTo(relativeXFromView(1), relativeXFromView(0.5f + magicNumber / 2),relativeXFromView(0.5f + magicNumber / 2), relativeYFromView(1f),relativeXFromView(0.5f), relativeYFromView(1f));path.cubicTo(relativeXFromView(0.5f – magicNumber / 2), relativeXFromView(1f),relativeXFromView(0), relativeYFromView(0.5f + magicNumber / 2),relativeXFromView(0f), relativeYFromView(0.5f));path.cubicTo(relativeXFromView(0f), relativeXFromView(0.5f – magicNumber / 2),relativeXFromView(0.5f – magicNumber / 2), relativeYFromView(0),relativeXFromView(0.5f), relativeYFromView(0f));mAnimPercent = 0;path.close();canvas.drawPath(path, mPaint);}break;case SHAPE_RECT:if (mIsLoading) {mAnimPercent += 0.15;if (mAnimPercent >= 1) {mShape = Shape.SHAPE_TRIANGLE;mIsLoading = false;mAnimPercent = 1;}Path path = new Path();path.moveTo(relativeXFromView(0.5f * mAnimPercent), 0);path.lineTo(relativeYFromView(1 – 0.5f * mAnimPercent), 0);float distanceX = (mControlX) * mAnimPercent;float distanceY = (relativeYFromView(1f) – mControlY) * mAnimPercent;path.lineTo(relativeXFromView(1f) – distanceX, relativeYFromView(1f) – distanceY);path.lineTo(relativeXFromView(0f) + distanceX, relativeYFromView(1f) – distanceY);path.close();canvas.drawPath(path, mPaint);invalidate();} else {mPaint.setColor(getResources().getColor(R.color.rect));mControlX = relativeXFromView(0.5f – genhao3 / 4);mControlY = relativeYFromView(0.75f);Path path = new Path();path.moveTo(relativeXFromView(0f), relativeYFromView(0f));path.lineTo(relativeXFromView(1f), relativeYFromView(0f));path.lineTo(relativeXFromView(1f), relativeYFromView(1f));path.lineTo(relativeXFromView(0f), relativeYFromView(1f));path.close();mAnimPercent = 0;canvas.drawPath(path, mPaint);}break;}}(float percent) {return getWidth() * percent;}(float percent) {return getHeight() * percent;}() {mIsLoading = true;invalidate();public enum Shape {SHAPE_TRIANGLE, SHAPE_RECT, SHAPE_CIRCLE}(int visibility) {super.setVisibility(visibility);if(visibility==VISIBLE){invalidate();}}public Shape getShape() {return mShape;}}

这个开源项目我们学习的两个主要知识 1.使用path绘制图形 2.ObjectAnimation&AnimatorSet 看了这个项目是不是可以用这两个知识点做一个自己喜欢的动画? just do it.

只有一条路不能选择——那就是放弃的路;

animation之objectAnimator

相关文章:

你感兴趣的文章:

标签云: