Android 圖形和動畫
Android 提供非常豐富且多樣化的架構,可支援 2D 圖形和動畫。 本主題介紹這些架構,並討論如何建立自定義圖形和動畫,以在 Xamarin.Android 應用程式中使用。
概觀
儘管在傳統上處於有限功率的裝置上執行,但最高分級的行動應用程式通常具有複雜的用戶體驗(UX),其完整的高品質圖形和動畫,可提供直覺、回應性、動態的感覺。 隨著行動應用程式越來越複雜,使用者已經開始期待越來越多的應用程式。
幸運的是,新式行動平臺有非常強大的架構,可用來建立複雜的動畫和自定義圖形,同時保留易於使用。 這可讓開發人員以很少的努力來新增豐富的互動功能。
Android 中的 UI API 架構大致可以分成兩個類別:圖形和動畫。
圖形會進一步分割成不同的方法來執行 2D 和 3D 圖形。 3D 圖形可透過數個內建架構取得,例如 OpenGL ES(行動裝置特定版本的 OpenGL),以及 MonoGame 等第三方架構(與 XNA 工具組相容的跨平臺工具組)。 雖然 3D 圖形不在本文的範圍內,但我們將會檢查內建的 2D 繪圖技術。
Android 提供兩個不同的 API 來建立 2D 圖形。 一個是高階宣告式方法,另一個則是程序設計低階 API:
可繪製的資源 – 這些是用來透過程序設計方式或(更通常)在 XML 檔案中內嵌繪圖指示來建立自定義圖形。 可繪製的資源通常定義為 XML 檔案,其中包含 Android 轉譯 2D 圖形的指示或動作。
Canvas – 這是低階 API,牽涉到直接在基礎位圖上繪製。 它提供非常精細的控制所顯示的內容。
除了這些 2D 圖形技術之外,Android 也提供數種不同的方法來建立動畫:
可繪製動畫 – Android 也支援稱為 「可繪製動畫」的逐畫面動畫。 這是最簡單的動畫 API。 Android 會循序載入並顯示可繪製的資源(很像卡通)。
檢視動畫 – 檢視動畫是 Android 中的原始動畫 API,且適用於所有版本的 Android。 此 API 有限,因為它只會使用 View 物件,而且只能在這些檢視上執行簡單的轉換。 檢視動畫通常會定義於資料夾中找到的
/Resources/anim
XML 檔案中。屬性動畫 – Android 3.0 引進了一組新的動畫 API,稱為 「屬性動畫」。 這些新的 API 引進了可延伸且彈性的系統,可用來建立任何對象的屬性動畫效果,而不只是 View 物件。 這種彈性可讓動畫封裝在不同的類別中,讓程式代碼共用更容易。
檢視動畫更適用於必須支援舊版 Android 3.0 API (API 層級 11) 的應用程式。 否則,應用程式應該基於上述原因使用較新的屬性動畫 API。
不過,所有這些架構都是可行的選項,不過,應該將喜好設定提供給屬性動畫,因為它是更靈活的 API 來搭配使用。 屬性動畫可讓動畫邏輯封裝在不同的類別中,讓程式代碼共用更容易並簡化程式代碼維護。
協助工具選項
圖形和動畫有助於讓Android應用程式更具吸引力且有趣地使用;不過,請務必記住,某些互動會透過螢幕助讀程式、替代輸入設備或輔助縮放進行。 此外,某些互動可能會在沒有音訊功能的情況下發生。
如果應用程式已設計為輔助功能,則這些應用程式更容易使用:在使用者介面中提供提示和瀏覽協助,並確保UI的圖片元素有文字內容或描述。
如需如何使用Android輔助功能 API 的詳細資訊,請參閱Google的輔助功能指南。
2D 圖形
可繪製的資源是Android應用程式中的熱門技術。 與其他資源一樣,可繪製的資源是宣告式資源, 它們定義於 XML 檔案中。 此方法可讓您清楚區分程式代碼與資源。 這可以簡化開發和維護,因為不需要變更程式碼來更新或變更 Android 應用程式中的圖形。 不過,雖然可繪製的資源適用於許多簡單且常見的圖形需求,但它們缺少 Canvas API 的功能和控制。
使用 Canvas 物件的另一種技術與其他傳統 API 架構非常類似,例如 System.Drawing 或 iOS 的核心繪圖。 使用 Canvas 物件可讓您最控制如何建立 2D 圖形。 適用於可繪製資源無法運作或難以使用的情況。 例如,您可能需要繪製自定義滑桿控件,其外觀會根據滑桿值的相關計算而變更。
讓我們先檢查可繪製的資源。 它們更簡單,涵蓋最常見的自定義繪圖案例。
可繪製的資源
可繪製的資源定義於目錄中 /Resources/drawable
的 XML 檔案中。 與內嵌 PNG 或 JPEG 不同,不需要提供可繪製資源的密度特定版本。
在運行時間,Android 應用程式會載入這些資源,並使用這些 XML 檔案中包含的指示來建立 2D 圖形。
Android 定義數種不同類型的可繪製資源:
ShapeDrawable – 這是繪製基本幾何圖形的 Drawable 物件,並套用一組有限的圖形效果給該圖形。 它們對於自定義按鈕或設定 TextViews 背景等專案非常有用。 我們將會在此文章稍後看到如何使用
ShapeDrawable
的範例。StateListDrawable – 這是可繪製的資源,會根據小工具/控件的狀態變更外觀。 例如,按鈕可能會根據是否按下按鈕來變更其外觀。
LayerDrawable – 此可繪製的資源會堆棧數個其他可繪製資源。另一個可繪製資源。 下列螢幕快照顯示 LayerDrawable 的範例:
TransitionDrawable – 這是 LayerDrawable,但有一個差異。 TransitionDrawable 能夠讓一個圖層以動畫顯示在另一層上方。
LevelListDrawable – 這與 StateListDrawable 非常類似,因為它會根據特定條件顯示影像。 不過,與 StateListDrawable 不同,LevelListDrawable 會根據整數值顯示影像。 LevelListDrawable 的範例是顯示WiFi訊號的強度。 隨著WiFi訊號的強度變更,所顯示的可繪製將會隨之變更。
ScaleDrawable ClipDrawable/– 正如其名稱所指,這些 Drawable 提供縮放和裁剪功能。 ScaleDrawable 會調整另一個 Drawable,而 ClipDrawable 則會裁剪另一個 Drawable。
InsetDrawable – 此 Drawable 會在另一個 Drawable 資源的兩側套用內嵌。 當 View 需要小於檢視實際界限的背景時,就會使用它。
XML BitmapDrawable – 此檔案是 XML 中要對實際點陣圖執行的一組指令。 Android 可以執行的一些動作是並排、打擷取和消除鋸齒。 其中一個很常見的用法是跨版面配置背景並排點陣圖。
可繪製範例
讓我們看看如何使用 建立 2D 圖形 ShapeDrawable
的快速範例。 ShapeDrawable
可以定義四個基本圖形之一:矩形、橢圓形、線條和環形。 您也可以套用基本效果,例如漸層、色彩和大小。 下列 XML 位於 ShapeDrawable
AnimationsDemo 隨附專案中(檔案中 Resources/drawable/shape_rounded_blue_rect.xml
)。
它會定義具有紫色漸層背景和圓角的矩形:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<!-- Specify a gradient for the background -->
<gradient android:angle="45"
android:startColor="#55000066"
android:centerColor="#00000000"
android:endColor="#00000000"
android:centerX="0.75" />
<padding android:left="5dp"
android:right="5dp"
android:top="5dp"
android:bottom="5dp" />
<corners android:topLeftRadius="10dp"
android:topRightRadius="10dp"
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp" />
</shape>
我們可以以宣告方式在版面配置或其他 Drawable 中參考此 Drawable 資源,如下列 XML 所示:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#33000000">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/shape_rounded_blue_rect"
android:text="@string/message_shapedrawable" />
</RelativeLayout>
您也可以以程式設計方式套用可繪製的資源。 下列代碼段示範如何以程式設計方式設定 TextView 的背景:
TextView tv = FindViewById<TextView>(Resource.Id.shapeDrawableTextView);
tv.SetBackgroundResource(Resource.Drawable.shape_rounded_blue_rect);
若要查看其外觀,請執行 AnimationsDemo 專案,然後從主選單中選取 Shape Drawable 專案。 我們應該會看到類似下列螢幕快照的內容:
如需有關可繪製資源之 XML 元素和語法的詳細資訊,請參閱 Google 的檔。
使用畫布繪圖 API
可抽籤功能強大,但有其限制。 某些專案可能或非常複雜(例如:將篩選套用至裝置上相機拍攝的圖片)。 使用可繪製的資源來套用紅眼縮小會非常困難。 相反地,Canvas API 可讓應用程式擁有非常精細的控制,以選擇性地變更圖片中特定部分的色彩。
一個通常與 Canvas 搭配使用的類別是 小畫家 類別。 這個類別保存如何繪製的色彩和樣式資訊。 它用來提供這類色彩和透明度的東西。
Canvas API 會使用 畫家的模型 來繪製 2D 圖形。 作業會以彼此頂端的連續層套用。 每個作業都會涵蓋基礎位圖的某些區域。 當區域重疊先前繪製的區域時,新的油漆會部分或完全遮蔽舊畫。 這與 System.Drawing 和 iOS 核心圖形等許多其他繪圖 API 的運作方式相同。
有兩種方式可以取得 Canvas
物件。 第一 種方式涉及定義 Bitmap 物件,然後使用它 具現 Canvas
化物件。 例如,下列代碼段會建立具有基礎位圖的新畫布:
Bitmap bitmap = Bitmap.CreateBitmap(100, 100, Bitmap.Config.Argb8888);
Canvas canvas = new Canvas(b);
取得物件的另一Canvas
種方式是提供 View 基類的 OnDraw 回呼方法。 Android 會在決定 View 需要自行繪製並傳入 Canvas
物件,讓 View 能夠使用時呼叫這個方法。
Canvas 類別會公開方法,以程式設計方式提供繪製指示。 例如:
Canvas.Draw 小畫家 – 以指定的繪製填滿整個畫布的點陣圖。
Canvas.DrawPath – 使用指定的繪製繪製指定的幾何圖形。
Canvas.DrawText – 使用指定的色彩繪製畫布上的文字。 文字會在位置
x,y
繪製。
使用 Canvas API 繪製
以下是畫布 API 運作情形的範例。 下列代碼段示範如何繪製檢視:
public class MyView : View
{
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
Paint green = new Paint {
AntiAlias = true,
Color = Color.Rgb(0x99, 0xcc, 0),
};
green.SetStyle(Paint.Style.FillAndStroke);
Paint red = new Paint {
AntiAlias = true,
Color = Color.Rgb(0xff, 0x44, 0x44)
};
red.SetStyle(Paint.Style.FillAndStroke);
float middle = canvas.Width * 0.25f;
canvas.DrawPaint(red);
canvas.DrawRect(0, 0, middle, canvas.Height, green);
}
}
上述程式代碼會先建立紅色油漆和綠色油漆物件。 它會以紅色填滿畫布的內容,然後指示畫布繪製 25% 的畫布寬度的綠色矩形。 在本文的原始程式碼隨附的專案中, AnimationsDemo
可以看到此專案的範例。 藉由啟動應用程式,並從主功能表中選取 [繪圖] 專案,我們應該有類似下列畫面:
動畫
用戶喜歡在其應用程式中移動的專案。 動畫是改善應用程式用戶體驗並協助其脫穎而出的絕佳方式。最好的動畫是使用者不會注意到的動畫,因為它們感覺自然。 Android 提供下列三個適用於動畫的 API:
檢視動畫 – 這是原始 API。 這些動畫會系結至特定的 View,而且可以在檢視的內容上執行簡單的轉換。 由於簡單起見,此 API 仍然適用於 Alpha 動畫、旋轉等專案。
屬性動畫 – 已在 Android 3.0 中引進屬性動畫。 它們可讓應用程式產生幾乎任何動畫效果。 屬性動畫可以用來變更任何物件的任何屬性,即使螢幕上看不到該物件也一樣。
可繪製動畫 – 這是特殊的可繪製資源,可用來將非常簡單的動畫效果套用至版面配置。
一般而言,屬性動畫是慣用的系統,因為它更具彈性,並提供更多功能。
檢視動畫
檢視動畫僅限於檢視,而且只能在起點和終點、大小、旋轉和透明度等值上執行動畫。 這些類型的動畫通常稱為 tween 動畫。 檢視動畫可以透過程式代碼或使用 XML 檔案,以程式設計方式定義兩種方式。 XML 檔案是宣告檢視動畫的慣用方式,因為它們更容易閱讀且更容易維護。
動畫 XML 檔案會儲存在 /Resources/anim
Xamarin.Android 專案的目錄中。 此檔案必須具有下列其中一個專案做為根元素:
alpha
– 淡入或淡出動畫。rotate
– 旋轉動畫。scale
– 重設大小動畫。translate
– 水準和/或垂直動作。set
– 可保存一或多個其他動畫元素的容器。
根據預設,XML 檔案中的所有動畫都會同時套用。 若要讓動畫循序進行,請在上面定義的其中一個項目上設定 android:startOffset
屬性。
您可以使用插補器來影響動畫中的變更速率。 插補器可讓動畫效果加速、重複或減速。 Android 架構提供數個現成的插補程式,例如 (但不限於):
AccelerateInterpolator
/DecelerateInterpolator
– 這些插補器會增加或減少動畫中的變更速率。BounceInterpolator
– 變更會在結尾反彈。LinearInterpolator
– 變更的速率是常數。
下列 XML 顯示結合其中一些元素的動畫檔案範例:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android=http://schemas.android.com/apk/res/android
android:shareInterpolator="false">
<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:fillEnabled="true"
android:fillAfter="false"
android:duration="700" />
<set android:interpolator="@android:anim/accelerate_interpolator">
<scale android:fromXScale="1.4"
android:toXScale="0.0"
android:fromYScale="0.6"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:fillEnabled="true"
android:fillBefore="false"
android:fillAfter="true"
android:startOffset="700"
android:duration="400" />
<rotate android:fromDegrees="0"
android:toDegrees="-45"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:fillEnabled="true"
android:fillBefore="false"
android:fillAfter="true"
android:startOffset="700"
android:duration="400" />
</set>
</set>
此動畫會同時執行所有動畫。 第一個縮放動畫會水平縮放影像,並垂直縮小影像,然後同時旋轉 45 度逆時針和縮小,從螢幕消失。
動畫可以透過擴充動畫,然後將動畫套用至 View,以程式設計方式套用至檢視。 Android 提供協助程式類別,這個類別 Android.Views.Animations.AnimationUtils
會擴充動畫資源,並傳回的 Android.Views.Animations.Animation
實例。 這個物件會藉由呼叫 StartAnimation
並傳遞 Animation
物件,套用至 View。 下列代碼段顯示下列範例:
Animation myAnimation = AnimationUtils.LoadAnimation(Resource.Animation.MyAnimation);
ImageView myImage = FindViewById<ImageView>(Resource.Id.imageView1);
myImage.StartAnimation(myAnimation);
既然我們已經對檢視動畫的運作方式有了基本瞭解,讓我們移至屬性動畫。
屬性動畫
屬性動畫器是 Android 3.0 中引進的新 API。 它們提供更具擴充性的 API,可用來建立任何物件上任何屬性的動畫效果。
所有屬性動畫都是由 Animator 子類別的實例所建立。 應用程式不會直接使用此類別,而是使用其中一個子類別:
ValueAnimator – 這個類別是整個屬性動畫 API 中最重要的類別。 它會計算需要變更的屬性值。
ViewAnimator
不會直接更新這些值,而是會引發可用來更新動畫物件的事件。ObjectAnimator – 這個類別是 的
ValueAnimator
子類別。 它旨在藉由接受要更新的目標對象和屬性來簡化動畫物件的程式。AnimationSet – 此類別負責協調動畫如何彼此相關執行。 動畫可以同時執行、循序執行,或兩者之間有指定的延遲。
評估工具 是動畫器用來計算動畫期間新值的特殊類別。 現為 Android 提供下列評估工具:
IntEvaluator – 計算整數屬性的值。
FloatEvaluator – 計算 float 屬性的值。
ArgbEvaluator – 計算色彩屬性的值。
如果正在產生動畫效果的屬性不是 float
或 int
色彩,應用程式可能會藉由實 ITypeEvaluator
作 介面來建立自己的評估工具。 (實作自定義評估工具超出本主題的範圍。
使用 ValueAnimator
任何動畫都有兩個部分:計算動畫值,然後在某些物件上的屬性上設定這些值。 ValueAnimator 只會計算值,但不會直接在對象上運作。 相反地,物件將會在動畫生命週期內叫用的事件處理程式內更新。 此設計允許從一個動畫值更新數個屬性。
您可以呼叫下列其中一個 Factory 方法,以取得 的實例 ValueAnimator
:
ValueAnimator.OfInt
ValueAnimator.OfFloat
ValueAnimator.OfObject
完成後, ValueAnimator
實例必須設定其持續時間,然後才能啟動。 下列範例示範如何在1000毫秒的跨度上,以動畫顯示從0到1的值:
ValueAnimator animator = ValueAnimator.OfInt(0, 100);
animator.SetDuration(1000);
animator.Start();
但本身,上述代碼段並不十分有用 – 動畫工具會執行,但更新的值沒有目標。 類別 Animator
會在決定必須通知接聽程式新值時引發Update事件。 應用程式可能會提供事件處理程式來回應此事件,如下列代碼段所示:
MyCustomObject myObj = new MyCustomObject();
myObj.SomeIntegerValue = -1;
animator.Update += (object sender, ValueAnimator.AnimatorUpdateEventArgs e) =>
{
int newValue = (int) e.Animation.AnimatedValue;
// Apply this new value to the object being animated.
myObj.SomeIntegerValue = newValue;
};
既然我們已經瞭解 ValueAnimator
,讓我們深入瞭解 ObjectAnimator
。
使用 ObjectAnimator
ObjectAnimator 是 的 ViewAnimator
子類別,結合了 計時引擎和的值計算 ValueAnimator
,以及連接事件處理程式所需的邏輯。 需要 ValueAnimator
應用程式明確地連接事件處理程式, ObjectAnimator
將會為我們處理此步驟。
的 API 非常類似於 的 API ObjectAnimator
, ViewAnimator
但要求您提供 要更新的物件和屬性名稱。 下列範例顯示使用 ObjectAnimator
的範例:
MyCustomObject myObj = new MyCustomObject();
myObj.SomeIntegerValue = -1;
ObjectAnimator animator = ObjectAnimator.OfFloat(myObj, "SomeIntegerValue", 0, 100);
animator.SetDuration(1000);
animator.Start();
如您先前代碼段所見, ObjectAnimator
可以減少並簡化建立對象動畫所需的程序代碼。
可繪製的動畫
最後一個動畫 API 是可繪製的動畫 API。 可繪製的動畫會一個接一個地載入一系列的 Drawable 資源,並循序顯示它們,類似於翻轉動畫片。
可繪製的資源定義於 XML 檔案中,該檔案具有 <animation-list>
元素做為根元素,以及一系列 <item>
定義動畫中每個畫面的專案。 這個 XML 檔案會儲存在 /Resource/drawable
應用程式的資料夾中。 下列 XML 是可繪製動畫的範例:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/asteroid01" android:duration="100" />
<item android:drawable="@drawable/asteroid02" android:duration="100" />
<item android:drawable="@drawable/asteroid03" android:duration="100" />
<item android:drawable="@drawable/asteroid04" android:duration="100" />
<item android:drawable="@drawable/asteroid05" android:duration="100" />
<item android:drawable="@drawable/asteroid06" android:duration="100" />
</animation-list>
此動畫會透過六個畫面執行。 屬性 android:duration
會宣告每個畫面的顯示時間長度。 下一個代碼段顯示建立 Drawable 動畫的範例,並在使用者按兩下畫面上的按鈕時啟動它:
AnimationDrawable _asteroidDrawable;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
_asteroidDrawable = (Android.Graphics.Drawables.AnimationDrawable)
Resources.GetDrawable(Resource.Drawable.spinning_asteroid);
ImageView asteroidImage = FindViewById<ImageView>(Resource.Id.imageView2);
asteroidImage.SetImageDrawable((Android.Graphics.Drawables.Drawable) _asteroidDrawable);
Button asteroidButton = FindViewById<Button>(Resource.Id.spinAsteroid);
asteroidButton.Click += (sender, e) =>
{
_asteroidDrawable.Start();
};
}
此時,我們已涵蓋 Android 應用程式中可用的動畫 API 基礎。
摘要
本文介紹許多新的概念和 API,以協助將一些圖形新增至 Android 應用程式。 首先,它討論了各種 2D 圖形 API,並示範 Android 如何讓應用程式使用 Canvas 物件直接繪製到畫面。 我們也看到一些替代技術,允許使用 XML 檔案以宣告方式建立圖形。 然後,我們接著討論在Android中建立動畫的舊版和新 API。