自定義View
基本認知:
雖然Android已經自帶來很多強大的UI控件,但是依舊不能滿足所有開發人員的需求。通常開發人員需要實作設計師精心設計的視覺效果,這樣情況下可能現有的控件就不能滿足需求或者說使用現有的控件實作起來成本太高。這時候,我們隻能通過自定義View實作。是以,自定義View成為了Android開發人員必須掌握的最重要技能之一。自定義View的實作方式有幾種,重寫View無疑是最自由的,同時難度也是最大的。核心步驟分别為尺寸測量與繪制,對應的方法為onMeasure()、onDraw()。
自定義View/ViewGroup的步驟:
1.自定義屬性;
2.選擇和設定構造方法;
3.重寫onMeasure()方法;
4.重寫onDraw()方法;
5.重寫onLayout()方法;
6.重寫其他事件的方法(滑動監聽等)。
步驟詳解:
自定義屬性:
定義自定義屬性:
通常将自定義屬性定義在/values/attr.xml檔案中(attr.xml檔案需要自己建立)。
<?xml version="1.0" encoding="utf-8"?
可以看到,我們先是定義了一個屬性rightPadding,然後又在CustomMenu中引用了這個屬性。下面說明一下:
1、首先,在declare-stylable标簽中直接定義屬性而不需要引用外部定義好的屬性,但是為了屬性的重用,可以選擇上面的這種方法:先定義,後引用;
2、declare-stylable标簽隻是為了給自定義屬性分類。一個項目中可能有多個自定義控件,但隻能有一個attr.xml檔案,是以需要對不同自定義控件中的自定義屬性進行分類,是以declare-stylable标簽中的name屬性往往定義成自定義控件的名稱;
3、在declare-stylable标簽中的引用,就是去掉了外部定義的format屬性,如果沒有去掉format,則會報錯;如果外部定義中沒有format而在内部引用中有format,也一樣會報錯。
常見的format類型:
string:字元串類型;
integer:整數類型;float:浮點型;
dimension:尺寸,後面必須跟dp、dip、px、sp等機關;
Boolean:布爾值;
reference:引用類型,傳入的是某一資源的ID,必須以“@”符号開頭;
color:顔色,必須是“#”符号開頭;
fraction:百分比,必須是“%”符号結尾;enum:枚舉類型
下面對format類型說明幾點:
1、format中可以寫多種類型,中間使用“|”符号分割開,表示這幾種類型都可以傳入這個屬性
2、enum類型的定義示例如下代碼所示:
使用時通過getInt()方法擷取到value并判斷,根據不同的value進行不同的操作即可。
使用自定義屬性:
在XML布局檔案中使用自定義的屬性時,需要先定義一個namespace。Android中預設的namespace是android,是以通常可以使用“android:xxx”的格式去設定一個控件的某個屬性,android這個namespace的定義是在XML檔案的頭标簽中定義的,通常是這樣的:
xmlns:android="http://schemas.android.com/apk/res/android"
自定義的屬性不在這個命名空間下,是以需要添加一個命名空間。自定義屬性的命名空間如下:
xmlns:app="http://schemas.android.com/apk/res-auto"
可以看出來,除了将命名空間的名稱從android改成app之外,就是将最後的“res/android”改成了“res-auto”。
注意:自定義namespace的名稱可以自己定義,不一定非得是app。
擷取自定義屬性:
在自定義View / ViewGroup中,可以通過TypedArray擷取到自定義的屬性。示例代碼如下:
public CustomMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context .getTheme()
.obtainStyledAttributes(attrs, R.styleable.CustomMenu, defStyleAttr, 0);
int indexCount = a.getIndexCount();
for (int i = 0; i int attr = a.getIndex(i);
switch (attr) {
case R.styleable.CustomMenu_rightPadding:
mMenuRightPadding = a.getDimensionPixelSize(attr, 0);
break;
}
}
a.recycle();}
說明:
1、擷取自定義屬性的代碼通常是在三個參數的構造方法中編寫的;
2、在擷取TypedArray對象時就為其綁定了該自定義View的自定義屬性集(CustomMenu),通過getIndexCount()方法擷取到自定義屬性的數量,通過getIndex()方法擷取到某一個屬性,最後通過switch語句判斷屬性并進行相應的操作;
3、在TypedArray使用結束後,需要調用recycle()方法回收它。
構造方法:
當定義一個新的類繼承了View/ViewGroup時,系統都會提示重寫它的構造方法。View/ViewGroup中有四個構造方法可以重寫,它們分别有一、二、三、四個參數。四個參數的構造方法我們通常用不到。
一個參數的構造方法:
構造方法的代碼:public CustomMenu(Context context) { …… }
這個構造方法隻有一個參數Context上下文。當我們在JAVA代碼中直接通過new關鍵字建立,在建立這個控件時,就會調用這個方法。
兩個參數的構造方法:
構造方法的代碼:public CustomMenu(Context context, AttributeSet attrs) { …… }
這個構造方法有兩個參數:Context上下文和AttributeSet屬性集。當需要在自定義控件中擷取屬性時,就預設調用這個構造方法。AttributeSet對象就是這個控件中定義的所有屬性。
我們通過AttributeSet對象的getAttributeCount()方法擷取屬性的個數,通過getAttributeName()方法擷取到某條屬性的名稱,通過getAttributeValue()方法擷取到某條屬性的值。
注意:不管有沒有使用自定義屬性,都會預設調用這個構造方法。
三個參數的構造方法:
構造方法的代碼:public CustomMenu(Context context, AttributeSet attrs, int defStyleAttr) { …… }
這個構造方法中有三個參數:Context上下文、AttributeSet屬性集和defStyleAttr自定義屬性的引用。這個構造方法不會預設調用,必須要手動調用,這個構造方法和兩個參數的構造方法的唯一差別就是這個構造方法給我們預設傳入了一個預設屬性集。
defStyleAttr指向的是自定義屬性的
三個構造方法的整合:
一般情況下,會将這三個構造方法串聯起來,即層層調用,讓最終的業務處理都集中在三個參數的構造方法。讓一參的構造方法引用兩參的構造方法,兩參的構造方法引用三參的構造方法,就可以保證無論使用什麼方式建立這個控件,最終都會到三個參數的構造方法中處理,減少了重複代碼。示例代碼如下:
public CustomMenu(Context context) {
this(context, null);}public CustomMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);}public CustomMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 業務代碼}
onMeasure():
onMeasure()方法中主要負責測量,決定控件本身或其子控件所占的寬高。可以通過onMeasure()方法提供的參數widthMeasureSpec和heightMeasureSpec來分别擷取控件寬度和高度的測量模式和測量值(測量 = 測量模式 + 測量值)。
widthMeasureSpec和heightMeasureSpec雖然隻是int類型的值,但它們是通過MeasureSpec類進行了編碼處理的,其中封裝了測量模式和測量值,是以可以分别通過MeasureSpec.getMode(xMeasureSpec)和MeasureSpec. getSize(xMeasureSpec)來擷取到控件或其子View的測量模式和測量值。
onMeasure()方法中常用的方法:
1、getChildCount()//擷取子View的數量;2、getChildAt(i)//擷取第i個子控件;3、subView.getLayoutParams().width/height//設定或擷取子控件的寬或高;4、measureChild(child, widthMeasureSpec, heightMeasureSpec)//測量子View的寬高;5、child.getMeasuredHeight/width()//執行完measureChild()方法後就可以通過這種方式擷取子View的寬高值;6、getPaddingLeft/Right/Top/Bottom()//擷取控件的四周内邊距;7、setMeasuredDimension(width, height)//重新設定控件的寬高。如果寫了這句代碼,就需要删除“super.onMeasure(widthMeasureSpec, heightMeasureSpec);”這行代碼。
onDraw():
onDraw()方法負責繪制,每次觸摸了自定義View/ViewGroup時都會觸發onDraw()方法。
Paint類:
Paint畫筆對象,這個類中包含了如何繪制幾何圖形、文字和位圖的樣式和顔色資訊,指定了如何繪制文本和圖形。畫筆對象有很多設定方法,大體上可以分為兩類:一類與圖形繪制有關,一類與文本繪制有關。
1、圖像繪制:
1) setArgb(int a, int r, int g, int b):設定繪制的顔色,a表示透明度,r、g、b表示顔色值;2) setAlpha(int a):設定繪制的圖形的透明度;3) setColor(int color):設定繪制的顔色;4) setAntiAlias(boolean a):設定是否使用抗鋸齒功能,抗鋸齒功能會消耗較大資源,繪制圖形的速度會減慢;5) setDither(boolean b):設定是否使用圖像抖動處理,會使圖像顔色更加平滑飽滿,更加清晰;6) setFileterBitmap(Boolean b):設定是否在動畫中濾掉Bitmap的優化,可以加快顯示速度;7) setMaskFilter(MaskFilter mf):設定MaskFilter來實作濾鏡的效果;8) setColorFilter(ColorFilter cf):設定顔色過濾器,可以在繪制顔色時實作不同顔色的變換效果;9) setPathEffect(PathEffect pe):設定繪制的路徑的效果;10) setShader(Shader s):設定Shader繪制各種漸變效果;11) setShadowLayer(float r, int x, int y, int c):在圖形下面設定陰影層,r為陰影角度,x和y為陰影在x軸和y軸上的距離,c為陰影的顔色;12) setStyle(Paint.Style s):設定畫筆的樣式:FILL實心;STROKE空心;FILL_OR_STROKE同時實心與空心;13) setStrokeCap(Paint.Cap c):當設定畫筆樣式為STROKE或FILL_OR_STROKE時,設定筆刷的圖形樣式;14) setStrokeJoin(Paint.Join j):設定繪制時各圖形的結合方式;15) setStrokeWidth(float w):當畫筆樣式為STROKE或FILL_OR_STROKE時,設定筆刷的粗細度;16) setXfermode(Xfermode m):設定圖形重疊時的處理方式;
2、文本繪制:
1) setTextAlign(Path.Align a):設定繪制的文本的對齊方式;2) setTextScaleX(float s):設定文本在X軸的縮放比例,可以實作文字的拉伸效果;3) setTextSize(float s):設定字号;4) setTextSkewX(float s):設定斜體文字,s是文字傾斜度;5) setTypeFace(TypeFace tf):設定字型風格,包括粗體、斜體等;6) setUnderlineText(boolean b):設定繪制的文本是否帶有下劃線效果;7) setStrikeThruText(boolean b):設定繪制的文本是否帶有删除線效果;8) setFakeBoldText(boolean b):模拟實作粗體文字,如果設定在小字型上效果會非常差;9) setSubpixelText(boolean b):如果設定為true則有助于文本在LCD螢幕上顯示效果;
Canvas類:
Canvas即畫布,其上可以使用Paint畫筆對象繪制很多東西。
Canvas對象中可以繪制:
1) drawArc():繪制圓弧;
2) drawBitmap():繪制Bitmap圖像;
3) drawCircle():繪制圓圈;
4) drawLine():繪制線條;
5) drawOval():繪制橢圓;
6) drawPath():繪制Path路徑;
7) drawPicture():繪制Picture圖檔;
8) drawRect():繪制矩形;
9) drawRoundRect():繪制圓角矩形;
10) drawText():繪制文本;
11) drawVertices():繪制頂點。
Canvas對象的其他方法:
1) canvas.save():把目前繪制的圖像儲存起來,讓後續的操作相當于是在一個新圖層上繪制;
2) canvas.restore():把目前畫布調整到上一個save()之前的狀态;
3) canvas.translate(dx, dy):把目前畫布的原點移到(dx, dy)點,後續操作都以(dx, dy)點作為參照;
4) canvas.scale(x, y):将目前畫布在水準方向上縮放x倍,豎直方向上縮放y倍;
5) canvas.rotate(angle):将目前畫布順時針旋轉angle度。
onLayout():
onLayout()方法負責布局,大多數情況是在自定義ViewGroup中才會重寫,主要用來确定子View在這個布局空間中的擺放位置。onLayout(boolean changed, int l, int t, int r, int b)方法有5個參數,其中changed表示這個控件是否有了新的尺寸或位置;l、t、r、b分别表示這個View相對于父布局的左/上/右/下方的位置。
以下是onLayout()方法中常用的方法:
1) getChildCount():擷取子View的數量;
2) getChildAt(i):擷取第i個子View
3) getWidth/Height():擷取onMeasure()中傳回的寬度和高度的測量值;
4) child.getLayoutParams():擷取到子View的LayoutParams對象;
5) child.getMeasuredWidth/Height():擷取onMeasure()方法中測量的子View的寬度和高度值;
6) getPaddingLeft/Right/Top/Bottom():擷取控件的四周内邊距;
7) child.layout(l, t, r, b):設定子View布局的上下左右邊的坐标。
其他方法:
generateLayoutParams():
generateLayoutParams()方法用在自定義ViewGroup中,用來指明子控件之間的關系,即與目前的ViewGroup對應的LayoutParams。我們隻需要在方法中傳回一個我們想要使用的LayoutParams類型的對象即可。在generateLayoutParams()方法中需要傳入一個AttributeSet對象作為參數,這個對象是這個ViewGroup的屬性集,系統根據這個ViewGroup的屬性集來定義子View的布局規則,供子View使用。
onTouchEvent():
onTouchEvent()方法用來監測使用者手指操作。通過方法中MotionEvent參數對象的getAction()方法來實時擷取使用者的手勢,有UP、DOWN和MOVE三個枚舉值,分别表示用于手指擡起、按下和滑動的動作。每當使用者有操作時,就會回掉onTouchEvent()方法
onScrollChanged():
如果自定義View / ViewGroup是繼承自ScrollView / HorizontalScrollView等可以滾動的控件,就可以通過重寫onScrollChanged()方法來監聽控件的滾動事件。這個方法中有四個參數:l和t分别表示目前滑動到的點在水準和豎直方向上的坐标;oldl和oldt分别表示上次滑動到的點在水準和豎直方向上的坐标。我們可以通過這四個值對滑動進行處理,如添加屬性動畫等。
invalidate():
nvalidate()方法的作用是請求View樹進行重繪,即draw()方法,如果視圖的大小發生了變化,還會調用layout()方法。
一般會引起invalidate()操作的函數如下:
1) 直接調用invalidate()方法,請求重新draw(),但隻會繪制調用者本身;
2) 調用setSelection()方法,請求重新draw(),但隻會繪制調用者本身;
3) 調用setVisibility()方法,會間接調用invalidate()方法,繼而繪制該View;
4) 調用setEnabled()方法,請求重新draw(),但不會重新繪制任何視圖,包括調用者本身。
postInvalidate():
功能與invalidate()方法相同,隻是postInvalidate()方法是異步請求重繪視圖。
requestLayout():
requestLayout()方法隻是對View樹進行重新布局layout過程(包括measure()過程和layout()過程),不會調用draw()過程,即不會重新繪制任何視圖,包括該調用者本身。
requestFocus():
請求View樹的draw()過程,但隻會繪制需要重繪的視圖,即哪個View或ViewGroup調用了這個方法,就重繪哪個視圖。
小結:
1、onMeasure()會在初始化之後調用一到多次來測量控件或其中的子控件的寬高;
2、onLayout()會在onMeasure()方法之後被調用一次,将控件或其子控件進行布局;
3、onDraw()會在onLayout()方法之後調用一次,也會在使用者手指觸摸螢幕時被調用多次,來繪制控件。
實作的三種方式:
1.繼承控件:繼承現有控件,對其控件的功能進行拓展
2.組合控件:将現有控件進行組合,實作功能更加強大的控件
3.自繪控件:重寫View,實作全新的控件
自定義控件代碼:
public class CounterView extends View implements View.OnClickListener {
private Paint mPaint;
private Rect mRect;//擷取文字的寬高
private int mCounter;
public CounterView(Context context) {
super(context);
}
public CounterView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//初始化畫筆、Rect
mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
mRect=new Rect();
setOnClickListener(this);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.CYAN);
//繪制一個填充色為青藍色的圓形
canvas.drawRect(0,0,getWidth(),getHeight(),mPaint);
mPaint.setColor(Color.WHITE);
mPaint.setTextSize(150);
String text=String.valueOf(mCounter);
//擷取文字的寬高
mPaint.getTextBounds(text,0,text.length(),mRect);
float textWidth=mRect.width();
float textHeight=mRect.height();
//繪制字元串
canvas.drawText(text,getWidth()/2-textWidth/2,getHeight()/2+textHeight/2,mPaint);
}
@Override
public void onClick(View v) {
mCounter++;
invalidate(); //重繪
}}
在MainActivity中加載activity_main.xml布局,布局中使用剛才繪制的自定義View
<?xml version="1.0" encoding="utf-8"? xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" android:id="@+id/counter_view"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_gravity="center"
android:layout_margin="20dp" / android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="20dp"
android:gravity="bottom"
android:text="點選矩形按鈕可以重新繪制View" /
效果圖:
動畫
動畫
基本認知:
Android系統提供了很多豐富的API去實作UI的2D與3D動畫,最主要的劃分可以分為如下幾類:
View Animation(視圖/補間動畫): 視圖動畫在古老的Android版本系統中就已經提供了,隻能被用來設定View的動畫。
Frame Animation(幀動畫): 其實可以劃分到視圖動畫的類别,專門用來一個一個的顯示Drawable的resources,就像放幻燈片一樣。
Property Animation(屬性動畫): 屬性動畫隻對Android 3.0(API 11)以上版本的Android系統才有效,這種動畫可以設定給任何Object,包括那些還沒有渲染到螢幕上的對象。這種動畫是可擴充的,可以讓你自定義任何類型和屬性的動畫。
補間動畫:
屬性詳解:
在補間動畫中主要可以實作視圖的位移(translate)、縮放(scale)、旋轉(rotate)、淡入淡出(alpha)四種效果。其中的主要屬性如下:
Animation屬性詳解
xml屬性java方法解釋android:detachWallpapersetDetachWallpaper(boolean)是否在桌面上運作android:durationsetDuration(long)動畫持續時間,毫秒為機關android:fillAftersetFillAfter(boolean)控件動畫結束時是否保持動畫最後的狀态android:fillBeforesetFillBefore(boolean)控件動畫結束時是否還原到開始動畫前的狀态android:interpolatorsetInterpolator(Interpolator)設定插值器(指定的動畫效果,譬如回彈等)android:repeatCountsetRepeatCount(int)重複次數android:repeatModesetRepeatMode(int)重複類型有兩個值,reverse表示倒序回放,restart表示從頭播放android:startOffsetsetStartOffset(long)調用start函數之後等待開始運作的時間,機關為毫秒android:zAdjustmentsetZAdjustment(int)表示被設定動畫的内容運作時在Z軸上的位置(top/bottom/normal),預設為normal
Alpha屬性詳解
xml屬性java方法解釋android:fromAlphaAlphaAnimation(float fromAlpha, …)動畫開始的透明度(0.0到1.0,0.0是全透明,1.0是不透明)android:toAlphaAlphaAnimation(…, float toAlpha)動畫結束的透明度,同上
Rotate屬性詳解
xml屬性java方法解釋android:fromDegreesRotateAnimation(float fromDegrees, …)旋轉開始角度,正代表順時針度數,負代表逆時針度數android:toDegreesRotateAnimation(…, float toDegrees, …)旋轉結束角度,正代表順時針度數,負代表逆時針度數android:pivotXRotateAnimation(…, float pivotX, …)縮放起點X坐标(數值、百分數、百分數p,譬如50表示以目前View左上角坐标加50px為初始點、50%表示以目前View的左上角加上目前View寬高的50%做為初始點、50%p表示以目前View的左上角加上父控件寬高的50%做為初始點)android:pivotYRotateAnimation(…, float pivotY)縮放起點Y坐标,同上規律
Translate屬性詳解
xml屬性java方法解釋android:fromXDeltaTranslateAnimation(float fromXDelta, …)起始點X軸坐标(數值、百分數、百分數p,譬如50表示以目前View左上角坐标加50px為初始點、50%表示以目前View的左上角加上目前View寬高的50%做為初始點、50%p表示以目前View的左上角加上父控件寬高的50%做為初始點)android:fromYDeltaTranslateAnimation(…, float fromYDelta, …)起始點Y軸從标,同上規律android:toXDeltaTranslateAnimation(…, float toXDelta, …)結束點X軸坐标,同上規律android:toYDeltaTranslateAnimation(…, float toYDelta)結束點Y軸坐标,同上規律
Scale屬性詳解
xml屬性java方法解釋android:fromXScaleScaleAnimation(float fromX, …)初始X軸縮放比例,1.0表示無變化android:toXScaleScaleAnimation(…, float toX, …)結束X軸縮放比例android:fromYScaleScaleAnimation(…, float fromY, …)初始Y軸縮放比例android:toYScaleScaleAnimation(…, float toY, …)結束Y軸縮放比例android:pivotXScaleAnimation(…, float pivotX, …)縮放起點X坐标(數值、百分數、百分數p,譬如50表示以目前View左上角坐标加50px為初始點、50%表示以目前View的左上角加上目前View寬高的50%做為初始點、50%p表示以目前View的左上角加上父控件寬高的50%做為初始點)android:pivotYScaleAnimation(…, float pivotY)縮放起點Y坐标,同上規律
xml檔案中定義
xml定義動畫
<?xml version="1.0" encoding="utf-8"?
android:fromXScale="1.0"
android:toXScale="1.4"
android:fromYScale="1.0"
android:toYScale="0.6"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="700" /
在java使用動畫資源
Animation animation = AnimationUtils.loadAnimation(context,R.anim.view_anin);
image.startAnimation(animation);
java檔案中定義
RotateAnimation rotateAnimation = new RotateAnimation(0,180);rotateAnimation.setDuration(400);image.startAnimation(rotateAnimation);
幀動畫:
它通過加載圖檔資源,将多張圖檔一幀一幀顯示形成動畫效果。在Android中提供了兩種方式為AnimationDrawable添加幀:XML定義的資源檔案和Java代碼建立。
AnimationDrawable的常用方法
void start()
:開始播放逐幀動畫。
void stop()
:停止播放逐幀動畫。
void addFrame(Drawable frame,int duration)
:為AnimationDrawable添加一幀,并設定持續時間。
int getDuration(int i)
:得到指定index的幀的持續時間。
Drawable getFrame(int index)
:得到指定index的幀Drawable。
int getNumberOfFrames()
:得到目前AnimationDrawable的所有幀數量。
boolean isOneShot()
:目前AnimationDrawable是否執行一次,傳回true執行一次,false循環播放。
boolean isRunning()
:目前AnimationDrawable是否正在播放。
void setOneShot(boolean oneShot)
:設定AnimationDrawable是否執行一次,true執行一次,false循環播放。
在xml檔案中定義資源檔案
1.xml檔案中定義
<?xml version="1.0" encoding="utf-8"? android:oneshot="false"
2.在java中調用
// 通過逐幀動畫的資源檔案獲得AnimationDrawable示例
AnimationDrawable animationDrawable = (AnimationDrawable) getResources().getDrawable(R.drawable.animation_loading);
image.setImageDrawable(animationDrawable);
animationDrawable.start();
使用java定義資源檔案
AnimationDrawable drawable = new AnimationDrawable();drawable.addFrame(getResources().getDrawable(R.drawable.loading_1),100);drawable.addFrame(getResources().getDrawable(R.drawable.loading_2),100);drawable.addFrame(getResources().getDrawable(R.drawable.loading_3),100);drawable.addFrame(getResources().getDrawable(R.drawable.loading_4),100);drawable.setOneShot(true);image.setImageDrawable(drawable);drawable.start();
屬性動畫:
特點:
Duration:可以指定動畫的持續時間。預設長度為300毫秒;
Time interpolation:可以指定該屬性的值如何作為動畫的目前的運作時間的函數來計算;
Repeat count and behavior:指定動畫的播放次數,還可定義是否反向播放動畫;
Animator sets:動畫集合,即可以同時對一個對象應用多個動畫,這些動畫可以同時播放也可以對不同動畫設定不同的延遲;
Frame refresh delay:多少時間重新整理一次動畫,即每隔多少時間計算一次屬性值,預設10ms。最終取決于系統整體多麼繁忙,系統如何能夠快速的服務基礎計時器。
工作原理:
ValueAnimator:是動畫的執行類,跟蹤動畫的時間,并且它是動畫的屬性的目前值。
TimeInterpolator:ValueAnimator封裝了動畫的
TimeInterpolator
時間插值器,定義動畫的插入。
TypeEvaluator:用于設定動畫屬性的值。
要啟動動畫,需要建立一個ValueAnimator,并且指定目标對象屬性的開始、結束值和持續時間。在調用start後,整個動畫過程中, ValueAnimator會根據已經完成的動畫時間計算得到一個0到1之間的分數,代表該動畫的已完成動畫百分比。0表示0%,1表示100%。
當ValueAnimator計算完已完成動畫分數後,它會調用目前設定的TimeInterpolator,去計算得到一個interpolated(插值)分數,在計算過程中,已完成動畫百分比會被加入到新的插值計算中。
當插值分數計算完成後,
ValueAnimator
會根據插值分數調用合适的
TypeEvaluator
去計算運動中的屬性值。
具體使用:
ValueAnimator
ValueAnimator
是屬性動畫的核心類。使用的時候需要添加監聽
AnimatorUpdateListener
監聽,在監聽方法中對需要執行動畫的對象設定目前的屬性值。
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);animation.setDuration(1000);animation.start();animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator updatedAnimation) {
float animatedValue = (float)updatedAnimation.getAnimatedValue();
textView.setTranslationX(animatedValue);
}});
ObjectAnimator
ObjectAnimato
r是
ValueAnimator
的一個子類
ObjectAnimator.ofFloat(textview,"rotationX",0.0f,180f)
.setDuration(100)
.start();
AnimatorSet組合動畫
after(Animator anim): 将現有動畫插入到傳入的動畫之後執行
after(long delay): 将現有動畫延遲指定毫秒後執行
before(Animator anim): 将現有動畫插入到傳入的動畫之前執行
with(Animator anim): 将現有動畫和傳入的動畫同時執行
ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);AnimatorSet animSet = new AnimatorSet();animSet.play(rotate).with(fadeInOut).after(moveIn);animSet.setDuration(5000);animSet.start();
使用xml聲明動畫
通過自定義的xml進行聲明動畫,可以進行動畫的重用,更輕松地編輯動畫序列。為了區分使用來自那些使用傳統的新屬性動畫的API動畫檔案(視圖動畫)架構,從Android 3.1開始,屬性動畫的xml檔案應儲存在
res/animator/
目錄下。
1.xml檔案:
<?xml version="1.0" encoding="utf-8"?
android:ordering="together" android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="0.5" android:duration="1000"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="0.5"
2.在java中調用:
// 加載動畫 Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scale); mMv.setPivotX(0); mMv.setPivotY(0); //顯示的調用invalidate mMv.invalidate(); anim.setTarget(mMv); anim.start();
Animation監聽器:
Animator
提供了一個
addListener()
的方法,這個方法接收一個
AnimatorListener
,我們隻需要去實作這個
AnimatorListener
就可以監聽動畫的各種事件了。
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//動畫啟動時調用
}
@Override
public void onAnimationEnd(Animator animation) {
//當動畫結束時調用
}
@Override
public void onAnimationCancel(Animator animation) {
//當動畫被取消調用,被取消的動畫還會調用onAnimationEnd方法
}
@Override
public void onAnimationRepeat(Animator animation) {
//當動畫重演調用
}
});
插值器(Interpolator)與估值器(TypeEvaluator):
插值器:
TranslateAnimation rotateAnimation = new TranslateAnimation(0,200,0,200);rotateAnimation.setDuration(400);//建立對于的插值器OvershootInterpolator interpolator = new OvershootInterpolator();//設定插值器rotateAnimation.setInterpolator(interpolator);image.startAnimation(rotateAnimation);
估值器:
系統内置了3個估值器,分别是:
IntEvaluator:整數屬性值。
FloatEvaluator:浮點型屬性值。
ArgbEvaluator:十六進制color屬性值。
ObjectAnimator objectAnimator = ObjectAnimator.ofObject(image,"alpha",new IntEvaluator(),1,0,1);objectAnimator.setDuration(500);objectAnimator.start();