ndroid 動畫基礎
在Android 裡你能夠使用的動畫效果:
平移
縮放
旋轉
透明
以上動畫的基本使用就是本文的內容了。由於,本人的能力問題,實在搞不出讓人眼前一亮的動畫,就湊合著看著吧。不過,那些令人讚歎的動畫效果的基礎就是這些。
Interpolators(插值器)
一般而言,要做動畫的,需要封裝點物理公式,用作為計算幀與幀間的數值計算,不過,如果,只是,為了搞些動畫讓app好用一些,倒不需要搞得這麼複雜,android 官方api 已經封裝好了一些常用的動畫插值器。
預設內建7種類型的插值器,個人覺得,如果只是應用裡面的一些動畫的話這7個就夠用了。
AccelerateInterpolator
加速
Decelerate
減速
AccelerateDecelerateInterpolator
開始,和結尾都很慢,但是,中間加速
AnticipateInterpolator
開始向後一點,然後,往前拋
OvershootInterpolator
往前拋超過一點,然後返回來
AnticipateOvershootInterpolator
開始向後一點,往前拋過點,然後返回來
BounceInterpolator
結束的時候彈一下
LinearInterpolator
勻速
以上動畫都源自android官方api demo,用eclipse adt android 選擇例子項目導航,然後,選擇APIDEMOS 就能建立(什麼沒聽說過?現在知道了吧。。。)
好了,雖然截取的gif 動畫播放起來有點抽筋的感覺,接下來我們該如何在應用中使用這些知識呢?
組合動畫
目前講解動畫api 的資料比較多,這裡就不在重複那些基礎的知識了!
現在讓我們學習一下,如何利用,平移,縮放,旋轉創造出讓人眼前一亮的動畫.
為了,更有目的的使用動畫,下面假想一個使用情境。
假想:商品購物車案例
Notice :為了方便看效果,動畫延時時間將會設定的比較長。特地說明一下:假想就是隨便想,切勿對號入座。
任務:
為了,讓商城app有更好的互動效果,決定對購物車控制項和商品控制項上面加一些動畫效果。
購物車動畫設計方案:
利用,透明,平移,對購物車的出現和離開增加動畫互動效果。
經過一番努力效果如下(湊合著看吧。。):
相關知識點
一些動畫常用的通用基礎屬性:
Notice: 所謂通用就是說所有動畫標籤都適用於這些屬性
android:duration 設定動畫播放的時間
android:startOffset 設定動畫的開始播放時間
andorid:interpolator 設定動畫的插值器
android:repeatCount 動畫播放的常用次數
android:repeatMode 動畫重播的模式,即從頭到尾,從頭到尾,還是從頭到尾,在從尾到頭。
透明的使用:
<alpha />
value 從 0 (透明) 到 1 (不透明)在android中透明主要用於對view 淡入,淡出的效果控制主要有兩個屬性
android:fromAlpha view在動畫開始的透明度。
android:toAlpha view在動畫結束的透明度。
平移的使用:
<translate />
支援使用 %,如 “50%“ 擷取的是這個view的百分之50,除此之外還有另外一種寫法:”50%p“ 意思是擷取這個view的上一級view的百分之50 當然,指定特定值也是支援的“22.2”,不過為了相容更多的android裝置建議還是使用百分比的值。
android:fromXDelta
android:fromYDelta
from?Delta 意思是開始的軸線
android:toXDelta
android:toYDelta
to?Delta 意思是結束的軸線
這次的方案展示了兩個插值器的使用:
用於出現的:BounceInterpolator
用於離開的: AnticipateInterpolator
什麼是插值器?
所謂插值器就是用於數值的起始間的變化,就是相當於一個類似於物理引擎的東西。android官方內建了一些簡單常用的數值變換,讓我們,不需要去學習相關的物理知識。
例如:
開始值為1,結束值為 100.那麼我們如何控制變化這個值的變化過程呢?這裡就是插值器的使用。
一般勻速的話就是:
1,2,3,4,5...100。 然後我們就會看到物體以一個勻速的速度進行平移操作。
那麼我們需要物體像汽車那樣加速度的前進,我們可以用加速插值器,我們從1到100的過程,就會是:
1,2,4,5,8,16.。。。。100 展示在我們面前的view對象就會以一個加速度的形式進行平移。
有很多應用開發人員並不熟悉動畫製作的一些基礎知識,可能不太明白。現在,通過對源碼進行分析,來徹底搞明白這個概念。
我們分析一些Interpolator 類樹:
從api文檔TimeInterpolator 我們可以知道,這個插值器的實現只有一個方法:
getInterpolation(float t);
然後我們挑選前面用過的BounceInterpolator 看下,它是如何?這個方法。如果感興趣的,可以按照這種方法,把其他幾個插值器的實現都看一遍。
最後我們會發現,插值器的作用就是傳回值。
接著我們來看下Animation line:869 是怎麼用這個介面的.
看完這這幾個地方,相信應該對android 動畫架構怎麼對值進行變換的原理應該有所瞭解。
有了以上知識,我們對android的動畫架構基本上已經完全瞭解,現在,我們利用學到的知識,進行更好的動畫設計。
我們接著剛才的案例,著手設計商品控制項的動畫設計
商品動畫設計:
這次,我們學習一個新的動畫標籤縮放(<scale>)
效果如下:
<scale />
使view 大點或者小點
android:fromXScale
android:fromYScale
from?Scale 意思是開始軸線的縮放比例(預設 1.0)
android:toXScale
android:toYScale
to?Scale 意思是結束軸線的縮放比例(預設 1.0)
android:pivotX
android:pivotX
旋轉用的軸點座標
最後我們把購物車的動畫,和商品的動畫在組合起來。效果如下:
添加商品的時候,如果購物車還沒出現,先出現購物車顯示的動畫,在進行商品的動畫播放。
這次我們學習一下如何監聽動畫的動作,對於AnimationListener()主要有三個
onAnimationStart(Animation animation)
onAnimationRepeat(Animation animation)
onAnimationEnd(Animation animation)
package com.youxiachai.animutils.example;
import android.app.Activity;import android.graphics.Color;import android.os.Bundle;import android.os.Handler;import android.view.Gravity;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.view.ViewGroup.LayoutParams;import android.view.animation.Animation;import android.view.animation.Animation.AnimationListener;import android.view.animation.AnimationUtils;import android.widget.Button;import android.widget.LinearLayout;import android.widget.TextView;
/** * @author youxiachai * @date 2013-5-30 */public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
findViewById(R.id.bShopcart).setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) { // TODO Auto-generated method stub
if( getShopCart() == null){ showShopCart(); }else{ hideShopCart((ViewGroup) findViewById(R.id.shopcart)); } } });
findViewById(R.id.bShop).setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) { //TODO Auto-generated method stub
addShop(); } });
}
/**播放view 的動畫 * @param v * @param id */ private void startViewAnimation(View v,int id){ Animation animation = AnimationUtils.loadAnimation(this, id); v.startAnimation(animation); }
private void addShop(){ if( getShopCart() != null){// getScene().removeView(v);// getScene().addView(v);// startViewAnimation(v, R.anim.block_move_right); Button b = new Button(this); ViewGroup.LayoutParams lp = new LayoutParams(200, 50); b.setText("xxx"); b.setLayoutParams(lp); getShopCart().addView(b); startViewAnimation(b, R.anim.block_move_right); }else{ Animation shopCartAnim = AnimationUtils.loadAnimation(this, R.anim.in_translate_top); shopCartAnim.setAnimationListener(new AnimationListener() {
@Override public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub
}
@Override public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub
}
@Override public void onAnimationEnd(Animation animation) { // TODO Auto-generated method stub new Handler().postDelayed(new Runnable() {
@Override public void run() { // TODO Auto-generated method stub addShop(); } }, 500); } });
View v = buildShopCart(); getScene().addView(v); v.startAnimation(shopCartAnim); } }
private ViewGroup getShopCart(){ return (ViewGroup) findViewById(R.id.shopcart); }
/** * 顯示購物車 */ private void showShopCart(){ View v= buildShopCart();
//利用@android:anim/bounce_interpolator 出現的時候彈一下 startViewAnimation(v, R.anim.in_translate_top); getScene().addView(v); }
/**隱藏購物車 * @param v */ private void hideShopCart(ViewGroup v){ TextView tv = (TextView) v.getChildAt(0); tv.setText("向下一點,然後往頂部拋離開");
// 利用 @android:anim/anticipate_interpolator 向下一點,然後離開 startViewAnimation(v, R.anim.out_translate_top); getScene().removeView(v); }
/**建立購物車對象 * @return */ private View buildShopCart(){ LinearLayout ll = new LinearLayout(this); ll.setOrientation(LinearLayout.VERTICAL); TextView tv = new TextView(this); tv.setTextColor(Color.WHITE); tv.setText("從頂部下來,到底部的時候彈一下"); ll.setId(R.id.shopcart); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(400, 400); lp.setMargins(0, 10, 0, 0); ll.setBackgroundColor(getResources().getColor(R.color.pink)); ll.setLayoutParams(lp); ll.setGravity(Gravity.CENTER); ll.addView(tv); return ll; }
/**獲得動畫播放view group * @return */ private ViewGroup getScene(){ return (ViewGroup) findViewById(R.id.animContext); }
}//////////////////////////////////
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/bounce_interpolator"> <alpha android:duration="2000" android:fromAlpha="0" android:toAlpha="1" /> <translate android:duration="2000" android:fromXDelta="0" android:fromYDelta="-100%" android:toXDelta="0" android:toYDelta="0" /></set>////////////////////////////////