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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM