1. 程式人生 > >android進階4step1:Android動畫處理與自定義View——轉場動畫

android進階4step1:Android動畫處理與自定義View——轉場動畫

以下都需要執行在5.0以上

一、揭露動畫效果

參考:使用Circular Reveal為你的應用新增揭露動畫效果

最主要的類Circular Reveal

官方將這一動畫稱為揭露效果,它在官網中的描述是這樣的:

當您顯示或隱藏一組 UI 元素時,揭露動畫可為使用者提供視覺連續性。[ViewAnimationUtils.createCircularReveal()](https://developer.android.com/reference/android/view/ViewAnimationUtils.html?hl=zh-cn#createCircularReveal(android.view.View

, int, int, float, float))
方法讓您能夠為裁剪區域新增動畫以揭露或隱藏檢視。

很明顯,我們使用ViewAnimationUtils.createCircularReveal()方法就能達到基本的揭露動畫效果了。那麼我們就直接開始看一下這個方法到底需要哪些引數吧

Animator createCircularReveal (View view,        // The View will be clipped to the animating circle.
            int centerX,                         // The x coordinate of the center of the animating circle, relative to view
            int centerY,                         // The y coordinate of the center of the animating circle, relative to view
            float startRadius,                   // The starting radius of the animating circle.
            float endRadius                      // The ending radius of the animating circle.
)

ViewAnimationUtils.createCircularReveal()方法所執行的效果,就是將一個View裁剪成圓,然後從圓心逐漸揭露展現檢視。

引數 引數說明
view 要執行動畫效果的View
centerX 圓心x座標
centerY 圓心y座標
startRadius 開始時的圓半徑
endRadius 結束時的圓半徑

其實引數都是比較容易理解的,主要是涉及到了動畫開始的x,y座標,以及圓形揭露的半徑變化startRadius->endRadius。
在此我就以最上面的那個效果圖為例,對createCircularReveal ()的使用進行一個簡單的引入吧。

簡單使用:

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewAnimationUtils;

public class MainActivity extends AppCompatActivity {

    private View mView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mView = findViewById(R.id.view);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_enter:
                revealEnter();
                break;
            case R.id.btn_exit:
                revealExit();
                break;
        }
    }


    /**
     * 進入動畫
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void revealEnter() {
        //獲取檢視的寬度
        int w = mView.getWidth();
        int h = mView.getHeight();
        //設定基準點(園的中心點)的位置 從左上角開始(0,0)
        //(w,h) 應該在檢視的右下角
        int cx = w;
        int cy = h;
        //Math.hypot() 函式返回它的所有引數的平方和的平方根,即:檢視的對角線
        //開始的圓的半徑
        int r = (int) Math.hypot(w, h);
        Animator animator = ViewAnimationUtils.createCircularReveal(mView, cx, cy, 0, r);
        //設定顯示動畫的時間間隔
        animator.setDuration(2000);
        mView.setVisibility(View.VISIBLE);
        animator.start();
    }

    /**
     * 離開動畫
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void revealExit() {
        //獲取檢視的寬度
        int w = mView.getWidth();
        int h = mView.getHeight();
        //設定基準點(園的中心點)的位置 從左上角開始(0,0)
        int cx = w;
        int cy = h;
        //Math.hypot() 函式返回它的所有引數的平方和的平方根,即:檢視的對角線
        //開始的圓的半徑
        int r = (int) Math.hypot(w, h);
        /**
         *
         */
        Animator animator = ViewAnimationUtils.createCircularReveal(mView, cx, cy, r, 0);
        //設定顯示動畫的時間間隔
        animator.setDuration(2000);
        animator.start();
        //當動畫結束後讓檢視不可見
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mView.setVisibility(View.INVISIBLE);
            }
        });
    }
}

二、轉場動畫(場景間 同一個Activity中)

Transition框架核心Scene、Transition和TransitionManager類

  • Scene:場景  (定義了介面當前的狀態資訊,儲存了佈局中所有View的屬性值)

其中Scene是一個容器,就是放置你定義的佈局,而真正去做場景之間切換這個動作是Transition框架中TransitionManager 呼叫其中go方法或者transitionTo方法完成場景之間切換,而真正建立具體動畫交由Transition子類來完成,開始動畫交給Transition來執行。
轉:Android場景動畫(Scene)

Scene.getSceneForLayout() 引數介紹如下:

  • sceneRoot 表示從什麼地方開始切換場景。
  • layoutId 切換到什麼場景的佈局檔案,比如上述例子中生成Scene2例項,layoutId 就是場景2中的佈局。
  • context 上下文
  • Transition:轉換

當一個場景改變的時候,transition主要負責:捕獲每個View在開始場景和結束場景時的狀態(各種屬性值);

根據兩個場景(開始和結束)之間的區別自動建立一個Animator。

監聽一個容器內部有控制元件的狀態發生改變後執行的動畫

一個有四種動畫效果:

  • Slide 劃入
  • Explode 爆炸
  • Fade 隱藏
  • changeBounds 位置與大小變化
  • TransitionManager:負責場景之間的跳轉和新增效果

  • 這個類將SenceTransition關聯了起來,大多數情況下的場景變化都會使用AutoTransition(預設動畫)。只有當應用程式需要不同的轉換行為時,才需要指定其他的Transition來滿足特定的場景需求。

以下轉載:Android Transition——基礎篇

  • setTransition(Scene scene, Transition transition) 

設定需要的場景與過渡動畫

  • setTransition(Scene fromScene, Scene toScene, Transition transition) 

設定起始場景和結束場景與過渡動畫

  • go(Scene scene) 

切換到指定的場景

  • go(Scene scene, Transition transition) 

切換到指定的場景以及所使用的過渡動畫,transition如果傳了null,那麼就沒有了過渡動畫。

  • beginDelayedTransition(ViewGroup sceneRoot, Transition transition) 

可以自定義場景過渡的方法,呼叫此方法時,TransitionManager會捕獲sceneRoot中View的屬性值,然後發出請求以在下一幀上進行轉換。那時候,sceneRoot中的新值將被捕獲,變化的過程將會以動畫的形式展現出來。我們沒有必要建立一個新的Scene,因為這個方法主要是用來展現當前場景到下一幀的過渡效果。

  • void endTransitions (ViewGroup sceneRoot) 

結束指定場景根目錄在準備/正在進行的轉換。

更詳細的解釋,請移步官方API。 

 示例程式碼:

效果:

自定義動畫效果:在res目錄中建立transition資料夾 建立transition.xml檔案

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
     <!--第一種動畫效果-->
    <changeImageTransform android:duration="1000">
        <!--指定圖片控制元件的id-->
        <targets android:targetId="@id/image" />
    </changeImageTransform>
    <!--第二種動畫效果 淡入淡出-->
    <fade android:duration="1000" android:startDelay="1000">
    </fade>
</transitionSet>

實現類 


​public class SceneActivity extends AppCompatActivity {

    private Scene mOverViewScene;
    private Scene mInfoScene;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scene);
        //根佈局
        ViewGroup sceneRoot = (ViewGroup) findViewById(R.id.scene_root);
        //搭建第一個場景
        mOverViewScene = Scene.getSceneForLayout(sceneRoot, R.layout.scene_overview, getBaseContext());
        //搭建第二個場景
        mInfoScene = Scene.getSceneForLayout(sceneRoot, R.layout.scene_info, getBaseContext());
        //首先跳轉到第一個場景
        TransitionManager.go(mOverViewScene);
    }

    //點選事件實現場景的跳轉邏輯
    public void onClick(View view) {
        switch (view.getId()) {
            //點選info圖示時
            case R.id.btnInfo:
                //載入自定義的跳轉動畫
                Transition transition = TransitionInflater.from(getBaseContext())
                        .inflateTransition(R.transition.transition);
                TransitionManager.go(mInfoScene, transition);
                 //預設是AutoTransition
                //TransitionManager.go(mInfoScene);
                break; 
            //點選close圖示時
            case R.id.btnClose:
                TransitionManager.go(mOverViewScene);
                break;
        }
    }

}

三、Activity間的轉場動畫

轉:Android開發之Activity轉場動畫

轉:android 學習使用Activity轉場動畫及shareElement

