屬性動畫,android屬性動畫
屬性(Property)動畫
屬性(Property)動畫:安卓提供的眾多動畫中的一種,從某種角度來看,屬性動畫實際上是增強版的補間(Tween)動畫。
屬性動畫主要由兩方面組成:
1.計算各幀的相關屬性值。
2.給指定的對象設定相關的屬性值。
區別:
1.補間(Tween)動畫只能夠操控各種組件的透明度(alpha),位置(translate),
旋轉(rotate)和放縮(scale)四種屬性進行相應的變換,但是屬性(Property)動畫可以對任何的屬性值做出改變。
2.補間(Tween)動畫只能對UI組件作用,但是屬性(Property)動畫沒有限制,可以對任何對象進行操作。
屬性動畫API:
1.ValueAnimator:屬性動畫主要的時間引擎,它負責計算各個幀的屬性值,也就是屬性動畫第一組成部分。由於ValueAnimator只會負責第一部分,第二部分給組件賦屬性值就需要手動完成。
2.ObjectAnimator:ValueAnimator的子類,在使用的時候可以直接指定組件對象,使用起來更加的方便了。但是在某些情境下,ObjectAnimator存在一些限制,可能需要考慮使用ValueAnimator。
3.AnimatorSet:Animator的子類,可以用於組合多個Animator對象,還可以指定是按次序播放還是同時播放。
在ValueAnimator中還用到了一個計算工具類Evaluator(計算機),控制者屬性動畫如何計算屬性值。Android提供了集中Evaluator:
1.IntEvaluator:用於計算int類型的屬性值計算機。
2.FloatEvaluator:用於計算float類型的屬性值計算機。
3.ArgbEvaluator:用於計算十六進位的rgb顏色值。
4.TypeEvaluator:計算機的介面,供自訂計算器實現。
使用ValueAnimator建立動畫大致如下四個步驟:
1.調用ValueAnimator的ofInt(), ofFloat(), ofObject()靜態方法建立ValueAnimator執行個體,很明顯這幾個不同的方法建立的不同執行個體中,所用到的計算機也是不同的。2.調用ValueAnimator的setDuration()等方法給屬性動畫設定相應的參數,如動畫的期間,重複次數等。3.調用start()方法啟動相應的動畫。4.為ValueAnimator註冊AnimatorUpdateListener監聽器,在監聽器中可以即時擷取到ValueAnimator計算出來的屬性值,只需要在監聽器中賦值給對應對象就行了。例如:
ValueAnimator animation = ValueAnimator.ofFloat(1f, 0f); animation.setDuration(3000); animation.setRepeatCount(1); animation.start(); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { /** * 使用的時候可以通過getAnimatedValue()來擷取當前計算出來的幀的屬性值,並賦值給制定對象。 */ } });
如果是希望使用自己利用TypeEvaluator定義出來的屬性值計算機,則將第一步改為:
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(),1f, 0f);
2.使用ObjectAnimator建立動畫和ValueAnimator差不多,只不過ObjectAnimator已經實現了將計算結果賦值給對象,我們在使用的時候提供控制項對象,
不需要註冊AnimatorUpdateListener監聽器(沒有上述的第四個步驟)。
例如:
ObjectAnimator animation = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 1f); animation.setDuration(1000); animation.setRepeatCount(1); animation.start();
注意: 1.在使用ObjectAnimator的對象上一定要有改變的屬性值,例如上述的例子中imageView一定要有alpha這個屬性值。 2.如果在第一句話是
ObjectAnimator animation = ObjectAnimator.ofFloat(imageView, "alpha", 1f);
少提供了一個參數,則提供的值會被認為是屬性計算的結束值,對alpha這個屬性一定要提供getter方法,返回的值將作為屬性計算的初始值,也就是從該組件的目前狀態開始執行動畫。 3.如果動畫的對象是View,為了能顯示動畫的效果,需要不斷的通知群組件重新繪製,調用View.invalidate()方法, 但是View定義的setter方法,如setAloha()等方法都會自動的調用invalidate()方法,不需要我們再額外的調用了。
/** * 圖形類 * 在執行個體中是一個圓 */public class ShapeHolder { private float x = 0, y = 0; private ShapeDrawable shape; private int color; private RadialGradient gradient; private float alpha = 1f; private Paint paint; public ShapeHolder(ShapeDrawable s) { shape = s; } public float getWidth() { return shape.getShape().getWidth(); } public void setWidth(float width) { Shape s = shape.getShape(); s.resize(width,s.getWidth()); } public float getHeight() { return shape.getShape().getHeight(); } public void setHeight(float height) { Shape s = shape.getShape(); s.resize(height,s.getHeight()); } public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; } public int getColor() { return color; } public void setColor(int color) { this.color = color; } public ShapeDrawable getShape() { return shape; } public void setShape(ShapeDrawable shape) { this.shape = shape; } public RadialGradient getGradient() { return gradient; } public void setGradient(RadialGradient gradient) { this.gradient = gradient; } public float getAlpha() { return alpha; } public void setAlpha(float alpha) { this.alpha = alpha; } public Paint getPaint() { return paint; } public void setPaint(Paint paint) { this.paint = paint; }}public class MainActivity extends Activity { static final float BALL_SIZE = 50F; /** * 用來控制動畫執行的時間 */ static final float FULL_TIME = 1000; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LinearLayout container = (LinearLayout) findViewById(R.id.root); /** * 將自訂控制項加入到布局中 */ container.addView(new MyAniamtionView(this)); } /** * 自訂View * 實現了AnimatorUpdateListener監聽類 */ public class MyAniamtionView extends View implements ValueAnimator.AnimatorUpdateListener { /** * 儲存多個小球的容器 */ public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>(); public MyAniamtionView(Context context) { super(context); setBackgroundColor(Color.WHITE); } @Override public boolean onTouchEvent(MotionEvent event) { //在手指觸摸的地方添加一個小球 ShapeHolder newBall = addBall(event.getX(), event.getY()); float startY = newBall.getY(); float endY = getHeight() - BALL_SIZE; float h = (float) getHeight(); float eventY = event.getY(); int duration = (int) (FULL_TIME * ((h - eventY) / h)); //用ValueAnimator定義落下的動畫 ValueAnimator fallAnim = ObjectAnimator.ofFloat(newBall, "y", startY, endY); fallAnim.setDuration(duration); fallAnim.setInterpolator(new AccelerateInterpolator()); //用ObjectAnimator定義落下的動畫 ObjectAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y", endY, startY); bounceBackAnim.setDuration(duration); bounceBackAnim.setInterpolator(new DecelerateInterpolator()); fallAnim.addUpdateListener(this); //定義小球透明度的動畫 ObjectAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f); fadeAnim.setDuration(250); fadeAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { balls.remove(((ObjectAnimator)animation).getTarget()); } }); fadeAnim.addUpdateListener(this); //定義一個AnimatorSet來將定義的三個動畫排序 AnimatorSet animatorSet = new AnimatorSet();animatorSet.play(fallAnim).before(bounceBackAnim); animatorSet.play(bounceBackAnim).before(fadeAnim); animatorSet.start(); return true; } /** * 向小球集合ArrayList中加入小球 * 設定各種屬性座標等 * * @param x * @param y * @return */ private ShapeHolder addBall(float x, float y) { OvalShape circle = new OvalShape(); circle.resize(BALL_SIZE, BALL_SIZE); ShapeDrawable drawable = new ShapeDrawable(circle); ShapeHolder shapeHolder = new ShapeHolder(drawable); shapeHolder.setX(x - BALL_SIZE / 2); shapeHolder.setY(y - BALL_SIZE / 2); int red = (int) (Math.random() * 255); int green = (int) (Math.random() * 255); int blue = (int) (Math.random() * 255); int color = 0xff000000 + red << 16 | green << 8 | blue; Paint paint = drawable.getPaint(); int drakColor = 0xff000000 | red / 4 << 16 | green / 4 << 8 | blue /4; RadialGradient gradient = new RadialGradient(37.5f, 12.5f, BALL_SIZE, color, drakColor, Shader.TileMode.CLAMP); paint.setShader(gradient); shapeHolder.setPaint(paint); balls.add(shapeHolder); return shapeHolder; } /** * 將集合裡的每個小球都繪製在螢幕上面 * @param canvas */ @Override protected void onDraw(Canvas canvas) { for (ShapeHolder shapeHolder : balls) { canvas.save(); canvas.translate(shapeHolder.getX(), shapeHolder.getY()); shapeHolder.getShape().draw(canvas); canvas.restore(); } } @Override public void onAnimationUpdate(ValueAnimator animation) { this.invalidate(); } }}