58同城加载动画

来源:互联网 发布:期权 内在价值 知乎 编辑:程序博客网 时间:2024/05/16 19:39

一、效果先行

  这里写图片描述

二、功能实现

1.布局分析
  可以看到上图可分为三部分,最上面是弹跳的几何形状图形,中间是阴影指示器,最下面是文字,所以布局用LinearLayout,最上面暂且放ImageView,中间放ImageView , 最下面放置文字

1.ui_loding_view.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:gravity="center_horizontal"    android:orientation="vertical">    <ImageView        android:id="@+id/shapeLoadingView"        android:layout_width="24dp"        android:layout_height="24dp"        android:layout_centerHorizontal="true"        android:layout_marginTop="4dp" />        <ImageView            android:id="@+id/indication"            android:layout_width="23dp"            android:layout_height="3dp"            android:layout_centerHorizontal="true"            android:layout_marginTop="82dp"            android:src="@drawable/shadow" />        <TextView            android:id="@+id/promptTV"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_below="@+id/indication"            android:layout_centerHorizontal="true"            android:layout_marginTop="18dp"            android:textColor="#757575"            android:text="玩命加载中..."            android:textSize="14sp" /></LinearLayout>

2.LoadingView 继承自 LinearLayout

public class LoadingView extends LinearLayout{    private ImageView mShapeLodingView,mIndicationView;    private Context mContext;    public LoadingView(Context context) {        this(context, null);    }    public LoadingView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        this.mContext = context;        initLayout();    }    private void initLayout() {        View.inflate(mContext, R.layout.load_view,this);        mShapeLodingView = (ShapeLoadingView) findViewById(R.id.shapeLoadingView);        mIndicationView = (ImageView) findViewById(R.id.indication);    }

2.动画分析
  这里可以看做两个部分的动画,一个是上面几何图形的下落上抛动画,一个是中间阴影指示器放大缩小的动画,如果能这样组合就算实现了:当几何图形下落时配合阴影放大,当几何图形上抛时配合中间阴影缩小。这里需要用到ObjectAnimator属性动画http://blog.csdn.net/lmj623565791/article/details/38067475

3.动画实现

 //初始化下落动画 private void initFreeFallAnimation() {        // 下落动画集合        mFreeFallAnimatiorSet  = new AnimatorSet();        // 几何图形的垂直位移动画        ObjectAnimator freeFallTranslationAnimator = ObjectAnimator.ofFloat(                mShapeLodingView, "translationY", 0, mTranslationYDistance);        // 定义动画的变化率。        freeFallTranslationAnimator.setInterpolator(new AccelerateInterpolator(factor));        // 中间阴影缩小动画        ObjectAnimator scaleIndication = ObjectAnimator.ofFloat(mIndicationView,                "scaleX", 1, 0.2f);        mFreeFallAnimatiorSet.setDuration(ANIMATION_DURATION);        mFreeFallAnimatiorSet.playTogether(freeFallTranslationAnimator, scaleIndication);        mFreeFallAnimatiorSet.addListener(new AnimatorListenerAdapter() {            //设置动画监听器,监听该动画的开始、停止、取消、结束等状态,我们往往会用AnimtorListener适配器类来只实现我们需要的方法            @Override            public void onAnimationEnd(Animator animation) {                super.onAnimationEnd(animation);                // 下落动画结束,改变形状,然后执行上抛动画                upThrow();                mShapeLodingView.changeShape();            }        });    }

  上抛动画其实和下落动画差不多,只要在下落动画执行完之后启动上抛动画即可,但是我们需要在下落动画结束完后改变形状,最直接的方式便是改变几何图像ImageView的背景资源即可,但是个人认为这样不是太好,所以需要自定义几何形状ShapeLoadingView,然后提供一个changeShape()的方法,里面调用invalidate(),在onDraw(Canvas canvas)中画对应的几何形状
  
