动画

动画

2019-12-29  本文已影响0人  匠人plus

Android中的动画主要分为补间动画、帧动画和属性动画。

1.补间动画与帧动画都是canvas对matrix的操作,所以并没有改变view的实际属性。

补间动画主要有:
AlphaAnimation、TranslateAnimation、ScaleAnimation、RotateAnimation
以下是一个demo的效果图:


ezgif.com-video-to-gif.gif

以下是示例代码:

public class AnimView extends View{
    private AnimationSet animationSet;
    public AnimView(Context context) {
        super(context);
        init();
    }

    public AnimView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public AnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public AnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    // 透明度动画
    public Animation alpha() {
        AlphaAnimation alphaAnimation = new AlphaAnimation(0.2f, 1);
        alphaAnimation.setDuration(3000);// 每次动画持续时间3秒
        alphaAnimation.setFillAfter(true);// 动画最后是否停留在终止的状态
        alphaAnimation.setRepeatCount(3);// 动画重复的次数
        alphaAnimation.setRepeatMode(Animation.REVERSE);// REVERSE: 反转模式
        // RESTART:重新开始
        // 动画监听
        alphaAnimation.setAnimationListener(new Animation.AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
                Log.e("alphaAnimation","动画开始回调");
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                Log.e("alphaAnimation","动画重复回调");

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                Log.e("alphaAnimation","动画结束回调");


            }
        });
        return alphaAnimation;
    }
    public Animation translate() {
        TranslateAnimation translateAnimation = new TranslateAnimation(
                Animation.ABSOLUTE,
                this.getWidth(), // 当前屏幕密度 :240 标准的屏幕密度:160 则dp转px :
                // px=dp*240/160
                Animation.ABSOLUTE, this.getWidth(),
                Animation.ABSOLUTE, 0,
                Animation.RELATIVE_TO_SELF, 1);
        translateAnimation.setDuration(3000);// 每次动画持续时间3秒
        translateAnimation.setFillAfter(true);// 动画最后停留在终止的状态
        translateAnimation.setRepeatCount(3);// 动画重复的次数
        translateAnimation.setRepeatMode(Animation.REVERSE);// REVERSE: 反转模式
        // RESTART:重新开始
        translateAnimation.setInterpolator(new BounceInterpolator());// 设置特效,弹簧效果
        return translateAnimation;
    }

    public Animation scale() {
        ScaleAnimation scaleAnimation =new ScaleAnimation
                (0, 2, 0, 2, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation.setDuration(3000);// 每次动画持续时间3秒
        scaleAnimation.setFillAfter(true);// 动画最后停留在终止的状态
        scaleAnimation.setRepeatCount(1);// 动画重复的次数
        this.startAnimation(scaleAnimation);
        return scaleAnimation;
    }
    public Animation rotate() {
        RotateAnimation rotateAnimation =new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        LinearInterpolator lin = new LinearInterpolator();
        rotateAnimation.setInterpolator(lin);
        rotateAnimation.setDuration(1500);//设置动画持续时间
        rotateAnimation.setRepeatCount(5);//设置重复次数
        rotateAnimation.setFillAfter(true);//动画执行完后是否停留在执行完的状态
        rotateAnimation.setStartOffset(10);//执行前的等待时间
        return rotateAnimation;
    }

    public void execAnim(){
        animationSet=new AnimationSet(false);
        animationSet.addAnimation(alpha());
        animationSet.addAnimation(translate());
        animationSet.addAnimation(scale());
        animationSet.addAnimation(rotate());
        //设置动画结束之后是否保持动画的目标状态
        animationSet.setFillAfter(false);
        //设置动画结束之后是否保持动画开始时的状态
        animationSet.setFillBefore(true);
        this.startAnimation(animationSet);
    }
    private void init(){
        this.setBackgroundColor(Color.RED);
        execAnim();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (animationSet!=null){
            animationSet.cancel();
            animationSet.reset();
        }
    }
}