轉場動畫(Activity Transition)基本介紹

Android 5.0 提供了三種Transition型別

  • 進入:決定Activity中的所有的檢視怎麼進入螢幕。
  • 退出:決定一個Activity中的所有檢視怎麼退出螢幕。
  • 共享元素(shareElement:決定兩個activities之間的過渡,怎麼共享(它們)的檢視。

進入和退出包含如下動畫效果

  • explode(分解) – 從螢幕中間進或出
  • slide(滑動) - 從螢幕邊緣進或出地
  • fade(淡出) –通過改變螢幕上檢視的不透明度達到新增或者移除檢視的效果

共享元素包含如下動畫效果

  • changeBounds - 改變目標檢視的佈局邊界
  • changeClipBounds - 裁剪目標檢視邊界
  • changeTransform - 改變目標檢視的縮放比例和旋轉角度
  • changeImageTransform - 改變目標圖片的大小和縮放比例

Transition 與 Activity的跳轉動畫有以下幾個

  • setEnterTransition 進入的動畫
  • setExitTransition 退出的動畫
  • setReturnTransition 返回的動畫
  • setReenterTransition 重入的動畫

示例:

第一個Activity

public class FirstActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public void onClick(View view) {
        int resId = -1;
        switch (view.getId()) {
            case R.id.iv1:
                resId = R.drawable.pic1;
                break;
            case R.id.iv2:
                resId = R.drawable.pic2;
                break;
            case R.id.iv3:
                resId = R.drawable.pic3;
                break;
            case R.id.iv4:
                resId = R.drawable.pic4;
                break;
        }
        /**
         * 每點選一張圖片
         * 都會將這一張圖片的資源id傳出去
         */
        Intent intent = new Intent(this, SecondActivity.class);
        intent.putExtra("resId", resId);

        //建立transition
        Transition transition = new Explode();
        //指定狀態列不變(指定某一個控制元件不使用動畫)(排除某個元素不在轉場動畫中)
        transition.excludeTarget(android.R.id.statusBarBackground, true);

        //設定進場動畫
        getWindow().setEnterTransition(transition);
        //設定離場動畫
        getWindow().setExitTransition(transition);
        //重進動畫
        getWindow().setReenterTransition(transition);
        //設定共享元素進場動畫
        getWindow().setSharedElementEnterTransition(transition);
        //設定共享元素(當前view 和 共享元素id 根據這個id來匹配)
        Pair<View, String> shareElement = Pair.create(view, "img");

        
        //makeSceneTransitionAnimation 可以不設定或者設定多個共享元素
        ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, shareElement);
        //通過toBundle方法傳給startActivity 
        startActivity(intent, options.toBundle());
    }
}

第二個Activity

public class SecondActivity extends Activity {

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        //拿到傳來的圖片資源id
        int resId = getIntent().getExtras().getInt("resId");
        ImageView iv =  findViewById(R.id.iv);
        //共享元素的id
        iv.setTransitionName("img");
        //設定給當前佈局的ImageView
        iv.setImageResource(resId);

        Transition transition = new Explode();
        //指定狀態列不變(指定某一個控制元件不使用動畫)(排除它)
        transition.excludeTarget(android.R.id.statusBarBackground, true);
        //設定進場動畫
        getWindow().setEnterTransition(transition);
        //設定離場動畫
        getWindow().setExitTransition(transition);

    }

}

 除了可以在程式碼中開啟轉場還可以定義在Style中

啟動轉場

<style name="BaseAppTheme" parent="android:Theme.Material"> 

<!– 啟動視窗內容轉場 -->
<item name="android:windowContentTransitions">true</item>
<!– 視窗進入/離開時演示的動畫 -->
<item name="android:windowEnterTransition">@transition/explode</item> <item name="android:windowExitTransition">@transition/explode</item>
<!– 共享元素進入/離開時演示的動畫 -->
<item name="android:windowSharedElementEnterTransition">
@transition/change_image_transform</item>
<item name="android:windowSharedElementExitTransition">
@transition/change_image_transform</item> 

</style>

更多案例:https://github.com/Trisaa/MaterialTranstion

進階用法:https://github.com/andremion/Music-Player