4.自定义几何view

 public class ShapeLoadingView extends View{    // 圆 ,三角 ,正方形 的画笔    private Paint mPaint;    // 宽度和高度    private int mHeigth,mWidth;    // 当前是什么形状    private Shape mCureentShape;    public ShapeLoadingView(Context context) {        this(context, null);    }    public ShapeLoadingView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public ShapeLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initData();    }    private void initData() {        mPaint = new Paint();        mPaint.setAntiAlias(true);        mCureentShape = Shape.SHAPE_CIRCLE;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        mHeigth = getMeasuredHeight();        mWidth = getMeasuredWidth();    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        switch (mCureentShape){            case SHAPE_CIRCLE:                drawCircle(canvas);                break;            case SHAPE_TRIANGLE:                drawTriangle(canvas);                break;            case SHAPE_RECT:                drawRect(canvas);                break;        }    }    /**     * 画正方形     */    private void drawRect(Canvas canvas) {        mPaint.setColor(getResources().getColor(R.color.rect));        canvas.drawRect(0, 0, mWidth, mHeigth, mPaint);    }    /**     * 画三角形     */    private void drawTriangle(Canvas canvas) {        mPaint.setColor(getResources().getColor(R.color.triangle));        Path path = new Path();        path.moveTo(mWidth / 2, 0);        path.lineTo(0, mHeigth);        path.lineTo(mWidth, mHeigth);        path.close();        canvas.drawPath(path, mPaint);    }    /**     * 画圆形     */    private void drawCircle(Canvas canvas) {        mPaint.setColor(getResources().getColor(R.color.circle));        canvas.drawCircle(mWidth / 2, mHeigth / 2, mWidth / 2, mPaint);    }    /**     * 改变形状     */    public void changeShape() {        switch (mCureentShape){            case SHAPE_CIRCLE:                mCureentShape = Shape.SHAPE_RECT;                break;            case SHAPE_RECT:                mCureentShape = Shape.SHAPE_TRIANGLE;                break;            case SHAPE_TRIANGLE:                mCureentShape = Shape.SHAPE_CIRCLE;                break;        }        // 重新绘制        invalidate();    }    public enum Shape{        // 三角        SHAPE_TRIANGLE,        // 四边形        SHAPE_RECT,        // 圆形        SHAPE_CIRCLE    }}

4.旋转动画
  最后就剩两个旋转的动画了,我们旋转的动画以及角度问题我们直接从自定义ShapeLoadingView 中获取,提供一个getUpThrowRoteAnimation()方法

    /**    * 在ShapeLoadingView的构造方法中初始化旋转动画即可    */    private void initRoteAnimation() {        mRectRoteAnimation = ObjectAnimator.ofFloat(this,                "rotation", 0, -120);        mDefaultRoteAnimation = ObjectAnimator.ofFloat(this,                "rotation", 0, 180);    }     /**     * 得到当前正在上抛时应该旋转的动画     */    public ObjectAnimator getUpThrowRoteAnimation() {        switch (mCureentShape){            case SHAPE_RECT:                return  mRectRoteAnimation;            default:                return mDefaultRoteAnimation;        }    }

给上抛动画设置动画监听,在其onAnimationStart()中执行旋转动画

       mUpThrowAnimatiorSet.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                super.onAnimationEnd(animation);                //动画结束,下落                freeFall();            }            @Override            public void onAnimationStart(Animator animation) {                super.onAnimationStart(animation);                // 动画开始,和旋转动画一起执行                startShapeRoteAnimator();            }            /**             * 执行旋转动画             */            private void startShapeRoteAnimator() {                ObjectAnimator roteAnimation  = mShapeLodingView.getUpThrowRoteAnimation();                roteAnimation.setDuration(ANIMATION_DURATION);                roteAnimation.setInterpolator(new DecelerateInterpolator(factor));                roteAnimation.start();            }        });

源码下载:http://download.csdn.net/detail/z240336124/9353335

0 0
原创粉丝点击