2.属性动画是通过设置view的属性,不断刷新视图实现的,所以属性动画实际改变了view的属性。可以通过属性动画改变view的宽、高、透明度等,以及其他自定义属性

属性动画主要有:ValueAnimator、ObjectAnimator

ValueAnimator是属性动画框架的基础,它实现了动画相关的接口,
ObjectAnimator继承自ValueAnimator,它将Object与动画绑定,可以方便的对某些属性进行改变,以达到快速实现动画效果的目的。
以下是属性动画两个重要的方法,

setInterpolator//设置插值器,用于模拟动画的自然进度

Interpolator实现TimeInterpolator接口,
主要有以下实现类
AccelerateDecelerateInterpolator、AccelerateInterpolator、
DecelerateInterpolator、LinearInterpolator、BounceInterpolator、
AnticipateInterpolator、OvershootInterpolator、AnticipateOvershootInterpolator、CycleInterpolator。

setEvaluator//设置估值器,用于修改动画的轨迹

Evaluator实现TypeEvaluator接口,
主要实现类IntEvaluator、FloatEvaluator、ArgbEvalutor
ArgbEvalutor可以方便的实现颜色值过渡转换。

以下例子通过LoopTextView,展示ObjectAnimator的常规用法。


public class LoopTextView extends RelativeLayout {
    private Context context;
    private MyTextView textView1;
    private MyTextView textView2;

    private List<String> dataList;
    private AnimatorSet animSet;
    private boolean circleAnim = true;
    private int animPos = 0;
    private int viewHeight = 0;
    private int repeatTimes = ValueAnimator.INFINITE;
    private int repeatCount = 0;

    public LoopTextView(Context context) {
        super(context);
        initView(context);
    }

    public LoopTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public LoopTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    public LoopTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView(context);
    }

    private void initView(Context context) {
        this.context = context;
        textView1 = new MyTextView(context);
        addView(textView1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        textView2 = new MyTextView(context);
        addView(textView2, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        textView1.setGravity(Gravity.CENTER);
        textView2.setGravity(Gravity.CENTER);
        textView1.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
        textView2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
//        textView1.setBackgroundColor(Color.RED);
//        textView2.setBackgroundColor(Color.BLUE);
    }

    public void setDataList(List<String> stringList) {
        this.dataList = stringList;

    }

    public void setCircleTimes(int repeatTimes) {
        this.repeatTimes = repeatTimes;
    }

    private void initAnim() {
        if (dataList == null || dataList.size() == 0) {
            return;
        }

//        ObjectAnimator anim1 = ObjectAnimator.ofFloat(textView1, View.TRANSLATION_Y, 0.0f, -1.0f * viewHeight);
//        ObjectAnimator anim2 = ObjectAnimator.ofFloat(textView2, View.TRANSLATION_Y, 1.0f * viewHeight, 0.0f);
        final ObjectAnimator anim1 = ObjectAnimator.ofInt(textView1, "MyTranslationY", 0, -1 * viewHeight);
        ObjectAnimator anim2 = ObjectAnimator.ofInt(textView2, "MyTranslationY", 1 * viewHeight, 0);
        anim1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Object value = animation.getAnimatedValue();
//                Log.e("anim1Update", value + "");
            }
        });
        anim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Object value = animation.getAnimatedValue();
