自定义view-58同城数据加载动画

这里写图片描述

首先绘制三个形状

public class ShapeView extends View {
    private Paint mPaint;
    private Shape mCurrentShape = Shape.Circle;
    private Path mPath;

    public ShapeView(Context context) {
        this(context, null);
    }

    public ShapeView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }


    public ShapeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //保证是正方形
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(Math.min(width, height), Math.min(width, height));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int center = getWidth() / 2;
        switch (mCurrentShape) {
            case Circle:
                mPaint.setColor(ContextCompat.getColor(getContext(), R.color.circle));
                canvas.drawCircle(center, center, center, mPaint);
                break;
            case Square:
                mPaint.setColor(ContextCompat.getColor(getContext(), R.color.rect));
                canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
                break;
            case Triangle://绘制等边三角形
                mPaint.setColor(ContextCompat.getColor(getContext(), R.color.triangle));
                if (mPath == null) {
                    mPath = new Path();
                    mPath.moveTo(center, 0);
                    mPath.lineTo(0, (float) (center * Math.sqrt(3)));
                    mPath.lineTo(getWidth(), (float) (center * Math.sqrt(3)));
                    mPath.close();
                }
                canvas.drawPath(mPath, mPaint);
                break;
        }
    }

    public enum Shape {
        Circle, Square, Triangle

    }

    /**
     * 切换形状
     */
    public void exchange() {
        switch (mCurrentShape) {
            case Circle:
                mCurrentShape = Shape.Square;
                break;
            case Square:
                mCurrentShape = Shape.Triangle;
                break;
            case Triangle:
                mCurrentShape = Shape.Circle;
                break;
        }
        invalidate();
    }

    /**
     * 获得当前形状
     */
    public Shape getCurrentShape() {
        return mCurrentShape;
    }

}

<color name="triangle">#aa72d572</color>
<color name="circle">#aa738ffe</color>
<color name="rect">#aae84e40</color>

分析布局有三个部分:shapeView+View+TextView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:background="#FFFFFF"
    android:gravity="center"
    android:layout_height="match_parent">

    <com.hbwj.a14_58.ShapeView
        android:id="@+id/shape_view"
        android:layout_width="25dp"
        android:layout_marginBottom="82dp"
        android:layout_height="25dp" />

    <View
        android:id="@+id/shadow_view"
        android:background="@drawable/loading_shadow_bg"
        android:layout_width="25dp"
        android:layout_height="3dp"/>

    <TextView
        android:layout_marginTop="5dp"
        android:layout_width="wrap_content"
        android:text="玩命加载中..."
        android:layout_height="wrap_content" />

</LinearLayout>

activity_main主布局直接使用即可

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:onClick="start"
        android:layout_centerInParent="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.hbwj.a14_58.LoadingView
        android:id="@+id/loading_view"
        android:onClick="click"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

自定义view继承LinearLayout,实现动画效果

public class LoadingView extends LinearLayout {
    private View mShadeView;//阴影
    private ShapeView mShapeView;//形状
    private int mTranslationDistance = 0;
    // 动画执行的时间
    private final long ANIMATOR_DURATION = 350;
    private boolean mIsStopAnimation=false;

    public LoadingView(Context context) {
        this(context, null);
    }

    public LoadingView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mTranslationDistance = dp2x(80);
        initLayout();
    }

    private int dp2x(int dpValue) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, getResources().getDisplayMetrics());
    }

    private void initLayout() {
        // 1. 记载写好的 ui_loading_view
    /*    //1.1实例化view
        View view = inflate(getContext(), R.layout.ui_loading_view, null);
        // 1.2 添加到该View
        addView(view);*/
        //将ui_loading_view布局加载到改布局中
        inflate(getContext(), R.layout.ui_loading_view, this);
        mShadeView = findViewById(R.id.shadow_view);
        mShapeView = (ShapeView) findViewById(R.id.shape_view);
        post(new Runnable() {
            @Override
            public void run() {
                // onResume 之后View绘制流程执行完毕之后(View的绘制流程源码分析那一章)
                startFallAnimator();
            }
        });
        // onCreate() 方法中执行 ,布局文件解析 反射创建实例
        //startFallAnimator();
    }

    /**
     * 开始下落动画
     */
    private void startFallAnimator() {
        if(mIsStopAnimation){
            return;
        }
        //设置mShapeView的位移动画
        ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(mShapeView, "translationY", 0, mTranslationDistance);
        //设置mShadeView的透明度变化
        ObjectAnimator scaleAnimation = ObjectAnimator.ofFloat(mShadeView, "scaleX", 1f, 0.3f);
        AnimatorSet animationSet = new AnimatorSet();
        animationSet.setDuration(ANIMATOR_DURATION);//设置时长
        animationSet.playTogether(translationAnimator, scaleAnimation);//两个动画一起播放
        //有序播放
        //animationSet.playSequentially(translationAnimator,scaleAnimation);
        animationSet.setInterpolator(new AccelerateInterpolator());//加速
        animationSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                //下落完毕后,上抛
                startUpAnimation();
            }
        });
        animationSet.start();
    }

    /**
     * 开始上抛
     */
    private void startUpAnimation() {
        if(mIsStopAnimation){
            return;
        }
        Log.e("TAG", "startUpAnimation");
        //设置mShapeView的位移动画
        ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(mShapeView, "translationY", mTranslationDistance, 0);
        //设置mShadeView的透明度变化
        ObjectAnimator scaleAnimation = ObjectAnimator.ofFloat(mShadeView, "scaleX", 0.3f, 1f);
        AnimatorSet animationSet = new AnimatorSet();
        animationSet.setDuration(ANIMATOR_DURATION);//设置时长
        animationSet.playTogether(translationAnimator, scaleAnimation);//两个动画一起播放
        //有序播放
        //animationSet.playSequentially(translationAnimator,scaleAnimation);
        animationSet.setInterpolator(new DecelerateInterpolator());//减速
        animationSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                //上抛完毕后,下落
                startFallAnimator();
            }

            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                //旋转
                startRotationAnimator();
                //改变形状
                mShapeView.exchange();
            }
        });
        animationSet.start();
    }

    /**
     * 旋转动画
     */
    private void startRotationAnimator() {
        ObjectAnimator rotationAnimator = null;
        switch (mShapeView.getCurrentShape()) {
            case Circle:
            case Square://旋转180度
                rotationAnimator = ObjectAnimator.ofFloat(mShapeView, "rotation", 0, 180);
                break;
            case Triangle:
                rotationAnimator = ObjectAnimator.ofFloat(mShapeView, "rotation", 0, -120);
                break;
        }
        rotationAnimator.setDuration(ANIMATOR_DURATION);
        rotationAnimator.setInterpolator(new DecelerateInterpolator());
        rotationAnimator.start();
    }
    //当后台数据返回的时候我们要把当前页面,设置成 gone (隐藏),只是用代码设置为了
    // 隐藏,但是动画View的内存还在跑

    @Override
    public void setVisibility(int visibility) {
        super.setVisibility(INVISIBLE);// 不要再去排放和计算,少走一些系统的源码
        //清理所有动画
        mShapeView.clearAnimation();
        mShadeView.clearAnimation();
        //移除父布局
        ViewGroup parent = (ViewGroup) getParent();

        if (parent != null) {
            parent.removeView(this);//父布局中移除当前view
            removeAllViews();//移除自己的所有view
        }
        //此时上诉步骤完成,内存中有所以还是在运行
        mIsStopAnimation=true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值