• Android中的动画详解系列【3】——自定义动画研究


    在上一篇中我们使用到了位移动画TranslateAnimation,下面我们先来看看TranslateAnimation是如何实现Animation中的抽象方法的:

    /*
     * Copyright (C) 2006 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package android.view.animation;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.util.AttributeSet;
    
    /**
     * An animation that controls the position of an object. See the
     * {@link android.view.animation full package} description for details and
     * sample code.
     * 
     */
    public class TranslateAnimation extends Animation {
        private int mFromXType = ABSOLUTE;
        private int mToXType = ABSOLUTE;
    
        private int mFromYType = ABSOLUTE;
        private int mToYType = ABSOLUTE;
    
        private float mFromXValue = 0.0f;
        private float mToXValue = 0.0f;
    
        private float mFromYValue = 0.0f;
        private float mToYValue = 0.0f;
    
        private float mFromXDelta;
        private float mToXDelta;
        private float mFromYDelta;
        private float mToYDelta;
    
        /**
         * Constructor used when a TranslateAnimation is loaded from a resource.
         * 
         * @param context Application context to use
         * @param attrs Attribute set from which to read values
         */
        public TranslateAnimation(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            TypedArray a = context.obtainStyledAttributes(attrs,
                    com.android.internal.R.styleable.TranslateAnimation);
    
            Description d = Description.parseValue(a.peekValue(
                com.android.internal.R.styleable.TranslateAnimation_fromXDelta));
            mFromXType = d.type;
            mFromXValue = d.value;
    
            d = Description.parseValue(a.peekValue(
                    com.android.internal.R.styleable.TranslateAnimation_toXDelta));
            mToXType = d.type;
            mToXValue = d.value;
    
            d = Description.parseValue(a.peekValue(
                com.android.internal.R.styleable.TranslateAnimation_fromYDelta));
            mFromYType = d.type;
            mFromYValue = d.value;
    
            d = Description.parseValue(a.peekValue(
                com.android.internal.R.styleable.TranslateAnimation_toYDelta));
            mToYType = d.type;
            mToYValue = d.value;
    
            a.recycle();
        }
    
        /**
         * Constructor to use when building a TranslateAnimation from code
         * 
         * @param fromXDelta Change in X coordinate to apply at the start of the
         *        animation
         * @param toXDelta Change in X coordinate to apply at the end of the
         *        animation
         * @param fromYDelta Change in Y coordinate to apply at the start of the
         *        animation
         * @param toYDelta Change in Y coordinate to apply at the end of the
         *        animation
         */
        public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta) {
            mFromXValue = fromXDelta;
            mToXValue = toXDelta;
            mFromYValue = fromYDelta;
            mToYValue = toYDelta;
    
            mFromXType = ABSOLUTE;
            mToXType = ABSOLUTE;
            mFromYType = ABSOLUTE;
            mToYType = ABSOLUTE;
        }
    
        /**
         * Constructor to use when building a TranslateAnimation from code
         * 
         * @param fromXType Specifies how fromXValue should be interpreted. One of
         *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
         *        Animation.RELATIVE_TO_PARENT.
         * @param fromXValue Change in X coordinate to apply at the start of the
         *        animation. This value can either be an absolute number if fromXType
         *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
         * @param toXType Specifies how toXValue should be interpreted. One of
         *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
         *        Animation.RELATIVE_TO_PARENT.
         * @param toXValue Change in X coordinate to apply at the end of the
         *        animation. This value can either be an absolute number if toXType
         *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
         * @param fromYType Specifies how fromYValue should be interpreted. One of
         *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
         *        Animation.RELATIVE_TO_PARENT.
         * @param fromYValue Change in Y coordinate to apply at the start of the
         *        animation. This value can either be an absolute number if fromYType
         *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
         * @param toYType Specifies how toYValue should be interpreted. One of
         *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
         *        Animation.RELATIVE_TO_PARENT.
         * @param toYValue Change in Y coordinate to apply at the end of the
         *        animation. This value can either be an absolute number if toYType
         *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
         */
        public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
                int fromYType, float fromYValue, int toYType, float toYValue) {
    
            mFromXValue = fromXValue;
            mToXValue = toXValue;
            mFromYValue = fromYValue;
            mToYValue = toYValue;
    
            mFromXType = fromXType;
            mToXType = toXType;
            mFromYType = fromYType;
            mToYType = toYType;
        }
    
    
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            float dx = mFromXDelta;
            float dy = mFromYDelta;
            if (mFromXDelta != mToXDelta) {
                dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
            }
            if (mFromYDelta != mToYDelta) {
                dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
            }
            t.getMatrix().setTranslate(dx, dy);
        }
    
        @Override
        public void initialize(int width, int height, int parentWidth, int parentHeight) {
            super.initialize(width, height, parentWidth, parentHeight);
            mFromXDelta = resolveSize(mFromXType, mFromXValue, width, parentWidth);
            mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth);
            mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight);
            mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight);
        }
    
    可以看到实际上重写了两个方法:initialize和applyTransformation
        /**
         * Initialize this animation with the dimensions of the object being
         * animated as well as the objects parents. (This is to support animation
         * sizes being specifed relative to these dimensions.)
         *
         * <p>Objects that interpret Animations should call this method when
         * the sizes of the object being animated and its parent are known, and
         * before calling {@link #getTransformation}.
         *
         *
         * @param width Width of the object being animated
         * @param height Height of the object being animated
         * @param parentWidth Width of the animated object's parent
         * @param parentHeight Height of the animated object's parent
         */
        public void initialize(int width, int height, int parentWidth, int parentHeight) {
            reset();
            mInitialized = true;
        }
        /**
         * Helper for getTransformation. Subclasses should implement this to apply
         * their transforms given an interpolation value.  Implementations of this
         * method should always replace the specified Transformation or document
         * they are doing otherwise.
         * 
         * @param interpolatedTime The value of the normalized time (0.0 to 1.0)
         *        after it has been run through the interpolation function.
         * @param t The Transofrmation object to fill in with the current
         *        transforms.
         */
        protected void applyTransformation(float interpolatedTime, Transformation t) {
        }
    从initialize方法的注释上看,这个方法的主要作用是:初始化对象的尺寸以及父容器尺寸(为了确定和父容器的相对位置)。

    从applyTransformation方法的注释上看,这个方法应该被实现,这个方法给出了一个interpolation值,并帮助获得Transformation对象,应该自己设置transformation对象来实现自己的动画效果。

    好吧,基于以上研究,我们试着来重写一个Animation

    package com.example.testanimation;
    
    import android.graphics.Camera;
    import android.graphics.Matrix;
    import android.view.animation.Animation;
    import android.view.animation.LinearInterpolator;
    import android.view.animation.Transformation;
    
    /**
     * 自定义动画
     * @author 阳光小强
     *
     */
    public class MyAnimation extends Animation{
    	
    	private float centerX;
    	private float centerY;
    	private int duration;
    	private Camera camera = new Camera();
    	public MyAnimation(float x, float y, int duration){
    		this.centerX = x;
    		this.centerY = y;
    		this.duration = duration;
    	}
    	
    	@Override
    	public void initialize(int width, int height, int parentWidth,
    			int parentHeight) {
    		super.initialize(width, height, parentWidth, parentHeight);
    		
    		setDuration(duration);
    		
    		setFillAfter(true);
    		
    		setInterpolator(new LinearInterpolator());
    	}
    	
    	@Override
    	protected void applyTransformation(float interpolatedTime, Transformation t) {
    		camera.save();
    		camera.translate(100f - 100f * interpolatedTime, 150f * interpolatedTime -150, 80f - 80f * interpolatedTime);
    		camera.rotateY(360 * interpolatedTime);
    		camera.rotateX(360 * interpolatedTime);
    		Matrix matrix = t.getMatrix();
    		camera.getMatrix(matrix);
    		matrix.preTranslate(-centerX,  -centerY);
    		matrix.postTranslate(centerX, centerY);
    		camera.restore();	
    	}
    }
    
    代码解释:

    1、setDuration(duration):设置动画时间

    2、setFillAfter(true):设置动画结束后保持,如果设为false则动画结束后回到原来状态。

    3、setInterpolator(new LinearInterpolator()):Interpolater实际上是控制补间动画的插入帧的频率的,所以就会有加速、减速、匀速动画。

    4、Camera:一个空间变换工具,类似于Matrix,提供了各种变换方法,如上面的translate和rotateY等。

    5、Matrix:一个三维的矩阵变换函数。

    6、camera.getMatrix(matrix):计算当前的矩阵变换,并将其复制到矩阵matrix中。

    7、matrix.preTranslate :执行矩阵指定的转换。

    8、matrix.postTranslate:执行矩阵指定的转换(后面两个方法怎么转换,有什么区别,这就是数学知识了,一两句也说不清)。





  • 相关阅读:
    求树中两个节点的最低公共祖先
    [2014校招笔试]判断单链表是否有环?
    二叉树的遍历
    求所有划分集合
    用rand5()生成rand(n)
    由等概率生成的0和1构建rand()函数
    等概率生成0和1
    求输出和为n的所有连续自然数序列
    求正整数n的所有因子
    css 2D转换总结
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6469024.html
Copyright © 2020-2023  润新知