咱們都知道 Android 自帶了 Roate Scale Translate Alpha 多種框架動畫,咱們能夠經過她們實現豐富的動畫效果,可是這些寬家動畫卻有一個致命的弱點,它們只是改變了 View 顯示的大小,而沒有改變 View 的響應區域。這時以 ObjectAnimator、ValueAnimator 爲表明的屬性動畫也就應運而生了。java
屬性動畫字如其名,是經過改變 View 的屬性值來改變控件的形態,說白了就是經過反射技術來獲取控件的一些屬性如寬度、高度等的 get 和 set 方法,從而實現所謂的動畫效果。因此,這就須要咱們的 View (如自定義 View 中)具備 set 和 get 方法,若是沒有則會致使程序的 Clash 。
具體步驟android
由此也能夠看出:屬性動畫直接改變了控件的屬性,因此動畫結束後控件也就發生了永久性的變化。git
這裏我打算經過使用 ObjectAnimator 實現四大動畫框架:github
給你們講解下 ObjectAnimator 使用編程
private void iniAnimation(){ // 透明度動畫 ObjectAnimator.ofFloat(mAlphaImage, "alpha", 1, 0, 1) .setDuration(4000) .start(); // 縮放 final AnimatorSet animatorSet = new AnimatorSet(); mScaleImage.setPivotX(mScaleImage.getWidth()+250); mScaleImage.setPivotY(mScaleImage.getHeight()+250); animatorSet.playTogether( ObjectAnimator.ofFloat(mScaleImage, "scaleX", 1, 0) .setDuration(2000), ObjectAnimator.ofFloat(mScaleImage, "scaleY", 1, 0) .setDuration(2000) ); animatorSet.start(); // 平移 translation final AnimatorSet translationAnimatorSet = new AnimatorSet(); translationAnimatorSet.playTogether( ObjectAnimator.ofFloat(mTranslationImage, "translationX", 20, 100) .setDuration(2000), ObjectAnimator.ofFloat(mTranslationImage, "translationY", 20,100) .setDuration(2000) ); translationAnimatorSet.start(); // 利用 ObjectAnimator 實現旋轉動畫 final AnimatorSet rotateAnimationSet = new AnimatorSet(); rotateAnimationSet.playTogether( ObjectAnimator.ofFloat(mRotationImage, "rotation",0, 360) .setDuration(2000) ); rotateAnimationSet.start(); }
以上代碼就經過了 ObjectAnimator 實現了,四大效果,實現過程基本能夠概括爲app
最後的運行效果如開頭動畫所示
一樣的,咱們能夠在一個 playTogether 方法中添加多個動畫,這樣就能實現多動畫組合的效果。這裏就不在贅述了,你們能夠本身試試看(我 GIF 圖中,右下角的動畫,就是旋轉 + 透明度)框架
ValueAnimator 是 ObjectAnimator 的父類,他兩之間的區別是,ObjectAnimator 在ValueAnimator 的基礎上,經過反射技術實現了動畫功能,也就像我剛剛所舉的例子,子要給了 ObjectAnimator 兩個值(from,to),在肯定動畫類型(「scale,translate」),他就能自動生成動畫。
與之造成區別,雖然咱們一樣須要給 ValueAnimator 傳遞起始和最終兩個值,可是 ValueAnimator 並不會自動去執行什麼,而是會經過 addUpdateListener 的監聽方法,在時間插值器的做用下,有序的返回一連串數值,而後咱們就能夠經過這些數值,對控件進行設置。
ide
最近看各大廠商,彷佛都迷上了對 FloatingActionButton 進行操做,我就也來趁波熱點。
佈局
這個效果既能夠經過動畫框架實現,也可經過屬性動畫實現,這裏我給你們講下實現的方法。
首先是思路
因爲這裏咱們是採用 ValueAnimator 實現的,因此更具 ValueAnimator 的特性,在咱們對其設定完時間插值器以後,它會規律的返回一系列數。因此咱們只要更具這一系列數對控件的屬性進行設置便可。post
private FloatingActionButton fab; private ImageView imageView; private int buttonSize = 0, imageSize = 0; private float startY = 0; private float endY = 0; private ValueAnimator createValueAnimate(final View view, int start, int end){ ValueAnimator valueAnimator = ValueAnimator.ofInt(start, end); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { ViewGroup.LayoutParams params = view.getLayoutParams(); params.height = (int) animation.getAnimatedValue(); params.width = (int) animation.getAnimatedValue(); view.setLayoutParams(params); } }); return valueAnimator; }
能夠看到咱們傳入三個參數,這裏我作的是縮放動畫,因此給的分別是控件,控件當前大小和控件目標大小。而後根據監聽器返回的值進行設置便可。
調用方面
我這裏實現的是上拉隱藏和下拉顯示,因此咱們須要判斷下 Y軸 滑動方向:
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_UP: startY = event.getY(); if ((startY - endY) < 0){ // 縮小 animationDown(fab, buttonSize); animationDown(imageView, imageSize); }else if ((startY - endY) > 0){ // 放大 animationUp(fab, buttonSize); animationUp(imageView, imageSize); } break; case MotionEvent.ACTION_DOWN: endY = event.getY(); break; } return super.onTouchEvent(event); } private void animationDown(final View view, int originalSize){ ValueAnimator animator = createValueAnimate(view, originalSize, 0); animator.addListener(new AnimatorListenerAdapter(){ @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); view.setVisibility(View.GONE); } }); animator.setInterpolator(new BounceInterpolator()); animator.setDuration(500).start(); } private void animationUp(final View view, int originalSize){ view.setVisibility(View.VISIBLE); ValueAnimator animator = createValueAnimate(view, 0, originalSize); animator.setInterpolator(new BounceInterpolator()); animator.setDuration(500).start(); }
這裏咱們會發現,因爲是屬性動畫,因此改變的直接就是控件的大小,這就致使了一個問題,若是是實時的獲取控件大小。那麼咱們在執行完多小動畫,也就是 animationDown 後,就沒法在得到控件原始大小了。
因此這裏咱們在 onResume 方法中獲取控件大小:
@Override protected void onResume() { super.onResume(); fab.post(new Runnable() { @Override public void run() { buttonSize = fab.getHeight(); } }); imageView.post(new Runnable() { @Override public void run() { imageSize = imageView.getHeight(); } }); }
屬性動畫能夠做爲 ViewGroup 增長活減小控件是的動畫,是的界面的變換不是那麼的突兀,其實細心的同窗可能有發現,android 是自帶切換效果的,可是形式比較單一,因此這裏我經過自定義 ObjectAnimator 的方法。
實現過程其實很是簡單:
用一樣的方法設置 remove 動畫
LayoutTransition transition = new LayoutTransition(); ObjectAnimator appendAnimator = ObjectAnimator.ofPropertyValuesHolder( (ImageView) null, PropertyValuesHolder.ofFloat("scaleX", 0.0f, 1.0f), PropertyValuesHolder.ofFloat("scaleY", 0.0f, 1.0f), PropertyValuesHolder.ofFloat("alpha" , 0.0f, 1.0f) ); appendAnimator.setInterpolator(new BounceInterpolator()); transition.setAnimator(LayoutTransition.APPEARING, appendAnimator); transition.setDuration(LayoutTransition.APPEARING, transition.getDuration(LayoutTransition.APPEARING)); transition.setStartDelay(LayoutTransition.APPEARING, transition.getStartDelay(LayoutTransition.APPEARING)); ObjectAnimator removeAnimator = ObjectAnimator.ofPropertyValuesHolder( (ImageView) null, PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.0f), PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.0f), PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.0f) ); removeAnimator.setInterpolator(new BounceInterpolator()); transition.setAnimator(LayoutTransition.DISAPPEARING, removeAnimator); transition.setDuration(LayoutTransition.DISAPPEARING, transition.getDuration(LayoutTransition.DISAPPEARING)); transition.setStartDelay(LayoutTransition.DISAPPEARING, transition.getStartDelay(LayoutTransition.DISAPPEARING));
最後經過 setLayoutTransition 將這個 LayoutTransition 對象付給你的 ViewGroup 便可
layout = findViewById(R.id.layout); layout.setLayoutTransition(transition);
測試是分爲添加控件和移除控件,功能在活動中動態的執行:
添加方法:
移除方法
@Override public void onClick(View v) { switch (v.getId()){ case R.id.btn_add_image: ImageView imageView = new ImageView(ExtendActivity.this); imageView.setScaleType(ImageView.ScaleType.FIT_XY); imageView.setImageResource(R.drawable.heart); ViewGroup.LayoutParams params = new LinearLayout.LayoutParams(200, 200); imageView.setLayoutParams(params); layout.addView(imageView,0); break; case R.id.btn_remove_image: int count = layout.getChildCount(); if (count > 0){ layout.removeViewAt(0); } break; } }
項目 Demo 點擊前往https://github.com/FishInWater-1999/android_view_user_defined_first
到此爲止全部屬性動畫的使用基本介紹完畢
因爲是我的學習的總結,若是有問題或是我我的疏漏,但願你們在評論區給我留言 祝你們編程愉快,少碼 bug ,哈哈哈