zoukankan      html  css  js  c++  java
  • android自定义动画

    前一篇说了实现过程,这次来写一个自己简单实现的3d动画

    先来属性声明配置,方便使用xml 文件来定制动画

    <!-- 有些类型其实是没必要的,只是实例代码,为了更具有代表性 -->
         <declare-styleable name="CubeAnimation">
             <attr name="fromX" format="dimension|fraction|float"/> 
             <attr name="toX" format="dimension|fraction|float"/> 
             <attr name="fromDegree" format="float"/> 
             <attr name="toDegree" format="float"/> 
             <attr name="axisY" format="float|integer"/> 
             <attr name="positive" format="boolean"/> 
         </declare-styleable>

    配置参数相关的一些解释

      dimension 像素值类型,包括有"px", "dip", "sp", "pt", "in", "mm", 一般用TypedValue.complexToDimension解析
      fraction 分数,一般用来表示占的百分比,"%", "%p"。 一般用TypedValue.complexToFraction解析 有时候和float类型功能通用
      float 浮点数。当确定是这个类型的时候,用TypedValue.getFloat解析
      integer 整数,TypedValue.data 就是这个值。
      后两者,如果参数只有确定的一个类型,直接用TypedArray 的 getInteger 或者 getFloat方法就可以获取

    动画配置

    <!-- 命名空间神马的就不说了 -->
    <?xml version="1.0" encoding="utf-8"?>
    <cube 
        xmlns:android="http://schemas.android.com/apk/res/android" 
           xmlns:cs="http://schemas.android.com/apk/res/com.example.testwifi"
        android:duration="2000"
        android:repeatCount="5"
        cs:fromDegree="0"
        cs:toDegree="1440"
        cs:fromX="50"
        cs:toX="90%p"
        cs:axisY="0.5"
        cs:positive="true"/>

    含在集合内的动画配置

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android" 
         xmlns:cs="http://schemas.android.com/apk/res/com.example.testwifi">
        <cube 
            cs:fromDegree="0"
            cs:toDegree="1440"
            cs:fromX="50"
            cs:toX="90%p"
            cs:axisY="0.5"
            cs:positive="true/>
        <scale
            android:interpolator="@android:anim/accelerate_decelerate_interpolator"
            android:fromXScale="1.0"
            android:toXScale="1.4"
            android:fromYScale="1.0"
            android:toYScale="0.6"
            android:pivotX="50%"
            android:pivotY="50%"
            android:fillAfter="false"
            android:duration="700" />
    </set> 

    动画类的代码

    public class CubeAnimation extends Animation {
        
        private float mFromDegrees;
        private float mToDegrees;
        
        private int mFromXType = ABSOLUTE;;
        private float mFromX = 0;
        private int mFromXdata = 0;
        
        private int mToXType = ABSOLUTE;
        private float mToX = 0;
        private int mToXData = 0;
        
        private Camera mCamera;
        private Resources mResources;
        private float mAxisY = 0;
        private int mAxisYType = ABSOLUTE;
        
        public CubeAnimation(float fromX,float toX,float fromDegree,float toDegree,float axisY) {
            this.mFromX = fromX;
            this.mToX = toX;
            this.mFromDegrees = fromDegree;
            this.mToDegrees = toDegree;
            this.mAxisY = axisY;
            
            mFromXType = TypedValue.TYPE_FLOAT;
            mToXType = TypedValue.TYPE_FLOAT;
            mAxisYType = ABSOLUTE;
            
        }
        public CubeAnimation(Context context, AttributeSet attrs) {
            super(context, attrs);
            TypedArray a = context.obtainStyledAttributes(attrs,
                    R.styleable.CubeAnimation);
            mResources = context.getResources();
            TypedValue value = a.peekValue(R.styleable.CubeAnimation_fromX);
            if(value.type==TypedValue.TYPE_FLOAT){
                this.mFromX = value.getFloat();
                this.mFromXType = value.type;
            }else{
                this.mFromXType = value.type;
                this.mFromXdata = value.data;
            }
            
            value = a.peekValue(R.styleable.CubeAnimation_toX);
            if(value.type==TypedValue.TYPE_FLOAT){//FLOAT 类型的,必须在这里解析了,因为下边的resolveData 方法拿不到TypedValue,没法解析
                this.mToX = value.getFloat();
                this.mToXType = value.type;
            }else{
                this.mToXType = value.type;
                this.mToXData = value.data;
            }
            boolean t = a.getBoolean(R.styleable.CubeAnimation_positive, true);
            if (!(t)) {
                this.mToDegrees = 0.0F;
                this.mFromDegrees = 90.0F;
            }
            this.mFromDegrees = a.getFloat(R.styleable.CubeAnimation_fromDegree, 0);
            this.mToDegrees = a.getFloat(R.styleable.CubeAnimation_toDegree, 90);
            
            value = a.peekValue(R.styleable.CubeAnimation_axisY);
            this.mAxisYType = value.type;
            //参数不同类型用来做什么用,按自己需求来设定和解析,我这里配置文件属性要求是两种 <attr name="axisY" format="float|integer"/>
            //如果是float类型,则做用来做组件的比例   如果是int型,认为是像素值
            if(this.mAxisYType==TypedValue.TYPE_FLOAT){
                this.mAxisY = value.getFloat();
                this.mAxisYType = RELATIVE_TO_SELF;
            }else{
                this.mAxisY = value.data;
            }
            a.recycle();
        }
        
        public void initialize(int width, int height, int parentWidth,
                int parentHeight) {
            super.initialize(width, height, parentWidth, parentHeight);
            if(this.mFromXType!=TypedValue.TYPE_FLOAT){//这里Float类型代表固定值,且已经解析过,不再解析 下同
                this.mFromX = resolveData(this.mFromXType,this.mFromXdata, width,
                        parentWidth);
            }
            if(mToXType!=TypedValue.TYPE_FLOAT){
                this.mToX = resolveData(this.mToXType,this.mToXData,width,parentWidth);
            }
            this.mCamera = new Camera();
            
            if(mAxisYType==RELATIVE_TO_SELF) {//如果是相对自身的大小比例,则按比例计算获取对应值。否则,则为固定像素值
                mAxisY = mAxisY*height;
            }
            System.out.println("mFromX="+mFromX+",mToX=="+mToX);
        }
        float resolveData( int type, int data, int size, int psize) {
            float value = 0;
            if (type == TypedValue.TYPE_FRACTION) {
                value = TypedValue.complexToFraction(data, size, psize);
            } else if (type == TypedValue.TYPE_DIMENSION) {
                value = TypedValue.complexToDimension(data, mResources.getDisplayMetrics());
            } else{//如果是由代码设置成的ABSOLUTE类型或者 配置文件本身就是int的固定值
                value= data;
            }
            return value;
        }
        
        
        // 自定义动画主要要实现的方法
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            float fromDegrees = this.mFromDegrees;
            float degrees = fromDegrees + (this.mToDegrees - fromDegrees)
                    * interpolatedTime;
    
            Camera camera = this.mCamera;
    
            Matrix matrix = t.getMatrix();
    
            camera.save();
            camera.rotateX(degrees);
            
            camera.getMatrix(matrix);
            camera.restore();
            
            
            matrix.postTranslate(mFromX+(mToX-mFromX)*interpolatedTime, this.mAxisY);
    
        }
    
        // 因为用AnimationUtils无法解析出这个动画的属性,所以所有CubeAnimation的配置文件或者包含这个动画的set配置文件,必须用这个方法加载
        public static Animation loadAnimation(Context context, int id)
                throws NotFoundException {
    
            XmlResourceParser parser = null;
            try {
                parser = context.getResources().getAnimation(id);
                return createAnimationFromXml(context, parser, null,
                        Xml.asAttributeSet(parser));
            } catch (XmlPullParserException ex) {
                NotFoundException rnf = new NotFoundException(
                        "Can't load animation resource ID #0x"
                                + Integer.toHexString(id));
                rnf.initCause(ex);
                throw rnf;
            } catch (IOException ex) {
                NotFoundException rnf = new NotFoundException(
                        "Can't load animation resource ID #0x"
                                + Integer.toHexString(id));
                rnf.initCause(ex);
                throw rnf;
            } finally {
                if (parser != null)
                    parser.close();
            }
        }
    
        private static Animation createAnimationFromXml(Context c,
                XmlPullParser parser, AnimationSet parent, AttributeSet attrs)
                throws XmlPullParserException, IOException {
    
            Animation anim = null;
            // Make sure we are on a start tag.
            int type;
            int depth = parser.getDepth();
            while (((type = parser.next()) != XmlPullParser.END_TAG || parser
                    .getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
                if (type != XmlPullParser.START_TAG) {
                    continue;
                }
                String name = parser.getName();
                if (name.equals("set")) {
                    anim = new AnimationSet(c, attrs);
                    createAnimationFromXml(c, parser, (AnimationSet) anim, attrs);
                } else if (name.equals("alpha")) {
                    anim = new AlphaAnimation(c, attrs);
                } else if (name.equals("scale")) {
                    anim = new ScaleAnimation(c, attrs);
                } else if (name.equals("rotate")) {
                    anim = new RotateAnimation(c, attrs);
                } else if (name.equals("translate")) {
                    anim = new TranslateAnimation(c, attrs);
                } else if (name.equals("cube")) {
                    anim = new CubeAnimation(c, attrs);
                } else {
                    throw new RuntimeException(
                            "not a cubeanimation animation name: "
                                    + parser.getName());
                }
            }
            if (parent != null) {
                parent.addAnimation(anim);
            }
    
            return anim;
    
        }
    }
    View Code

    配置文件加载和动态构造两种方式创建对话实例以及调用

    public class AnimateActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            this.setContentView(R.layout.activity_main);
            View view = this.findViewById(R.id.tv);
            view.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Animation animation;
                    if(v.getTag()==null||(Boolean)v.getTag()){
                        ((TextView)v).setText("配置文件加载");
                        animation = CubeAnimation.loadAnimation(getApplicationContext(), R.anim.cubeanimation);
                        v.setTag(false);
                    }else{
                        ((TextView)v).setText("动态初始化");
                        animation = new CubeAnimation(0, 400, 0, 360, 100);
                        animation.setDuration(8000);
                        v.setTag(true);
                    }
                    v.startAnimation(animation);
                }
            });
    
        }
    }
    View Code

    ok 基本完成,希望没有什么遗漏

  • 相关阅读:
    Java学习笔记二.2
    Java学习笔记二.1
    Java学习笔记一
    cookie和session笔记
    编码知识笔记
    新手前端笔记之--css盒子
    新手前端笔记之--初识css
    新手前端笔记之--必备的标签
    新手前端笔记之--初识html标签
    二叉树总结
  • 原文地址:https://www.cnblogs.com/boliu/p/3296083.html
Copyright © 2011-2022 走看看