編輯:關於Android編程
本文講介紹android在3.0之後推出的一種新的動畫機制,屬性動畫,對動畫不了解的同學,可以先去看看繪圖篇——android動畫基礎這篇文章。好了,現在我們進入正題。
基本概念 android傳統動畫 Animation與屬性動畫 Animator的工作原理 Animator出現的原因 Animation的局限性 屬性動畫ObjectAnimator translationX translationY X和Y rotation 組合動畫 動畫事件監聽 小栗子
簡單來說,傳統動畫就是不斷的去調用系統的onDraw方法,去重新繪制組件,而屬性動畫則是通過調用屬性的get和set方法重新設置控件的屬性值,實現動畫的效果
既然已經存在了可以實現各種動畫的方法了,為什麼谷歌還要推出新的動畫框架呢?為了解釋這個問題,我們寫一個小栗子。
首先是布局文件,很簡單,就是一個imageView
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher"/> </RelativeLayout>
接下來是java代碼,我們找到這個view,為其添加點擊事件,這裡直接簡單的Toast一下,表示view被點擊;然後我們為這個view添加一個位移動畫。代碼如下:
package com.example.dell.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends Activity {
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView= (ImageView) findViewById(R.id.image);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"ImageView",Toast.LENGTH_SHORT).show();
}
});
//參數1:X開始位置 參數2:x結束的位置
//參數3:y開始位置 參數4:y結束的位置
TranslateAnimation animation =new TranslateAnimation(0f,500f,0f,0f);
animation.setDuration(2000);
//動畫結束後應用動畫
animation.setFillAfter(true);
imageView.startAnimation(animation);
}
}
我們來看看演示效果:
可以看到,當我們進入到Activity當中後,動畫就已經完成了,大家注意一下,這段代碼其實是有問題的,因為我們只看到了動畫的結果,而沒看到動畫的過程,這樣一來,動畫設置的就毫無意義。為什麼會出現這種情況呢?這涉及到了Activity生命周期的內容,答案將在本節最後揭曉。
現在這時我先點的imageview完成動畫後的位置(0f,100f)發現並沒有彈出Toast,然後我們再去點擊imageView的初始位置(0f,0f),有意思的事情發生了,Toast被彈出來了
那麼這些說明了什麼呢?
說明了我們在使用Animation的時候,雖然可以改變動畫在界面上顯示的位置,但是卻不能改變點擊事件所在的位置<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPqGjPC9wPg0KPHA+tb3V4sDvo6y0q82zQW5pbWF0aW9u0ru49rrctPO1xL7Wz97Q1KOsy/zWu8rH1ti75sHLtq+7raOsuMSx5MHLPHN0cm9uZz7P1Mq+PC9zdHJvbmc+tcTOu9bDo6y1q8rH1ebV/crCvP7P7NOmtcTOu9bDo6zItMO709C3osn6yM66zrjEseSho8v50tSjrEFuaW1hdGlvbrKisrvKyrrP1sbX9zxzdHJvbmc+vt/T0L27u6W1xLavu63Qp7n7PC9zdHJvbmc+oaPL/Na7xNzTw8C0zeqzydK70Kk8c3Ryb25nPs/Uyr7Q1LXE0Ke5+zwvc3Ryb25nPqGjPC9wPg0KPHA+xMfDtM/Cw+ajrM7Sw8e+zcC0wdDSu8/CtKvNs0FuaW1hdGlvbrXEvtbP3tDUPC9wPg0KPGg0IGlkPQ=="animation的局限性">【Animation的局限性】
第一點就是上面所說的內容,不在啰嗦了。 因為Animation的工作原理,上面介紹了,是不斷調用系統的onDraw()方法去繪制圖像,那麼必然十分耗費GPU,效率不高 Animation提供了位移、旋轉、透明度、縮放這四種動畫,雖然經過組合,可以創造出很多的動畫效果,但是有時候依然無法制作出復雜好看的動畫,即存在動畫效果上的局限。
為解決以上的局限性,Google在android3.0後推出了屬性動畫。那麼接下來我們就正式進入屬性動畫的內容。 在這之前,我們似乎還有一個小問題沒有解決,那就是為什麼上一個栗子的動畫沒有顯示出來呢? 答案是,動畫的啟動寫在了onCreate()方法當中,而在這之後,還有onStart(),onResume()方法,而用戶真正看到界面的時候,onCreate方法早已經調用完畢了,此時如果動畫的持續時間過短,那麼用戶看到界面時動畫自然已經結束了。解決的辦法也非常簡單,只需要把動畫的啟動邏輯放在onResume() (活動准備好和用戶進行交互的時候 )方法當中即可 補充:經過測試,發現在onResume()方法當中也會出現一些延時,這因為機器性能的問題,啟動一個活動的時間長短不一,即便調用了onResume()方法,距離Activity的啟動可能還有一段時間。但是這種寫法肯定要比在onCreate()方法中啟動動畫要好一些。 現在我們在上面栗子的基礎上增加一個button,將動畫的啟動邏輯放在裡面,這樣就能避免剛才動畫顯示的問題。 更改後的布局 接下來是java代碼 我們看一下效果 這裡很明顯,view的點擊事件也發生了相應的變化。 想要改變Y上的屬性,也很簡單,代碼如下: 看到這裡,有的小伙伴可能會有疑問,到底那些屬性是我們可以去設置的呢?其實只要是Google定義了的可以通過set和get去操縱的屬性,我們都可以在屬性動畫中對其進行設置。 前面已經講了translationX和translationY,那麼現在出現的X和Y又是什麼東西呢? translationX是指的是物體的偏移量,而X是指物體最後到達的一個絕對值,即具體移動到的坐標 旋轉屬性,旋轉360度 以此類推,可以操作的屬性還有很多,凡是可以通過get或者set設置的屬性,都可以設置成屬性動畫。 現在我們使用ObjectAnimator來進行多個動畫效果的組合 效果圖: 實際上,我們還有更好的方法去實現這種組合效果,我們對上面的寫法進行優化: 這裡我們使用了一個PropertyValuesHolder的容器來容納3個動畫效果,然後在最後調用ObjectAnimator的ofPropertyValuesHolder()方法來加載之前定義的三個holder。那麼這樣寫的好處是什麼呢?Google在PropertyValuesHolder這個類中對動畫進行了一些優化,這些優化使得我們在使用多個動畫屬性的時候能夠更加有效率,更加節省系統資源。 在前面的動畫基礎當中,有一個動畫集合的概念,那麼在屬性動畫當中其實也有這麼一個集合的概念。下面我們就用AnimatorSet來實現上述的效果。 代碼如下: 當然在AnimatorSet方法當中我們還有更多的選擇去控制動畫。從animatorSet.playTogether()這個方法的名字中就能看出,該方法是讓所有的動畫同時起效果,我們才看到了和剛才幾種方法實現的同樣的效果。這裡google還提供了playSequentially()方法,該方法則是按順序去播放動畫。大家可以試一下。 我們還可以使用play()方法,這裡我們實現view在X和Y軸上同時平移,結束之後再旋轉360度。 代碼如下: 這樣一來就實現了對每個動畫更加細致的控制。通過play(),with(),after(),before()方法,我們就能做到對一個屬性集合的詳細的順序控制。這種方式,也是屬性動畫框架中使用最多的一種配和。 接下來總結一下 (1)通過ObjectAnimator進行更精細的控制,只控制一個對象的一個屬性。 顧名思義,和一般的點擊事件差不多,我們為ObjectAnimator設置監聽事件,以滿足實際開發當中的需求。 我們在上一個栗子的基礎上為我們的Button添加一個alpha動畫,讓其從透明變成不透明,然後在這個動畫裡面加入了一個監聽事件,在監聽事件當中,我們看到了4個需要重寫的方法,通過這4個方法,我們就可以監聽動畫在不同事件段所需要完成的操作。 演示效果: 現在我們在考慮一種情況,那就是如果我們並不需要重寫那麼多的方法該怎麼辦呢?這時可以使用android系統提供的一個更方便的接口AnimatorListenerAdapter(),大家可以發現,系統幫我們實現了很多方法,這裡我們只需要添加需要重寫的方法即可 代碼如下: 這樣我們就實現了對某一個事件的監聽,而不需要寫出所有的事件。 總結一下 看到出來動畫監聽事件還是比較簡單的,我們只需要調用ObjectAnimator的addListener()方法,就能為我們的Animator增加一個監聽事件,接著我們可以通過 AnimatorListenerAdapter這個類,去有選擇的去選取我們需要監聽的事件。 這裡的栗子來自於慕課網的課程,有興趣的小伙伴可以去看看。 在開始寫這個栗子之前,請各位小伙伴去下載一下素材,其中a.png的尺寸有點問題,改為58*58即可 演示效果: 裡面定義了我們需要用到的imageView 上述代碼當中有非常詳細的注釋,這裡就不多解釋了。為了讓動畫效果更棒,有時我們還可以為動畫添加差插器(interpolator)。android內置的插值器有如下
屬性動畫——ObjectAnimator
【“translationX”】
public class MainActivity extends Activity {
private ImageView imageView;
private TranslateAnimation animation;
private Button bt_move;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView= (ImageView) findViewById(R.id.image);
bt_move= (Button) findViewById(R.id.bt_move);
//view的點擊事件
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"ImageView",Toast.LENGTH_SHORT).show();
}
});
//button的點擊事件
bt_move.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//使用ObjectAnimator
//第一個參數是被操縱的view對象;第二個參數是被操作的屬性
//第三,第四個參數是可變長的數,表示熟悉所變化的范圍
ObjectAnimator objectAnimator= ObjectAnimator.ofFloat(imageView,"translationX",0f,200f);
//設置顯示時長
objectAnimator.setDuration(2000);
//讓動畫開始
objectAnimator.start();
}
});
}
}
【“translationY”】
ObjectAnimator objectAnimator= ObjectAnimator.ofFloat(imageView,"translationY",0f,200f);
//設置顯示時長
objectAnimator.setDuration(2000);
//讓動畫開始
objectAnimator.start();
【“X和Y”】
【“rotation”】
ObjectAnimator objectAnimator= ObjectAnimator.ofFloat(imageView,"rotation",0f,360f);
//設置顯示時長
objectAnimator.setDuration(2000);
//讓動畫開始
objectAnimator.start();
【組合動畫】
ObjectAnimator.ofFloat(imageView,"translationY",0f,100f).setDuration(1000).start();
ObjectAnimator.ofFloat(imageView,"translationX",0f,100f).setDuration(1000).start();
ObjectAnimator.ofFloat(imageView,"rotation",0f,360f).setDuration(1000).start();
可以發現,這三個動畫的效果是同時完成的,因為在調用start()方法之後,實際上是一個異步的過程。
PropertyValuesHolder p1=PropertyValuesHolder.ofFloat("translationY",0f,100f);
PropertyValuesHolder p2=PropertyValuesHolder.ofFloat("translationX",0f,100f);
PropertyValuesHolder p3=PropertyValuesHolder.ofFloat("rotation",0f,360f);
//通過ObjectAnimator來調用ofPropertyValuesHolder()方法
//第一個參數傳遞view,後續的參數為可變長的數組
ObjectAnimator.ofPropertyValuesHolder(imageView,p1,p2,p3).setDuration(1000).start();
AnimatorSet animatorSet=new AnimatorSet();
//接下來將單個動畫添加到AnimatorSet當中
animatorSet.playTogether(animator1,animator2,animator3);
animatorSet.setDuration(1000);
animatorSet.start();
ObjectAnimator animator1= ObjectAnimator.ofFloat(imageView,"translationY",0f,100f);
ObjectAnimator animator2= ObjectAnimator.ofFloat(imageView,"translationX",0f,100f);
ObjectAnimator animator3= ObjectAnimator.ofFloat(imageView,"rotation",0f,360f);
AnimatorSet animatorSet=new AnimatorSet();
//animator1和Animator2同時播放
animatorSet.play(animator1).with(animator2);
//Animator3在Animator1或者Animator2結束後播放
animatorSet.play(animator3).after(animator2);
animatorSet.setDuration(1000);
animatorSet.start();
(2)同時多個ObjectAnimator組合到AnimatorSet當中,可以形成一個完整的動畫效果。
(3)而且AnimatorSet可以自動驅動,可以去調用play(),with(),after(),before,playTogether(),playSequentially()實現更為豐富的動畫效果。動畫事件監聽
bt_move.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
………………
ObjectAnimator bt_animator=ObjectAnimator.ofFloat(view,"alpha",0f,1f);
bt_animator.setDuration(1000);
bt_animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
//動畫開始前調用
}
@Override
public void onAnimationEnd(Animator animator) {
//動畫結束後調用,為簡單起見,這裡我們只簡單的提示一行字
Toast.makeText(MainActivity.this,"anim is end",Toast.LENGTH_SHORT).show();
}
@Override
public void onAnimationCancel(Animator animator) {
//動畫被取消後
}
@Override
public void onAnimationRepeat(Animator animator) {
//動畫重復時調用
}
});
bt_animator.start();
…………
}
});
bt_animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
Toast.makeText(MainActivity.this,"anim is end",Toast.LENGTH_SHORT).show();
}
});
小栗子
接下來讓讓我們看看布局文件
<framelayout android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android">
接下來是比較關鍵的java代碼:
public class MainActivity extends Activity implements View.OnClickListener {
//定義每一個圖片資源
private int[] res = {R.id.view_a, R.id.view_b, R.id.view_c, R.id.view_d, R.id.view_e, R.id.view_f, R.id.view_g,
R.id.view_h};
//存儲viewd的list集合
private List
- Accelerate
- Decelerate
- Accelerate/Decelerate、
- Overshoot
- Bounce
通過插值器,我們讓某一屬性在數值上的變化時,可以擁有不同的加速曲線,進而讓我們的動畫更加豐富。
正常情況下Activity的聲明周期先來看看官方給出的聲明周期圖:這裡需要說明如下幾點:針對特定Activity,第一次啟動,回調如下:onCreate->onSt
我相信,在平時的開發過程中,大家一定會或多或少地接觸到 SQLite。然而在使用它時,我們往往需要做許多額外的工作,像編寫 SQL 語句與解析查詢結果等。所以,適用於 A
可能很多人會感覺Activity很簡單,但是經歷了半年的android開發,我發現我對Activity的的理解還是比較淺顯的,其實Activity並沒有我們想
package com.example.jreduch08.util;import android.content.Context;import androi