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 基本完成,希望没有什么遗漏

posted @ 2013-09-02 11:01  boliu  阅读(3069)  评论(3编辑  收藏  举报
hljs.initHighlightingOnLoad(); 最恶心的莫过于找不出的bug和夏天的蚊子
最爽的当然也是干掉的bug和拍死的蚊子