什麼是屬性動畫
見名知義,屬性動畫通過控制對象的屬性,(
修改控件的屬性值
)來實作動畫效果。屬性動畫是在Android3.0之後引進的,它非常的強大,可以比較簡單的實作許多視圖動畫做不到的事情。
在使用屬性動畫之前先來看幾個常用的View屬性成員:
-
:控制View的位置,值是相對于View容器左上角坐标的偏移。translationX,translationY,translationZ
-
:控制相對于軸心旋轉。(rotationX,rotationY
)0f-> 360f
- x,y:控制View在容器中的位置,即左上角坐标加上translationX和translationY的值。
- alpha:控制View對象的alpha透明度值。(
)0f-> 1f
- 縮放:水準縮放
,垂直縮放scaleX
scaleY
ValueAnimator 是ObjectAnimato的父類:
-
:傳回一個int型變化的ValueAnimator。ValueAnimator ofInt (int... values)
-
:傳回一個float型變化的ValueAnimator。ValueAnimator ofFloat (float... values)
-
傳回一個object型變化的ValueAnimator。ValueAnimator ofObject (TypeEvaluator evaluator, Object... values):
-
ValueAnimator ofArgb (int... values)
:傳回一個顔色值變化的ValueAnimator,API
LEVEL 21引入。
位移屬性動畫基本使用
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary">
<LinearLayout
android:id="@+id/llAddAccount"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_alignParentRight="true"
android:layout_marginTop="100dp"
android:layout_marginRight="-70dp"//将現有視圖藏在螢幕的右邊
android:background="@drawable/bg_10_10_fff">
<ImageView
android:id="@+id/ivMakeNote"
android:layout_width="35dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:paddingLeft="2dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:src="@mipmap/ic_account_add" />
<TextView
android:id="@+id/tvAddAccount"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:paddingRight="12dp"
android:text="添加賬戶"
android:textColor="@color/colorPrimary"
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>
mLinearLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ObjectAnimator animator;
if(!flag){
animator = ObjectAnimator.ofFloat(mLinearLayout,"translationX",0f,-70f);
flag = true;
}else {
animator = ObjectAnimator.ofFloat(mLinearLayout,"translationX",0f,0f);
//animator.setInterpolator(new OvershootInterpolator());
flag = false;
}
animator.start();
}
});
通過
ObjectAnimator
的工廠方法
ofFloat
我們得到一個
ObjectAnimator
對象,并通過該對象的
start()
方法,開啟動畫效果。
ofFloat()
方法的第一個參數為要實作動畫效果的View,例如這裡整體效果的
LinearLayout
;第二個參數為屬性名,也就是前面所說的:
translationX,translationY,alpha,rotation,scaleX,scaleY
等,這裡要實作的是水準平移效果,是以我們采用了
translationX
;第三參數為可變長參數,
第一個值為動畫開始的位置,第二個值為結束值得位置
,如果數組大于3位數,那麼前者将是後者的起始位置。
translationX
和
translationY
這裡涉及到的位移都是相對自身位置而言。
例如: View在點A(x,y)要移動到點B(x1,y1),那麼ofFloat()方法的可變長參數,第一個值應該0f,第二個值應該x1-x。
XML布局實作:
在res/animator檔案夾下,建立animator_translation.xml檔案,内容如下:
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="translationX"
android:valueFrom="0dp"
android:valueTo="-70dp"
android:valueType="floatType"
/>
ObjectAnimator animator = AnimatorInflater.loadAnimator(this,R.animator.animator_translation);
animator.setTarget(mLinearLayout);
animator.start();
淡入淡出透明屬性動畫
mTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mTextView,
"alpha",1f,0f,1f);
objectAnimator.setDuration(3000);
objectAnimator.start();
}
});
縮放屬性動畫基本使用
//第一個參數是控件,第二個是選擇什麼動畫屬性 例如 scaleX(x軸縮放),scaleY
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mTextView,
"scaleX",1f,2f,3f,2f,1f);
objectAnimator.setDuration(3000);//動畫持續時間
objectAnimator.setRepeatCount(2);//動畫重複次數
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);//動畫持續模式 上一次效果反着來
objectAnimator.start();
旋轉屬性動畫基本使用
//ofFloat()方法的可變長參數,如果後者的值大于前者,
// 那麼順時針旋轉,小于前者,則逆時針旋轉。
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mTextView,
"rotation",0f,180f,0f,-360f,0f);
objectAnimator.setDuration(3000);//動畫持續時間
objectAnimator.start();
AnimatorSet
代碼直接利用 AnimatorSet() 如果是XML定義AnimatorSet 利用AnimatorInflater.loadAnimator()加載(使用較少)
<set android:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
</set>
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.animator.property_animator);
set.setTarget(mTextView);
set.start();
AnimatorSet可以作用于ObjectAnimator和ValueAnimator,但通常ObjectAnimator用的比較多。
AnimatorSet的相關函數:
-
,設定之後内部子動畫的插值器都是這個setInterpolator (TimeInterpolator interpolator)
-
,設定之後所有内部子動畫都作用于相同的target目标對象setTarget(Object target)
-
,它不會覆寫子動畫開始延遲,隻對AnimatorSet的開始時間起作用,是以它會延後AnimatorSet激活整體動畫的開始時間setStartDelay(long startDelay)
-
取消動畫,會取消AnimatorSet中的所有子動畫。cancle()
-
結束動畫,會結束AnimatorSet中的所有子動畫。end()
-
擷取所有受AnimatorSet控制的動畫getChildAnimations()
-
,AnimationSet動畫是否開始了,true開始isStarted()
-
isRunning()
,AnimationSet開始之後(isStarted =
true),内部是否有子動畫正在執行,有動畫執行傳回true
-
暫停動畫,pause()
-
恢複暫停的動畫resume()
-
擷取Builder對象play(Animator anim)
函數
playTogether
和
playSequentially
的差別:
多個動畫同時執行,可以是對一個對象執行的多個動畫,也可以是對多個對象的多個動畫。
animatorSet.playTogether():
//利用集合添加動畫
playTogether(Collection<Animator> items)
//利用可變參數添加動畫
playTogether(Animator... items)
ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f);
ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 50);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4);
animatorSet.setDuration(3000);
animatorSet.start();
效果和animatorSet.playTogether()差不多
PropertyValuesHolder holder1=PropertyValuesHolder.ofFloat("rotation",0f,360f,0f);
PropertyValuesHolder holder2=PropertyValuesHolder.ofFloat("translationX",0f,600f);
PropertyValuesHolder holder3=PropertyValuesHolder.ofFloat("alpha",1f,0f,1f);
ObjectAnimator objectAnimator=ObjectAnimator.ofPropertyValuesHolder(sun,holder1,holder2,holder3);
objectAnimator.setDuration(3000);
objectAnimator.setInterpolator(new OvershootInterpolator());//插值器
objectAnimator.start();
如果多個動畫同時對控件的同一個屬性進行操作,會按照playTogether添加的最後一個動畫覆寫前面操作相同屬性的動畫,也可能沒有覆寫,但确實是最後一個添加的動畫起了作用。
順序播放動畫:
playSequentially
playSequentially(List<Animator> items)
playSequentially(Animator... items)
是一個動畫執行完後執行下一個動畫,但如果前一個動畫是無限循環,下一個動畫永遠不會執行。
playSequentially
ObjectAnimator objectAnimator5 = ObjectAnimator.ofFloat(mTextView, "translationY", 200, 450);
ObjectAnimator objectAnimator6 = ObjectAnimator.ofFloat(mTextView, "translationY", 300, 600);
ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f);
ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 250);
AnimatorSet animatorSet = new AnimatorSet();
//按順序執行動畫
animatorSet.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4,objectAnimator5,objectAnimator6);
animatorSet.setDuration(5000);
animatorSet.start();
//實作動畫無限循環
objectAnimator1.setRepeatCount(-1);
animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4,objectAnimator5,objectAnimator6);
利用play(Animator)建構Builder對象
Builder play(Animator anim);生成builder對象,Builder能夠控制動畫的執行順序和互相之間的依賴。
Builder的函數:
-
和前面動畫一起執行public Builder with(Animator anim)
-
執行前面的動畫後再執行該動畫public Builder before(Animator anim)
-
先執行這個動畫再執行前面動畫public Builder after(Animator anim)
-
延遲n毫秒之後執行動畫public Builder after(long delay)
//按函數性質執行動畫
animatorSet.play(objectAnimator1).with(objectAnimator2).before(objectAnimator3);
animatorSet.setDuration(5000);
animatorSet.start();
/*
* 鍊式調用動畫執行順序總結如下:
Builder鍊式調用中會先執行after函數中的動畫(有多個同時執行),
* 然後執行play和with函數(有多個同時執行)中的動畫,
* 最後執行before函數中的動畫(有多個同時執行)
* */
動畫監聽
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
//需要api19
animatorSet.addPauseListener(new Animator.AnimatorPauseListener() {
@Override
public void onAnimationPause(Animator animation) {
}
@Override
public void onAnimationResume(Animator animation) {
}
});
ViewPropertyAnimator 動畫
//ViewPropertyAnimator 動畫,隻是針對View對象的特定屬性同時播放動畫
/*
* 支援屬性:
translationX、translationY、translationZ
x、y、z
alpha
scaleX、scaleY
*
* */
mTextView.animate().translationX(100f).translationY(100f).translationZ(20f).
setInterpolator(new OvershootInterpolator()).start();
//ViewPropertyAnimator 動畫,隻是針對View對象的特定屬性同時播放動畫
ViewPropertyAnimator viewPropertyAnimator = mTextView.animate();
viewPropertyAnimator.setDuration(2000);
viewPropertyAnimator.translationX(100f);//點選一次向右偏移,之後點選無效果(一次性)
//viewPropertyAnimator.translationXBy(100f);//每次點選都會向右偏移,重複利用
viewPropertyAnimator.start();
估值器與插值器
插值器:根據時間流逝的百分比計算出目前屬性值改變的百分比。
正常情況下,預設的插值器已經夠用,如果自己數學厲害,想顯擺一下,
也是通過實作TimeInterpolator接口的getInterpolation()自定義
的。
/**
* A time interpolator defines the rate of change of an animation. This allows animations
* to have non-linear motion, such as acceleration and deceleration.
*/
public interface TimeInterpolator {
/**
* Maps a value representing the elapsed fraction of an animation to a value that represents
* the interpolated fraction. This interpolated value is then multiplied by the change in
* value of an animation to derive the animated value at the current elapsed animation time.
*
* @param input A value between 0 and 1.0 indicating our current point
* in the animation where 0 represents the start and 1.0 represents
* the end
* @return The interpolation value. This value can be more than 1.0 for
* interpolators which overshoot their targets, or less than 0 for
* interpolators that undershoot their targets.
*/
float getInterpolation(float input);
}
估值器:根據目前屬性改變的百分比來計算改變後的屬性值,移動的位置;
自定義估值器:抛物線
//自定義估值器,重寫計算規則,多利用數學公式
class BallDownEvaluator implements TypeEvaluator<PointF>{
/** * @param fraction 動畫執行了的百分比,
* * @param startValue 點的起始值 *
* @param endValue 點的最終值 * @return
* */
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
//以後可以利用估值器實作更多的曲線動畫,比如貝塞爾、正弦餘弦動畫等。
//抛物線方程式 s=1/2*g*t*t
//定義初速度150,加速g=9.8,時間t=5s,就是動畫設定的執行時間
float time = 5* fraction* 1.0f;
PointF pointF = new PointF();
pointF.x = 150 * time;
pointF.y = 0.5f * 98.0f *time *time;
return pointF;
}
}
mTextView.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onClick(View view) {
//ValueAnimator 是 ObjectAnimator 的父類
//太陽下山抛物線
ObjectAnimator objectAnimator = new ObjectAnimator();
BallDownEvaluator ball = new BallDownEvaluator();
objectAnimator.setDuration(5000);
//1.先設定value 位置(0,0)
objectAnimator.setObjectValues(new PointF(0,0));
//2.再設定估值器
objectAnimator.setEvaluator(ball);
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
PointF pointF = (PointF) valueAnimator.getAnimatedValue();
//通過不斷的改變view(sun)的坐标來實作抛物線動畫
sun.setX(pointF.x);
sun.setY(pointF.y);
}
});
objectAnimator.start();
}
});
keyFrame(關鍵幀)
假如覺得自定義自定義插值器或估值器有難度,也可以使用關鍵幀
Keyframe對象
來實作
。Keyframe
讓我們可以指定某個屬性百分比時對象的屬性值。
Keyframe start = Keyframe.ofFloat(0f,0f);
Keyframe middle1 = Keyframe.ofFloat(0.3f,300f);
Keyframe middle2 = Keyframe.ofFloat(0.7f,600f);
Keyframe end = Keyframe.ofFloat(1f,900f);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX",
start,middle1,middle2,end);
ObjectAnimator.ofPropertyValuesHolder(sun,holder).setDuration(3000).start();
連結:各種動畫合集
連結:新小夢 https://juejin.cn/post/6846687601118691341