Animation Property Animation 使用
本篇主要講Animation 和 Property Animation的使用,最后會講QQ管家桌面火箭作為例子:
在Android中開發動效有兩套框架可以使用,分別為 Animation 和 Property Animation;
相對來說,Animator比Animation要強大太多,兩者之間的主要區別在于:
- 區別一:需要的Anroid API level不一樣
Property Animation需要Android API level 11的支持,當然可以使用nineoldandroids.jar進行兼容,而View Animation則是最原始的版本。 - 區別二:適用范圍不一樣
Property Animation適用于所有的Object對象,而View Animation則只能應用于View對象。 - 區別三,實際改變不一樣:
Animation:改變的是view的繪制位置,而非實際屬性;
Property Animation:改變的是view的實際屬性;
如:用兩套框架分別對一個button做位移動畫,用animation處理之后的點擊響應會在原處,而用Property Animation處理后的點擊響應會在最終位置處;
一:Animation
總的來說可以分為:Tween Animation(補間動畫) 和Frame Animation(幀動畫)
幀動畫(Frame Animation):
幀動畫其實就是按照一定的時間間隔進行快速的圖片切換,達到視覺上的動畫效果,這種動畫相對來說缺點較多,比如:
1.根據動畫的復雜度需要切多張圖,這樣就不可避免的增大了包大小
2.由于是多張圖,運行時需要加載到內存,那么又會增大運行時的內存大小
所以如果在動效上有別的方案選擇,個人不太建議使用幀動畫的實現方式,當然有時候不得不用,這時我們可以盡可能的在效果連貫的基礎上減少圖片張數;
幀動畫的實現也相對簡單,就舉一個例子,但是例子之中有幾條幀動畫的使用規則,是我以前在使用的過程中遇到問題后總結出來的;
1.在drawable目錄下xml中定義如下文件,節點為animation-list,oneshot代表是否執行一次,duration代表每張圖對應展示時間:
2.然后將該drawable設置給對應的imageview
3.在activity中
animDrawable = (AnimationDrawable) imageView.getBackground();4.在onWindowFocusChanged()中調用:
animDrawable.stop();
animDrawable.start();
如果不這么做,那么在性能比較差的機器上很可能就會出現沒有播放的情況,因為只顯示出了第一幀,問題在于動畫沒有和view完成關聯,所以不要在onCreate中去調用啟動,而需要在onWindowFocusChanged中進行調用;
在極特殊的情況下如果還無法播放,則可以mHandler.postDelay 200 毫秒作為終極殺手锏,當然只要按照我上面的步驟,應該不會出現問題;
好了,幀動畫最大的問題是按照上面的步驟開發,接下來看補間動畫(Tween Animation)
補間動畫(Tween Animation):
Animation下有五個子類:AlphaAnimation(漸變),RotateAnimation(旋轉),ScaleAnimation(縮放),TranslateAnimation(位移)
在實現原理上除了AlphaAnimation是動態的去改變view的alpha值,其他三個都是去改變里面的Matrix(矩陣,后面會專門講);
在Animation框架里,主要的類主要有Animation和Transformation、Interpolator(插值器,后面也會專門講)
Transformation里面主要對alpha和matrix進行了封裝,而改變view的透明度就是改變alpha,移動、旋轉、縮放甚至錯切則都是改變matrix
Animation里有一個重要的方法applyTransformation,實現自定義Animation也主要是實現這個方法:
以AlphaAnimation為例:
漸變動畫只需要在里面根據當前的interpolatedTime(已經由插值器轉換后的值)動態計算出對應的alpha,重新設置到Transformation中即可;
Animation的使用也相對比較簡單,可以通過xml配置,也可以通過代碼生成:
當要多個效果同時使用時,則如上使用set標簽進行組合,在代碼中使用如下:
Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.app_clean_animation); view.startAnimation(animation); 2.純代碼生成:// false代表里面的子animation不共用一個插值器AnimationSet animationSet = new AnimationSet(false);// 從alpha 完全透明變為完全不透明AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);alphaAnimation.setDuration(500);alphaAnimation.setFillAfter(true);// 運行完成后是否回到開始時的狀態alphaAnimation.setFillBefore(false);alphaAnimation.setInterpolator(new AccelerateInterpolator());// 重復的次數,infinite代表永久循環alphaAnimation.setRepeatCount(Animation.INFINITE);// 重復的模式, restart代表重新開始,reverse代表反轉alphaAnimation.setRepeatMode(Animation.RESTART);// 給動畫設置對應的監聽,可以在動畫開始、結束或重復執行時做對應操作alphaAnimation.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {//開始時候回調}@Overridepublic void onAnimationRepeat(Animation animation) {//重復執行時回調}@Overridepublic void onAnimationEnd(Animation animation) {//一輪結束時回調}});RotateAnimation rotateAnimation = new RotateAnimation(0, 360);rotateAnimation.setDuration(500);animationSet.addAnimation(alphaAnimation);animationSet.addAnimation(rotateAnimation);view.startAnimation(animationSet);好了,animation就講到這里,上面的注釋應該比較詳盡了,主要是弄清楚其使用方式和使用場景!
二:Property Animation(屬性動畫)
屬性動畫,它更改的是對象的實際屬性,在View Animation(Tween Animation)中,其改變的是View的繪制效果,真正的View的屬性保持不變,比如無論你在對話中如何縮放Button的大小,Button的有效點擊區域還是沒有應用動畫時的區域,其位置與大小都不變。而在Property Animation中,改變的是對象的實際屬性,如Button的縮放,Button的位置與大小屬性值都改變了。而且Property Animation不止可以應用于View,還可以應用于任何對象。Property Animation只是表示一個值在一段時間內的改變,當值改變時要做什么事情完全是你自己決定的。
在Property Animation中,可以對動畫應用以下屬性:
1.TimeInterpolator(插值器,和低版本的Interpolator一樣):屬性值的計算方式,如先快后慢
2.TypeEvaluator:根據屬性的開始、結束值與TimeInterpolator計算出的因子計算出當前時間的屬性值
3.Repeat Count and behavoir:重復次數與方式,如播放3次、5次、無限循環,可以此動畫一直重復,或播放完時再反向播放
4.Animation sets:動畫集合,即可以同時對一個對象應用幾個動畫,這些動畫可以同時播放也可以對不同動畫設置不同開始偏移
5.Frame refreash delay:多少時間刷新一次,即每隔多少時間計算一次屬性值,默認為10ms,最終刷新時間還受系統進程調度與硬件的影響
上面都是些概念,但這些東西不必刻意去記,或去理解插值器這樣的比較生澀的概念,我們只需要使用他最實用的部分,并熟悉動畫的實現套路;
所以對于屬性動畫主要帶大家熟悉兩個類,ValueAnimator和ObjectAnimator,通過這兩個類我們平常遇到的動效大部分都能夠加以解決;
1.ValueAnimator:
ValueAnimator包含了 Property Animation 動畫的所有核心功能,如動畫時間,開始、結束屬性值,相應時間屬性值計算方法等。
在我看來,使用 ValueAnimator 只是為我們創建了一個過程,我們可以用ValueAnimator.ofXXX()進行創建,然后通過各種setXXX()給其設定過程的時間,速率變化效果等,然后通過addUpdateListener()中去拿這個過程中回調回來的中間值,然后使用這些中間值改變view的屬性形成動態效果;
上面這句話通過代碼表現如下:
比如我們使用 ValueAnimator 在2S內將view橫向拉長為2倍,縱向壓縮為0:
// 在2S內將view橫向拉長為2倍,縱向壓縮為0// 創建0-1的一個過程,任何復雜的過程都可以采用歸一化,然后在addUpdateListener回調里去做自己想要的變化ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);// 設置過程的時間為2SvalueAnimator.setDuration(SCALE_ANIM_TIME);// 設置這個過程是速度不斷變快的valueAnimator.setInterpolator(new AccelerateInterpolator());// 這個過程中不斷執行的回調valueAnimator.addUpdateListener(new AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {// 不斷回調的在0-1這個范圍內,經過插值器插值之后的返回值float value = (Float) animation.getAnimatedValue();// ViewHelper可直接用于修改view屬性// 將寬在2S內放大一倍ViewHelper.setScaleX(mTestImage, 1 + value);// 將高在2S內壓縮為0ViewHelper.setScaleY(mTestImage, 1 - value);}});// AnimatorListenerAdapter是AnimatorListener的空實現,根據需要覆蓋的方法自行選擇valueAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animation) {super.onAnimationStart(animation);Toast.makeText(getApplicationContext(), "onAnimationStart", Toast.LENGTH_SHORT).show();}@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);Toast.makeText(getApplicationContext(), "onAnimationEnd", Toast.LENGTH_SHORT).show();}@Overridepublic void onAnimationCancel(Animator animation) {super.onAnimationCancel(animation);}@Overridepublic void onAnimationRepeat(Animator animation) {super.onAnimationRepeat(animation);}});valueAnimator.start();動畫其實就是在一個時間段內不斷去改變view的一些屬性值,這些屬性值動態變化,不斷重繪的過程,也就形成了我們所看到的動效;
那么基于此,我們可以知道這個過程都是通過時間來控制的,時間走過的比例肯定在 0-1 之間,如果我們直接用這個走過的時間比例去算當前屬性值,那么整個過程則是勻速(線性)的;
那么在這個基礎上,我們想我們的過程是非線性的,我們該怎么辦呢,那么只需要對這個時間比例加以加工,具體請看下圖:
橫軸就是經過的時間比例,肯定是勻速的從0-1,縱軸則是時間比例經過加工后的插值,這個對應過程則是Interpolator(插值器)對應的過程;
減速線則對應DecelerateInterpolater,因為它的斜率越來越平,所以瞬時速度越來越小,則形成了減速效果;
其他的效果類似,目前android里提供的插值器有如下一些:
- AccelerateInterpolator 加速,開始時慢中間加速
- DecelerateInterpolator 減速,開始時快然后減速
- AccelerateDecelerateInterolator 先加速后減速,開始結束時慢,中間加速
- AnticipateInterpolator 反向 ,先向相反方向改變一段再加速播放
- AnticipateOvershootInterpolator 反向加回彈,先向相反方向改變,再加速播放,會超出目的值然后緩慢移動至目的值
- BounceInterpolator 跳躍,快到目的值時值會跳躍,如目的值100,后面的值可能依次為85,77,70,80,90,100
- CycleIinterpolator 循環,動畫循環一定次數,值的改變為一正弦函數:Math.sin(2 * mCycles * Math.PI * input)
- LinearInterpolator 線性,線性均勻改變
- OvershottInterpolator 回彈,最后超出目的值然后緩慢改變到目的值
- TimeInterpolator 一個接口,允許你自定義interpolator,以上幾個都是實現了這個接口
其實想實現對應的效果,其實是找一條曲線對對應條件進行模擬,然后根據曲線函數,和X值,得出每個時間點上對應的Y值(插值),這也就是插值器原理;
2.ObjectAnimator
我們同樣還是實現在2S內將view橫向拉長為2倍,縱向壓縮為0:
AnimatorSet animatorSet = new AnimatorSet();// 將view在x方向上從原大小放大2倍ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(mTestImage, "scaleX", 1, 2);scaleXAnimator.setDuration(SCALE_ANIM_TIME);// 將view在y方向上從原大小壓縮為0ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(mTestImage, "scaleY", 1, 0);scaleYAnimator.setDuration(SCALE_ANIM_TIME);// 設置加速模式animatorSet.setInterpolator(new AccelerateInterpolator());// 設置回調,當然也可以設置在單獨的animator上,eg:scaleXAnimatoranimatorSet.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animation) {super.onAnimationStart(animation);Toast.makeText(getApplicationContext(), "onAnimationStart", Toast.LENGTH_SHORT).show();}@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);Toast.makeText(getApplicationContext(), "onAnimationEnd", Toast.LENGTH_SHORT).show();}@Overridepublic void onAnimationCancel(Animator animation) {super.onAnimationCancel(animation);}@Overridepublic void onAnimationRepeat(Animator animation) {super.onAnimationRepeat(animation);}});animatorSet.playTogether(scaleXAnimator, scaleYAnimator);animatorSet.start();ObjectAnimator 是ValueAnimator 的子類,可以直接改變Object的屬性,目前可供改變的屬性主要有:
- translationX,translationY View相對于原始位置的偏移量
- rotation,rotationX,rotationY 旋轉,rotation用于2D旋轉角度,3D中用到后兩個
- scaleX,scaleY 縮放比
- x,y View的最終坐標,是View的left,top位置加上translationX,translationY
- alpha 透明度
關于Animator主要分享這兩個類,其他的比如 PropertyValuesHolder 大家可以自己去看;
QQ管家桌面懸浮窗動畫
分析:
1.浮在桌面上的小圓泡可以蓋在所有應用之上,并且可以獨立操作,不影響其他操作,需要使用WindowManager.addView ;
2.拖動的時候變成小火箭,需要手勢處理 onTouch;
3.拖動到底部區域的時候震動,需要對拖動到的位置做時候判斷;
4.放手時位置如果在底座區,則發射火箭,否則變成小圓回到邊界;
5.火箭噴火效果,可以通過兩張圖幀動畫實現,也可以采用屬性動畫實現(通過看QQ管家的圖,應該是采用的幀動畫方式);
6.底部的底座閃動效果也是三張圖的幀動畫;
MainActivity
package com.itheima.rocket;import java.nio.channels.AlreadyConnectedException;import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.graphics.drawable.AnimationDrawable; import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.widget.ImageView; import android.widget.Toast;public class MainActivity extends Activity {private ImageView iv;private ImageView iv_bottom; private ImageView iv_top;private AnimationDrawable rocketAnimation;private Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {int position = (Integer) msg.obj ;iv.layout(iv.getLeft(), position, iv.getRight(), position+iv.getHeight());if(position<320){iv_top.setVisibility(View.VISIBLE);AlphaAnimation aa = new AlphaAnimation(0.6f, 1.0f);aa.setDuration(300);iv_top.startAnimation(aa);}if(position<20){AlphaAnimation aa = new AlphaAnimation(1.0f, 0.0f);aa.setDuration(300);aa.setFillAfter(true);iv_top.startAnimation(aa);}};};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);iv.setBackgroundResource(R.drawable.rocket);iv_top = (ImageView) findViewById(R.id.iv_top);iv_bottom = (ImageView) findViewById(R.id.iv_bottom);rocketAnimation = (AnimationDrawable) iv.getBackground();rocketAnimation.start();iv.setOnTouchListener(new OnTouchListener() {int startX;int startY;@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:startX =(int) event.getRawX();startY =(int) event.getRawY();break;case MotionEvent.ACTION_MOVE:int newX =(int) event.getRawX();int newY =(int) event.getRawY();int dx = newX - startX;int dy = newY - startY;//wm.updateViewLayout();iv.layout(iv.getLeft()+dx, iv.getTop()+dy, iv.getRight()+dx, iv.getBottom()+dy);startX =(int) event.getRawX();startY =(int) event.getRawY();break;case MotionEvent.ACTION_UP:int top = iv.getTop();int left = iv.getLeft();int right = iv.getRight();if(top>300&&left>100&&right<220){Toast.makeText(getApplicationContext(), "發射火箭", 0).show();iv_bottom.setVisibility(View.VISIBLE);AlphaAnimation aa = new AlphaAnimation(0.0f, 1.0f);aa.setDuration(500);aa.setRepeatCount(1);aa.setRepeatMode(Animation.REVERSE);aa.setFillAfter(true);iv_bottom.startAnimation(aa);sendRocket();}break;}return true;}});}protected void sendRocket() {new Thread(){public void run() {int start = 380;for(int i = 0 ;i<=11;i++){try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}//更新一下uiMessage msg = Message.obtain();msg.obj = 380 - i*38;//計算出火箭的高度handler.sendMessage(msg);}};}.start();} }rocket.xml
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android"android:oneshot="false"><item android:drawable="@drawable/desktop_rocket_launch_1" android:duration="200" /><item android:drawable="@drawable/desktop_rocket_launch_2" android:duration="200" /> </animation-list>布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><ImageView android:id="@+id/iv"android:layout_width="40dip"android:layout_height="73dip" /><ImageView android:visibility="invisible"android:id="@+id/iv_bottom"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:src="@drawable/desktop_smoke_m" /><ImageView android:visibility="invisible"android:id="@+id/iv_top"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_above="@id/iv_bottom"android:src="@drawable/desktop_smoke_t" /></RelativeLayout>源代碼下載
源代碼
參考鏈接
Animation & Property Animation 使用 - Ajian_studio - 博客頻道 - CSDN.NET
【TweenedAnimation】四種動畫效果參數詳解(自測所得) - 邪天殤 - 博客園
完成
總結
以上是生活随笔為你收集整理的Animation Property Animation 使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL流浪记(七)—— MySQL删
- 下一篇: 简单的线性回归实现模型的存储和读取