編輯:關於android開發
動畫在我們實際開發中占有很重要的地位,一個優秀的動畫能為我們的app應用增色很多,同時一個優秀的動畫銜接能夠增加我們app的邏輯展示。在Android系統中,系統給我們提供了幾種動畫的支持,分別是Frame Animation(幀動畫)、Tween Animation(補間動畫)以及3.0系統以後增加的Property Animator(屬性動畫)。這些動畫的熟練使用可以幫助我們設計出perfect效果的動畫,下面就開始我們的學習吧!
一、概述
幀動畫,顧名思義就是這個動畫的效果是由一幀幀的圖片組合出來的。通過制定圖片展示的順序,達到動畫的展示效果。
在Android開發中,系統給我們提供了”animation-list” 節點用於我們配置幀動畫。
實現步驟
1、在res目錄下創建用於存儲xml動畫文件的anim文件夾,res/anim,也可以放在drawable目錄下
2、動畫配置,在animation-list節點中配置item項
2、將文件設置到ImageView控件的背景上,然後獲取背景轉換為AnimationDrawable對象進行播放動畫
iv_imageView.setBackgroundResource(R.drawable.frame_animation);
AnimationDrawable animation = (AnimationDrawable)iv_imageView.getBackground();
animation.start();
二、實例講解
1、奔跑的飛馬
我們先來看下效果圖,第一個實例,飛奔的飛馬。
對於這種動畫效果使用Frame Animation動畫即可完成,我們只需要將gif動畫進行分幀切割成圖片,然後我們在animation-list標簽中指定圖片的順序進行播放即可。
代碼實現
<code class=" hljs xml"><animation-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@mipmap/Horse_start" android:duration="200"> <item android:drawable="@mipmap/Horse1" android:duration="200"> <item android:drawable="@mipmap/Horse2" android:duration="200"> <item android:drawable="@mipmap/Horse3" android:duration="200"> <item android:drawable="@mipmap/Horse4" android:duration="200"> <item android:drawable="@mipmap/Horse5" android:duration="200"> <item android:drawable="@mipmap/Horse6" android:duration="200"> <item android:drawable="@mipmap/Horse7" android:duration="200"> <item android:drawable="@mipmap/Horse8" android:duration="200"> <item android:drawable="@mipmap/Horse_start" android:duration="200"> </item></item></item></item></item></item></item></item></item></item></animation-list></code>
在animation-list中,item的先後順序就是圖片在動畫中播放的順序。順序設置好了以後,我們就將該anim綁定到我們的ImageView上,然後進行播放。
最後就是我們的代碼,獲取到該drawable,然後進行播放。
ImageView iv_animaView = (ImageView) findViewById(R.id.iv_frame);
AnimationDrawable animationDrawable = (AnimationDrawable) iv_animaView.getBackground();
animationDrawable.start();
看下動畫效果:
是不是很簡單,簡單的幾行代碼就可以做出一個gif的動畫效果,不過現在貌似有開源控件可以加載gif圖片,回頭研究下看看二者的效率如何。
2、裸奔的機器人
通過前面的一個案例,我們已經基本熟悉了Frame Animation的使用,下面我們在做一個例子,來鞏固下知識點。
代碼實現
<code class=" hljs xml"><animation-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@mipmap/zzlx1" android:duration="200"> <item android:drawable="@mipmap/zzlx2" android:duration="200"> <item android:drawable="@mipmap/zzlx3" android:duration="200"> <item android:drawable="@mipmap/zzlx4" android:duration="200"> <item android:drawable="@mipmap/zzlx5" android:duration="200"> <item android:drawable="@mipmap/zzlx6" android:duration="200"> <item android:drawable="@mipmap/zzlx7" android:duration="200"> <item android:drawable="@mipmap/zzlx8" android:duration="200"> </item></item></item></item></item></item></item></item></animation-list></code>
後面的代碼同上面,我們只需要看看我們的實現效果即可。
三、幀動畫原理分析
在上面的開發中,我們在將backgroud對應的Drawable對象轉換為一個AnimationDrawable對象,然後由這個對象啟動Frame動畫,那麼這個類究竟是由何方神聖呢?讓我們一起look look。
1、AnimationDrawable概述
AnimationDrawable用於創建frame-by-frame(逐幀)動畫,它定義了一些列的Drawable對象可用於設置View的backgroud背景屬性。frame-by-frame動畫最簡單的方式是通過XML文件進行創建,然後將xml文件放到res/drawable/folder文件夾下,同時將此drawa對象設置到view的backgroud屬性。Xml文件的組成:
下面是在代碼中創建和使用幀動畫:
ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image);
img.setBackgroundResource(R.drawable.spin_animation);
AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();
frameAnimation.start();
我們在來看看AnimationDrawable對象給我們提供的屬性。
AnimationDrawable_visible:設置是否可見 AnimationDrawable_variablePadding: AnimationDrawable_oneshot:設置是否只播放一次,true是,false否 AnimationDrawableItem_duration:設置每幀動畫之間的時間間隔 AnimationDrawableItem_drawable:設置每幀之間間隔的drawable對象2、AnimationDrawable源碼分析
上面我們已經對AnimationDrawable進行了一個簡要的分析,了解了一些它的屬性,我們心中獲取對幀動畫還有一些疑惑,比如一些問題:
下面我們就圍繞上面的幾個問題對AnimationdDrawable進行分析。查看源碼,我們可以看到AnimationDrawable暴露的public方法。
AnimationDrawable根據名稱,我們也能推算到這是一個Drawable的子類,我們仔細一想,為什麼通過getBackgroud()方法獲得的Drawable對象可以轉換到AnimationDrawable這個子類呢?這就需要我們去看下源碼。在Drawable類中,有一個方法createFromXml()方法:<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">
/**
* Create a drawable from an XML document. For more information on how to
* create resources in XML, see
* Drawable Resources.
*/
public static Drawable createFromXml(Resources r, XmlPullParser parser)
throws XmlPullParserException, IOException {
return createFromXml(r, parser, null);
}
這個方法就是用於將我的XML文件轉換成一個drawable對象,我們接著深入下去,看下createFromXml()這個方法。
public static Drawable createFromXml(Resources r, XmlPullParser parser, Theme theme)
throws XmlPullParserException, IOException {
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
while ((type=parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty loop
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
Drawable drawable = createFromXmlInner(r, parser, attrs, theme);
if (drawable == null) {
throw new RuntimeException("Unknown initial tag: " + parser.getName());
}
return drawable;
}
在這裡我們看到了XML文件轉換成Drawable的內部,在Android系統中,同樣是通過XmlPullParser進行Xml文件的解析,在上面的方法中,首先進行xml文件的開始標簽和結束標簽,判斷xml文件內部是否為空節點。然後通過:
Drawable drawable = createFromXmlInner(r, parser, attrs, theme);
進行XML文件解析,最後轉換成Drawable對象。
public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
final Drawable drawable;
final String name = parser.getName();
switch (name) {
case "selector":
drawable = new StateListDrawable();
break;
case "animated-selector":
drawable = new AnimatedStateListDrawable();
break;
case "level-list":
drawable = new LevelListDrawable();
break;
case "layer-list":
drawable = new LayerDrawable();
break;
case "transition":
drawable = new TransitionDrawable();
break;
case "ripple":
drawable = new RippleDrawable();
break;
case "color":
drawable = new ColorDrawable();
break;
case "shape":
drawable = new GradientDrawable();
break;
case "vector":
drawable = new VectorDrawable();
break;
case "animated-vector":
drawable = new AnimatedVectorDrawable();
break;
case "scale":
drawable = new ScaleDrawable();
break;
case "clip":
drawable = new ClipDrawable();
break;
case "rotate":
drawable = new RotateDrawable();
break;
case "animated-rotate":
drawable = new AnimatedRotateDrawable();
break;
case "animation-list":
drawable = new AnimationDrawable();
break;
case "inset":
drawable = new InsetDrawable();
break;
case "bitmap":
drawable = new BitmapDrawable();
break;
case "nine-patch":
drawable = new NinePatchDrawable();
break;
default:
throw new XmlPullParserException(parser.getPositionDescription() +
": invalid drawable tag " + name);
}
drawable.inflate(r, parser, attrs, theme);
return drawable;
}
在createFromXmlInner方法中,首先獲取我們都xml文件的標簽,然後根絕我們對應的標簽名稱創建對應的drawable對象,比如我們這次創建的AnimationDrawable對象。然後調用inflater()方法,由於AnimationDrawable方法中已經對inflater方法進行了重寫,所以此時這個就是:
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimationDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimationDrawable_visible);
updateStateFromTypedArray(a);
a.recycle();
inflateChildElements(r, parser, attrs, theme);
setFrame(0, true, false);
}
至此,我們已經基本理清了從XML文件到Drawable對象的轉換流程,現在我們就開始分析animation-list節點下的節點如何形成一個個幀動畫效果的。在進行分析之前,我們先了解下AnimationState類。這個類用於存儲我們的一系列drawable。通過源碼發現:
private final static class AnimationState extends DrawableContainerState
這個類繼承DrawableContainerState類,DrawableContainerState中有一個成員變量Drawable[] mDrawables;用於存儲我們的drawable信息。明白這一點,我們就可以分析方法inflateChildElements方法。
private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
int type;
final int innerDepth = parser.getDepth()+1;
int depth;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
if (depth > innerDepth || !parser.getName().equals("item")) {
continue;
}
final TypedArray a = obtainAttributes(r, theme, attrs,
R.styleable.AnimationDrawableItem);
final int duration = a.getInt(R.styleable.AnimationDrawableItem_duration, -1);
if (duration < 0) {
throw new XmlPullParserException(parser.getPositionDescription()
+ ": - tag requires a 'duration' attribute");
}
Drawable dr = a.getDrawable(R.styleable.AnimationDrawableItem_drawable);
a.recycle();
if (dr == null) {
while ((type=parser.next()) == XmlPullParser.TEXT) {
// Empty
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException(parser.getPositionDescription()
+ ":
- tag requires a 'drawable' attribute or child tag"
+ " defining a drawable");
}
dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
}
mAnimationState.addFrame(dr, duration);
if (dr != null) {
dr.setCallback(this);
}
}
}
在這方法裡面通過TypeArray獲取drawable的相關信息,然後調用mAnimationState的addFrame方法,將一系列動畫信息就存儲在drawable數組中。
通過上面的分析,一系列的動畫已經轉出並進行了存儲,我們接下來的任務就是進行start的分析,分析動畫的開啟。
public void start() {
mAnimating = true;
if (!isRunning()) {
// Start from 0th frame.
setFrame(0, false, mAnimationState.getChildCount() > 1
|| !mAnimationState.mOneShot);
}
}
通過setFrame方法設置我們的drawable,裡面有selectDrawable(frame)進行設置。
基本的流程就是這個樣子,主要理解使用即可。後面會接著分析幾篇關於動畫的文章。
Android中SQLite應用詳解 上次我向大家介紹了SQLite的基本信息和使用過程,相信朋友們對SQLite已經有所了解了,那今天呢,我就和大家分享一下在Andro
Android中Activity處理返回結果的實現方式,androidactivity大家在網上購物時都有這樣一個體驗,在確認訂單選擇收貨人以及地址時,會跳轉頁面到我們存
點擊文本改變改行背景色,彈出對話框,改行背景 我想單純靠一個文本實現微信回復評論的效果,在一列回復文本中點擊某一行,然後該行的背景色改變並且彈出對話框,如下圖,
Android中如何修改編譯的資源ID值(默認值是0x7F...可以隨意改成0x02~0x7E) 一、技術准備 今天我們來看一下如何修改Android中編譯時的資源I