編輯:關於android開發
標簽(空格分隔): Android基礎入門教程
本節給帶來的是Android動畫中的第三種動畫——屬性動畫(Property Animation),
記得在上一節Android基礎入門教程——8.4.2 Android動畫合集之補間動畫為Fragment
設置過渡動畫的時候,說過,App包和V4包下的Fragment調用setCustomAnimations()對應的
動畫類型是不一樣的,v4包下的是Animation,而app包下的是Animator;
Animation一般動畫就是我們前面學的幀動畫和補間動畫!Animator則是本節要講的屬性動畫!
關於屬性動畫,大牛郭大叔已經寫了三篇非常好的總結文,寫得非常贊,就沒必要重復造輪子了,
不過這裡還是過一遍,大部分內容參考的下面三篇文章:
Android屬性動畫完全解析(上),初識屬性動畫的基本用法
Android屬性動畫完全解析(中),ValueAnimator和ObjectAnimator的高級用法
Android屬性動畫完全解析(下),Interpolator和ViewPropertyAnimator的用法
寫的非常好,或者說你可以直接跳過本文去看上面的三篇文章~
當然,你願意看我叨叨逼的話,也很歡迎,好了,開始本節內容吧~
不BB,直接上圖,就是這麼暴力~
使用流程:
1.調用ValueAnimator的ofInt(),ofFloat()或ofObject()靜態方法創建ValueAnimator實例 2.調用實例的setXxx方法設置動畫持續時間,插值方式,重復次數等 3.調用實例的addUpdateListener添加AnimatorUpdateListener監聽器,在該監聽器中
可以獲得ValueAnimator計算出來的值,你可以值應用到指定對象上~ 4.調用實例的start()方法開啟動畫!
另外我們可以看到ofInt和ofFloat都有個這樣的參數:float/int… values代表可以多個值!
使用示例:
代碼實現:
布局文件:activity_main.xml,非常簡單,四個按鈕,一個ImageView
接著到MainActivity.java,
首先需要一個修改View位置的方法,這裡調用moveView()設置左邊和上邊的起始坐標以及寬高!
接著定義了四個動畫,分別是:直線移動,縮放,旋轉加透明,以及圓形旋轉!
然後通過按鈕觸發對應的動畫~
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_one;
private Button btn_two;
private Button btn_three;
private Button btn_four;
private LinearLayout ly_root;
private ImageView img_babi;
private int width;
private int height;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindViews();
}
private void bindViews() {
ly_root = (LinearLayout) findViewById(R.id.ly_root);
btn_one = (Button) findViewById(R.id.btn_one);
btn_two = (Button) findViewById(R.id.btn_two);
btn_three = (Button) findViewById(R.id.btn_three);
btn_four = (Button) findViewById(R.id.btn_four);
img_babi = (ImageView) findViewById(R.id.img_babi);
btn_one.setOnClickListener(this);
btn_two.setOnClickListener(this);
btn_three.setOnClickListener(this);
btn_four.setOnClickListener(this);
img_babi.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_one:
lineAnimator();
break;
case R.id.btn_two:
scaleAnimator();
break;
case R.id.btn_three:
raAnimator();
break;
case R.id.btn_four:
circleAnimator();
break;
case R.id.img_babi:
Toast.makeText(MainActivity.this, 不愧是coder-pig~, Toast.LENGTH_SHORT).show();
break;
}
}
//定義一個修改ImageView位置的方法
private void moveView(View view, int rawX, int rawY) {
int left = rawX - img_babi.getWidth() / 2;
int top = rawY - img_babi.getHeight();
int width = left + view.getWidth();
int height = top + view.getHeight();
view.layout(left, top, width, height);
}
//定義屬性動畫的方法:
//按軌跡方程來運動
private void lineAnimator() {
width = ly_root.getWidth();
height = ly_root.getHeight();
ValueAnimator xValue = ValueAnimator.ofInt(height,0,height / 4,height / 2,height / 4 * 3 ,height);
xValue.setDuration(3000L);
xValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 軌跡方程 x = width / 2
int y = (Integer) animation.getAnimatedValue();
int x = width / 2;
moveView(img_babi, x, y);
}
});
xValue.setInterpolator(new LinearInterpolator());
xValue.start();
}
//縮放效果
private void scaleAnimator(){
//這裡故意用兩個是想讓大家體會下組合動畫怎麼用而已~
final float scale = 0.5f;
AnimatorSet scaleSet = new AnimatorSet();
ValueAnimator valueAnimatorSmall = ValueAnimator.ofFloat(1.0f, scale);
valueAnimatorSmall.setDuration(500);
ValueAnimator valueAnimatorLarge = ValueAnimator.ofFloat(scale, 1.0f);
valueAnimatorLarge.setDuration(500);
valueAnimatorSmall.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float scale = (Float) animation.getAnimatedValue();
img_babi.setScaleX(scale);
img_babi.setScaleY(scale);
}
});
valueAnimatorLarge.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float scale = (Float) animation.getAnimatedValue();
img_babi.setScaleX(scale);
img_babi.setScaleY(scale);
}
});
scaleSet.play(valueAnimatorLarge).after(valueAnimatorSmall);
scaleSet.start();
//其實可以一個就搞定的
// ValueAnimator vValue = ValueAnimator.ofFloat(1.0f, 0.6f, 1.2f, 1.0f, 0.6f, 1.2f, 1.0f);
// vValue.setDuration(1000L);
// vValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
// @Override
// public void onAnimationUpdate(ValueAnimator animation) {
// float scale = (Float) animation.getAnimatedValue();
// img_babi.setScaleX(scale);
// img_babi.setScaleY(scale);
// }
// });
// vValue.setInterpolator(new LinearInterpolator());
// vValue.start();
}
//旋轉的同時透明度變化
private void raAnimator(){
ValueAnimator rValue = ValueAnimator.ofInt(0, 360);
rValue.setDuration(1000L);
rValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int rotateValue = (Integer) animation.getAnimatedValue();
img_babi.setRotation(rotateValue);
float fractionValue = animation.getAnimatedFraction();
img_babi.setAlpha(fractionValue);
}
});
rValue.setInterpolator(new DecelerateInterpolator());
rValue.start();
}
//圓形旋轉
protected void circleAnimator() {
width = ly_root.getWidth();
height = ly_root.getHeight();
final int R = width / 4;
ValueAnimator tValue = ValueAnimator.ofFloat(0,
(float) (2.0f * Math.PI));
tValue.setDuration(1000);
tValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 圓的參數方程 x = R * sin(t) y = R * cos(t)
float t = (Float) animation.getAnimatedValue();
int x = (int) (R * Math.sin(t) + width / 2);
int y = (int) (R * Math.cos(t) + height / 2);
moveView(img_babi, x, y);
}
});
tValue.setInterpolator(new DecelerateInterpolator());
tValue.start();
}
}
好的,使用的流程非常簡單,先創建ValueAnimator對象,調用ValueAnimator.ofInt/ofFloat
獲得,然後設置動畫持續時間,addUpdateListener添加AnimatorUpdateListener事件監聽,
然後使用參數animation的getAnimatedValue()獲得當前的值,然後我們可以拿著這個值
來修改View的一些屬性,從而形成所謂的動畫效果,接著設置setInterpolator動畫渲染模式,
最後調用start()開始動畫的播放~
臥槽,直線方程,圓的參數方程,我都開始方了,這不是高數的東西麼,
掛科學渣連三角函數都忘了…
例子參考自github:MoveViewValueAnimator
比起ValueAnimator,ObjectAnimator顯得更為易用,通過該類我們可以直接
對任意對象的任意屬性進行動畫操作!沒錯,是任意對象,而不單單只是View對象,
不斷地對對象中的某個屬性值進行賦值,然後根據對象屬性值的改變再來決定如何展現
出來!比如為TextView設置如下動畫:
ObjectAnimator.ofFloat(textview, “alpha”, 1f, 0f);
這裡就是不斷改變alpha的值,從1f - 0f,然後對象根據屬性值的變化來刷新界面顯示,從而
展現出淡入淡出的效果,而在TextView類中並沒有alpha這個屬性,ObjectAnimator內部機制是:
尋找傳輸的屬性名對應的get和set方法~,而非找這個屬性值!
不信的話你可以到TextView的源碼裡找找是否有alpha這個屬性!
好的,下面我們利用ObjectAnimator來實現四種補間動畫的效果吧~
運行效果圖:
代碼實現:
布局直接用的上面那個布局,加了個按鈕,把ImageView換成了TextView,這裡就不貼代碼了,
直接上MainActivity.java部分的代碼,其實都是大同小異的~
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_one;
private Button btn_two;
private Button btn_three;
private Button btn_four;
private Button btn_five;
private LinearLayout ly_root;
private TextView tv_pig;
private int height;
private ObjectAnimator animator1;
private ObjectAnimator animator2;
private ObjectAnimator animator3;
private ObjectAnimator animator4;
private AnimatorSet animSet;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindViews();
initAnimator();
}
private void bindViews() {
ly_root = (LinearLayout) findViewById(R.id.ly_root);
btn_one = (Button) findViewById(R.id.btn_one);
btn_two = (Button) findViewById(R.id.btn_two);
btn_three = (Button) findViewById(R.id.btn_three);
btn_four = (Button) findViewById(R.id.btn_four);
btn_five = (Button) findViewById(R.id.btn_five);
tv_pig = (TextView) findViewById(R.id.tv_pig);
height = ly_root.getHeight();
btn_one.setOnClickListener(this);
btn_two.setOnClickListener(this);
btn_three.setOnClickListener(this);
btn_four.setOnClickListener(this);
btn_five.setOnClickListener(this);
tv_pig.setOnClickListener(this);
}
//初始化動畫
private void initAnimator() {
animator1 = ObjectAnimator.ofFloat(tv_pig, alpha, 1f, 0f, 1f, 0f, 1f);
animator2 = ObjectAnimator.ofFloat(tv_pig, rotation, 0f, 360f, 0f);
animator3 = ObjectAnimator.ofFloat(tv_pig, scaleX, 2f, 4f, 1f, 0.5f, 1f);
animator4 = ObjectAnimator.ofFloat(tv_pig, translationY, height / 8, -100, height / 2);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_one:
animator1.setDuration(3000l);
animator1.start();
break;
case R.id.btn_two:
animator2.setDuration(3000l);
animator2.start();
break;
case R.id.btn_three:
animator3.setDuration(3000l);
animator3.start();
break;
case R.id.btn_four:
animator4.setDuration(3000l);
animator4.start();
break;
case R.id.btn_five:
//將前面的動畫集合到一起~
animSet = new AnimatorSet();
animSet.play(animator4).with(animator3).with(animator2).after(animator1);
animSet.setDuration(5000l);
animSet.start();
break;
case R.id.tv_pig:
Toast.makeText(MainActivity.this, 不愧是coder-pig~, Toast.LENGTH_SHORT).show();
break;
}
}
}
用法也非常簡單,上面涉及到的組合動畫我們下面講~
從上面兩個例子中我們都體驗了一把組合動畫,用到了AnimatorSet這個類!
我們調用的play()方法,然後傳入第一個開始執行的動畫,此時他會返回一個Builder類給我們:接下來我們可以調用Builder給我們提供的四個方法,來組合其他的動畫:
after(Animator anim) 將現有動畫插入到傳入的動畫之後執行 after(long delay) 將現有動畫延遲指定毫秒後執行 before(Animator anim) 將現有動畫插入到傳入的動畫之前執行 with(Animator anim) 將現有動畫和傳入的動畫同時執行嗯,很簡單,接下來要說下動畫事件的監聽,上面我們ValueAnimator的監聽器是
onAnimationStart():動畫開始 onAnimationRepeat():動畫重復執行 onAnimationEnd():動畫結束 onAnimationCancel():動畫取消
AnimatorUpdateListener,當值狀態發生改變時候會回調onAnimationUpdate方法!
除了這種事件外還有:動畫進行狀態的監聽~ AnimatorListener,我們可以調用addListener方法
添加監聽器,然後重寫下面四個回調方法:沒錯,加入你真的用AnimatorListener的話,四個方法你都要重寫,當然和前面的手勢那一節一樣,
Android已經給我們提供好一個適配器類:AnimatorListenerAdapter,該類中已經把每個接口
方法都實現好了,所以我們這裡只寫一個回調方法也可以額!
使用XML來編寫動畫,畫的時間可能比Java代碼長一點,但是重用起來就輕松很多!
android:ordering:指定動畫的播放順序:sequentially(順序執行),together(同時執行) android:duration:動畫的持續時間 android:propertyName=”x”:這裡的x,還記得上面的”alpha”嗎?加載動畫的那個對象裡需要
對應的XML標簽分別為:<animator><objectAnimator><set>
相關的屬性解釋如下:
定義getx和setx的方法,objectAnimator就是通過這裡來修改對象裡的值的! android:valueFrom=”1” :動畫起始的初始值 android:valueTo=”0” :動畫結束的最終值 android:valueType=”floatType”:變化值的數據類型
使用例子如下:
①從0到100平滑過渡的動畫:
②將一個視圖的alpha屬性從1變成0:
③set動畫使用演示:
加載我們的動畫文件:
AnimatorSet set = (AnimatorSet)AnimatorInflater.loadAnimator(mContext,
R.animator.property_animator);
animator.setTarget(view);
animator.start();
Android MediaPlayer的生命周期,androidmediaplayerMediaPlayer的狀態轉換圖也表征了它的生命周期,如下: 這張
Android事件分發 Android 中與 Touch 事件相關的方法包括:dispatchTouchEvent(MotionEvent ev)、onInterce
android --多線程下載過程分析 多線程下載文件的過程是: (1)首先獲得下載文件的長度,然後設置本地文件的長度。 HttpURLConnection.getCo
Android通過achartengine畫折線圖,achartengine折線圖因為前段時間Android項目中用到了折線圖的功能,在查資料的過程中發現acharten