//                Log.e("anim2Update", value + "");
            }
        });
        animSet = new AnimatorSet();
        animSet.setDuration(2000);
        animSet.setInterpolator(new AccelerateDecelerateInterpolator());
        //两个动画同时执行
        animSet.playTogether(anim1, anim2);
        animSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {

                if (circleAnim) {
                    repeatCount = (animPos + 1) / (dataList.size() - 1);
                    if (repeatCount != repeatTimes) {

                        postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                ++animPos;
                                circleTextAnim();
                            }
                        }, 300);
                    } else {
                        Toast.makeText(getContext(), "anim finish", Toast.LENGTH_SHORT).show();
                    }

                }
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
        circleTextAnim();
    }

    private void print() {
    }

    private void circleTextAnim() {
        circleAnim = true;

        textView1.setText(dataList.get(animPos % dataList.size()));
        textView2.setText(dataList.get((animPos + 1) % dataList.size()));
        textView1.setEachCharRandomTextColor();
        textView2.setShowLinearGradient(true);
        animSet.start();

    }

    public void cancelTextAnim() {
        circleAnim = false;
        animSet.cancel();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        cancelTextAnim();
    }

    @Override
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        return super.drawChild(canvas, child, drawingTime);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        Log.e("onSizeChanged", h + "");
        viewHeight = h;
        initAnim();
    }


    @SuppressLint("AppCompatCustomView")
    class MyTextView extends TextView {

        private Paint mPaint;
        private int mViewWidth;
        private LinearGradient mLinearGradient;
        private Matrix mGradientMatrix;
        private int mTransalte;


        Random random = new Random();

        private boolean showLinearGradient;


        private Timer timer;

        public MyTextView(Context context) {
            super(context);
        }

        public MyTextView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }

        public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }

        public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }

        public void setMyTranslationY(int translationY) {
            super.setTranslationY(translationY);
        }


        public float getMyTranslationY() {
            return super.getTranslationY();
        }

        public void setRandomTextColor() {
            setTextColor(getRandomTextColor());
        }

        public int getRandomTextColor() {
            return random.nextInt(0xffffff + 1) + 0xff000000;
        }

        public void setEachCharRandomTextColor() {
            SpannableString span = new SpannableString(getText());
            for (int i = 0; i < getText().length(); i++) {
                span.setSpan(new ForegroundColorSpan(getRandomTextColor()), i, i + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
            }

            setText(span);
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            if (mViewWidth == 0) {
                mViewWidth = getMeasuredWidth();
                if (if (showLinearGradient && mViewWidth > 0) {
                    mPaint = getPaint();//获得当前绘制的Paint对象
                    mLinearGradient = new LinearGradient(
                            0,//渐变起始点x坐标
                            0,//渐变起始点y坐标
                            mViewWidth,//渐变结束点x点坐标
                            0,//渐变结束点y坐标
                            new int[]{
                                    Color.RED, 0xffffffff,
                                    Color.BLUE, Color.RED, Color.YELLOW},//颜色的int数组
                            null,//相对位置的颜色数组,可为null, 若为null,可为null,颜色沿渐变线均匀分布
                            Shader.TileMode.MIRROR);//REPEAT
                    mPaint.setShader(mLinearGradient);//给这个paint设置linearFradient属性
                    mGradientMatrix = new Matrix();
                    drawMatrix();
                }
            }
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (showLinearGradient && mGradientMatrix != null) {
                mTransalte += mViewWidth / 5;
                if (mTransalte > 2 * mViewWidth) {
                    mTransalte -= mViewWidth;
                }
                mGradientMatrix.setTranslate(mTransalte, 0);
                mLinearGradient.setLocalMatrix(mGradientMatrix);//通过矩阵的方式不断平移产生渐变效果
            }
        }

        private void drawMatrix() {


            if (showLinearGradient && mGradientMatrix != null) {
                if (timer != null) {
                    timer.cancel();
                    timer = null;
                }
                timer = new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        post(new Runnable() {
                            @Override
                            public void run() {
                                invalidate();
                            }
                        });
                    }
                },0,100);


            }
        }

        public void setShowLinearGradient(boolean showLinearGradient) {
            this.showLinearGradient = showLinearGradient;
        }

        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            if (timer != null) {
                timer.cancel();
                timer = null;
            }
        }
    }

}

调用方法:

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

    <com.test.anim.LoopTextView
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:id="@+id/looptv"
        android:background="@android:color/holo_green_light"></com.test.anim.LoopTextView>
    <com.test.anim.AnimView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"/>
</RelativeLayout>

LoopTextView looptv = findViewById(R.id.looptv);
        List<String> data = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            data.add("this is"+i);
        }

        looptv.setDataList(data);
//        looptv.setCircleTimes(1);
上一篇 下一篇

猜你喜欢

热点阅读