Android中的动画和原理(帧动画和补间动画)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/androidxiaogang/article/details/80188372

1、Android中的动画分类

Android中的动画可以分为三类:帧动画,补间动画,和属性动画

动画分类 说明
帧动画 通过不停的播放图片产生的动画效果
补间动画 对View的平移,旋转,缩放,透明产生效果
属性动画 动态的改变属性产生动画效果

2、帧动画及其原理

原理

帧动画是按照一定的顺序播放一系列图片,从而产生动画。和我们看的动漫原理是一样的,本质上是对图片快速的翻页产生动的效果。

帧动画依赖于图片。
这里写图片描述

示例代码:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/rocket_thrust1" android:duration="100" />
    <item android:drawable="@drawable/rocket_thrust2" android:duration="100" />
    <item android:drawable="@drawable/rocket_thrust3" android:duration="100" />
</animation-list>

调用

public class MainActivity extends AppCompatActivity {
    AnimationDrawable rocketAnimation;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ImageView animationImg = (ImageView) findViewById(R.id.imageView);
        animationImg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                animationImg.setImageResource(R.drawable.play);
                AnimationDrawable animationDrawable1 = (AnimationDrawable) animationImg.getDrawable();
                animationDrawable1.setOneShot(true);
                animationDrawable1.start();
            }
        });
    }
}

3、补间动画及其原理

原理

补间动画的原理是对通过对View的平移,缩放,旋转和透明的操作,从而产生的动画。
注意:补间动画只调整View在Canvas上显示,并没有真实的改变View原来的位置,因此它的点击和触摸事件还保留在没有经过动画前的位置。

动画 说明
平移 移动View的位置 TranslateAnimation
缩放 对View的缩放 ScaleAnimation
旋转 对View的旋转 RotateAnimation
透明 改变View的透明度 AlphaAnimation
<?xml version="1.0" encoding= "utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true">
    <alpha
        android:duration="3000"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
    <scale
        android:duration="3000"
        android:fromXScale="0.0"
        android:fromYScale="0.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.0"
        android:toYScale="1.0" />
    <rotate
        android:duration="3000"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="720" />
    <translate
        android:duration="1000"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:startOffset="3000"
        android:toXDelta="85"
        android:toYDelta="0" />
</set>

补间动画既可以在xml文件中配置,也可以用Java代码实现:

public class MainActivity extends AppCompatActivity {
    private ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.imageView);
        TranslateAnimation translateAnim = new TranslateAnimation(0, 200, 0, 200);
        translateAnim.setDuration(3000);
        translateAnim.setFillAfter(true);
        imageView.startAnimation(translateAnim);
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //经过平移后的View不相应点击事件,点击事件仍然在没有移动前。
                Toast.makeText(MainActivity.this, "123", Toast.LENGTH_SHORT).show();
            }
        });


    }
}

原理

1、调用View的startAnimation()方法出发动画事件。

public void startAnimation(Animation animation) {
        animation.setStartTime(Animation.START_ON_FIRST_FRAME);
        setAnimation(animation);
        invalidateParentCaches();
        invalidate(true);
    }

在这个方法中,调用invalidate(true),触发调用draw()方法,对view进行重新绘制

2、draw()方法解析
把当前画布中View放置于矩阵中,然后通过矩阵变换对View在画布中影像进行改变。

Transformation 定义的矩阵对象

 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
        ...

        if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) {
            parent.getChildTransformation().clear();
            parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION;
        }
        ...
        //矩阵,把当前的View放置到矩阵中
        Transformation transformToApply = null;
        //对View进行平移,旋转,缩放,透明等事件处理
        if (transformToApply != null
                || alpha < 1
                || !hasIdentityMatrix()
                || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {
            if (transformToApply != null || !childHasIdentityMatrix) {
                int transX = 0;
                int transY = 0;

                if (offsetForScroll) {
                    transX = -sx;
                    transY = -sy;
                }

                if (transformToApply != null) {
                    if (concatMatrix) {
                        if (drawingWithRenderNode) {
                            renderNode.setAnimationMatrix(transformToApply.getMatrix());
                        } else {
                            // Undo the scroll translation, apply the transformation matrix,
                            // then redo the scroll translate to get the correct result.
                            canvas.translate(-transX, -transY);
                            canvas.concat(transformToApply.getMatrix());
                            canvas.translate(transX, transY);
                        }
                        parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                    }

                    float transformAlpha = transformToApply.getAlpha();
                    if (transformAlpha < 1) {
                        alpha *= transformAlpha;
                        parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                    }
                }

                if (!childHasIdentityMatrix && !drawingWithRenderNode) {
                    canvas.translate(-transX, -transY);
                    canvas.concat(getMatrix());
                    canvas.translate(transX, transY);
                }
            }

            // Deal with alpha if it is or used to be <1
            if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {
                if (alpha < 1) {
                    mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA;
                } else {
                    mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA;
                }
                parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                if (!drawingWithDrawingCache) {
                    final int multipliedAlpha = (int) (255 * alpha);
                    if (!onSetAlpha(multipliedAlpha)) {
                        if (drawingWithRenderNode) {
                            renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha());
                        } else if (layerType == LAYER_TYPE_NONE) {
                            canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(),
                                    multipliedAlpha);
                        }
                    } else {
                        // Alpha is handled by the child directly, clobber the layer's alpha
                        mPrivateFlags |= PFLAG_ALPHA_SET;
                    }
                }
            }
        } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {
            onSetAlpha(255);
            mPrivateFlags &= ~PFLAG_ALPHA_SET;
        }

        if (!drawingWithRenderNode) {
            // apply clips directly, since RenderNode won't do it for this draw
            if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) {
                if (offsetForScroll) {
                    canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight());
                } else {
                    if (!scalingRequired || cache == null) {
                        canvas.clipRect(0, 0, getWidth(), getHeight());
                    } else {
                        canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
                    }
                }
            }

            if (mClipBounds != null) {
                // clip bounds ignore scroll
                canvas.clipRect(mClipBounds);
            }
        }

        ...

        return more;
    }

参考:
https://blog.csdn.net/mr_liabill/article/details/49510485

展开阅读全文

没有更多推荐了,返回首页