Android進(jìn)階設(shè)計(jì) | 使用揭露動(dòng)畫(Reveal Effect)做一個(gè)絲滑的Activity轉(zhuǎn)場(chǎng)動(dòng)畫

提筆之際(附總體思路)


最近跟幾個(gè)小伙伴在實(shí)踐一個(gè)項(xiàng)目,考慮到界面效果,我們決定使用揭露動(dòng)畫作為Activity的轉(zhuǎn)場(chǎng)動(dòng)畫。


這里主要是我負(fù)責(zé)這部分的實(shí)現(xiàn)。
話說之前是沒接觸過的,關(guān)于具體的實(shí)現(xiàn)跟大體的思路都不太清楚。于是最先啃官方API,有點(diǎn)難看懂,然后下載了官方的demo,直接看代碼,還是有問題,畢竟它規(guī)模略大,集成了好多動(dòng)畫效果;
接著就找了很多博文,發(fā)現(xiàn)網(wǎng)上真的水文忒多了哎。。

最后找到了這三篇,算是解答了我的疑問:

  1. http://www.itdecent.cn/p/b75548e488df
    這篇思路很好,寫得也很走心,啟發(fā)了我設(shè)計(jì)的思路跟注意到的一些問題,像揭露動(dòng)畫的邏輯放在哪里之類的;正當(dāng)我要下載demo的時(shí)候發(fā)現(xiàn)他代碼是kotlin來的,好吧,再繼續(xù)找博文;

  2. https://blog.csdn.net/shedoor/article/details/81251849#5
    這篇就講得更加詳盡,這還看不懂那就有點(diǎn)說不過去了。一開始覺得揭露動(dòng)畫還是挺高大上的樣子,結(jié)果此博文文首便說很簡(jiǎn)單,那就很簡(jiǎn)單吧,后來理解透了之后發(fā)覺確實(shí)也不難,畢竟只有一個(gè)靜態(tài)方法而已;
    https://github.com/OCNYang/Android-Animation-Set/tree/master/reveal-animation
    這個(gè)點(diǎn)進(jìn)去是他的GitHub,demo下下來,代碼看一下,自己寫個(gè)小demo(我是先在一個(gè)activity里面跑通揭露動(dòng)畫,再進(jìn)一步將揭露動(dòng)畫實(shí)現(xiàn)成跳轉(zhuǎn)動(dòng)畫),再加入自己的邏輯,一步一步來算是沒有問題了。
    到這里就跑通了一個(gè)活動(dòng)中的Activity了;

  1. https://github.com/whyalwaysmea/AndroidDemos
    接下來就進(jìn)入本文主題了,使用揭露動(dòng)畫作為Activity的轉(zhuǎn)場(chǎng)動(dòng)畫;
    這篇文檔跟代碼算是幫上大忙了,有較大的參考價(jià)值;
    不同的是作者的思路是在跳轉(zhuǎn)的目標(biāo)活動(dòng)中,啟動(dòng)做揭露動(dòng)畫的收挽,收挽結(jié)束后再finish();
    我這里根據(jù)情況修改為跳轉(zhuǎn)的目標(biāo)活動(dòng)中按下返回鍵即finish(),完了之后原始活動(dòng)中的onReStart()中做揭露動(dòng)畫的收挽;另外我在在跳轉(zhuǎn)的目標(biāo)活動(dòng)中完成揭露動(dòng)畫展開的時(shí)候,添加了一個(gè)AlphaAnimation;
    這邊的起始活動(dòng)用的是button的onClick觸發(fā)的方式,以及這里對(duì)兩個(gè)活動(dòng)各自的控件的visible做了細(xì)節(jié)的把控;

最終效果圖
GitHub中附方法詳解圖




引子


使用揭露動(dòng)畫做一個(gè)絲滑的Activity轉(zhuǎn)場(chǎng)動(dòng)畫,
關(guān)于這個(gè)需求,可能不同的同學(xué),會(huì)有不同的問題,
我這里把可能遇到的問題跟我在完成這個(gè)demo的過程中遇到的問題做一個(gè)總結(jié),
然后附上總體的思路,大家可以交流一下~

  1. 什么是揭露動(dòng)畫?
    Material-Animations; 官網(wǎng)有詳細(xì)的介紹,
    揭露動(dòng)畫具有相當(dāng)絲滑的效果,
    常常可以用與基于一個(gè)Activity的碎片切換或者View、控件的切換覆蓋鋪張,如本文第一個(gè)demo;
    或者直接作為兩個(gè)Activity之間的轉(zhuǎn)場(chǎng)動(dòng)畫,如本文第二個(gè)demo;

  2. 揭露動(dòng)畫怎么用?
    官方API封裝好了,
    一個(gè)類一個(gè)靜態(tài)方法——ViewAnimationUtils.createCircularReveal(),
    傳進(jìn)五個(gè)參數(shù),返回一個(gè)Animator對(duì)象。根據(jù)具體情況調(diào)用即可。

    詳細(xì)可見參考文檔;

  3. “絲滑”之解
    這個(gè)轉(zhuǎn)場(chǎng)動(dòng)畫要實(shí)現(xiàn)得絲滑,需要注意幾個(gè)細(xì)節(jié):
    活動(dòng)A跳轉(zhuǎn)到活動(dòng)B的情況下,
    a.在A點(diǎn)擊觸發(fā)跳轉(zhuǎn)時(shí)刻,揭露動(dòng)畫要放在哪個(gè)活動(dòng)展開;
    b.在B按下返回鍵之后,揭露動(dòng)畫又要放在哪個(gè)活動(dòng)收挽;
    c.揭露動(dòng)畫的展開和收挽,createCircularReveal()分別以誰為操作對(duì)象;
    d.這里A通過FloatingActionButton出發(fā),那揭露層View跟FloatingActionButton的visible跟invisible設(shè)置的順序;
    e.關(guān)閉android默認(rèn)的activity轉(zhuǎn)場(chǎng)動(dòng)畫(不然就相當(dāng)不絲滑了hhh);

相關(guān)解答詳解下方第二個(gè)demo的思路總結(jié),請(qǐng)移步到正文中的第二個(gè)demo;

了解本文的兩個(gè)demo之后,我相信以這個(gè)兩個(gè)demo為模板,結(jié)合筆者之前關(guān)于Material Design做的諸多筆記,應(yīng)該是可以做出不少很有趣的東西來的~

再附上在做本demo的過程中一些debugExperience:




正文


1.先在一個(gè)activity里面跑通揭露動(dòng)畫

首先新建一個(gè)空項(xiàng)目,接著走三步即可:

1)更改styles.xml,改成NoActionBar,去掉標(biāo)題欄,待會(huì)兒調(diào)試可以觀察:

2)書寫activity_main.xml:

  • 這里對(duì)子空間的布局范圍要求并不多,直接簡(jiǎn)單用FrameLayout即可;
  • 然后是Textview放在最前面,最先渲染,以為至底層;
  • 接著我們這里使用一個(gè)View原生控件來作為揭露動(dòng)畫的操作對(duì)象,即通過對(duì)View控件的顯示和隱藏以及動(dòng)畫操作來具體實(shí)現(xiàn)揭露動(dòng)畫;
  • 最后放置一個(gè)懸浮按鈕,用于啟動(dòng)點(diǎn)擊事件,這里響應(yīng)的事件是啟動(dòng)揭露動(dòng)畫:

另外說一下,關(guān)于FloatingActionButton,
android:backgroundTint可以設(shè)置其背景色,
android:src則給按鈕設(shè)置圖標(biāo),
這里用的圖標(biāo)資源來自于阿里的矢量圖標(biāo)庫。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lwp.justtest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:layout_gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:id="@+id/view_puppet"
        android:background="@color/colorPrimaryDark"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"/>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="16dp"
        android:backgroundTint="@color/colorPrimary"
        android:src="@drawable/map"
        app:pressedTranslationZ="10dp" />

</FrameLayout>

3)書寫MainActivity.java:

  • 實(shí)例化各個(gè)組件之后,實(shí)現(xiàn)FloatingActionButton的onClick(),
  • onClick()中我們調(diào)用一個(gè)自定義方法,在里面啟動(dòng)揭露動(dòng)畫;
  • 這里通過變量flag實(shí)現(xiàn)點(diǎn)擊按鈕時(shí)揭露動(dòng)畫的交替開啟顯示以及關(guān)閉隱藏,效果圖在下方代碼之后;
  • 關(guān)于揭露動(dòng)畫的邏輯以及具體實(shí)現(xiàn)的語法,
    其實(shí)核心就是ViewAnimationUtils.createCircularReveal()這個(gè)方法以及其五個(gè)參數(shù)的意義,
    詳細(xì)地可以參考前面提到的參考文章鏈接:
package com.lwp.justtest;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    boolean flag = false;
    FloatingActionButton fab;
    private View mPuppet;

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

        mPuppet = findViewById(R.id.view_puppet);
        fab = (FloatingActionButton)findViewById(R.id.fab);
        fab.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        doRevealAnimation();
    }

    private void doRevealAnimation() {
        int[] vLocation = new int[2];
        fab.getLocationInWindow(vLocation);
        int centerX = vLocation[0] + fab.getMeasuredWidth() / 2;
        int centerY = vLocation[1] + fab.getMeasuredHeight() / 2;

        int height = mPuppet.getHeight();
        int width = mPuppet.getWidth();
        int maxRradius = (int) Math.hypot(height, width);
        Log.e("hei", maxRradius + "");

        if (flag) {
            Animator animator = ViewAnimationUtils.createCircularReveal(mPuppet, centerX, centerY, maxRradius, 0);
            animator.setDuration(1000);
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    mPuppet.setVisibility(View.GONE);
                }
            });
            animator.start();
            flag = false;
        } else {
            Animator animator = ViewAnimationUtils.createCircularReveal(mPuppet, centerX, centerY, 0, maxRradius);
            animator.setDuration(1000);
            animator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {
                    mPuppet.setVisibility(View.VISIBLE);
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });
            animator.start();
            flag = true;
        }
    }

}

上面三步走完,即可運(yùn)行程序,揭露動(dòng)畫隨即實(shí)現(xiàn),效果如下:


接著后面就進(jìn)入本文主題了;



2.使用揭露動(dòng)畫作為Activity的轉(zhuǎn)場(chǎng)動(dòng)畫

思路總結(jié):

1. MainActivity.java:
    1.1.   實(shí)例化、聲明各種對(duì)象,注意:
            根布局對(duì)象(用來控制整個(gè)布局),
            揭露層對(duì)象指的是用于作揭露操作的純色的match_parent的View控件;

    1.2.  onCreate():完成findViewById()以及intent的構(gòu)建,F(xiàn)loatingActionButton的setOnClickListener;

    1.3.  onClick():計(jì)算fab的中心坐標(biāo),用于作為揭露動(dòng)畫的圓心;同時(shí)把這對(duì)坐標(biāo)put進(jìn)intent中,然后startActivity(intent);跳轉(zhuǎn)到下一個(gè)活動(dòng),同時(shí)把坐標(biāo)對(duì)傳過去;

    1.4. createRevealAnimator():計(jì)算startRadius、endRadius,調(diào)用核心方法createCircularReveal()構(gòu)建出animator并做相關(guān)配置后return之;
          注意:
            這里的createCircularReveal()操作對(duì)象用的是揭露層純色View對(duì)象mPuppet0;
            以及配置中用了animator.addListener(animatorListener0);添加一個(gè)動(dòng)畫監(jiān)聽器;--->> 1.5.

    1.5.  Animator.AnimatorListener animatorListener0 

 注意這里的思路:
          ?。。?          onAnimationStart():收挽揭露動(dòng)畫開啟時(shí),揭露層setVisibility(View.VISIBLE);fab.setVisibility(View.INVISIBLE);
          onAnimationEnd():收挽版揭露動(dòng)畫結(jié)束時(shí),mPuppet0.setVisibility(View.INVISIBLE);fab.setVisibility(View.VISIBLE);
          !?。?    
    1.6. onRestart():回調(diào)方法,計(jì)算fab的中心坐標(biāo),用于作為揭露動(dòng)畫的圓心;
         調(diào)用createRevealAnimator()創(chuàng)建并配置一個(gè)animator(--->> 1.4.),
         然后開啟收挽版揭露動(dòng)畫,即animator.start();

2. next.java:
    2.1.   實(shí)例化、聲明各種對(duì)象,注意:
            根布局對(duì)象(用來控制整個(gè)布局),
            揭露層對(duì)象指的是用于作揭露操作的純色的match_parent的View控件;

    2.2.  onCreate():完成findViewById(),
        這里注意:
            動(dòng)畫需要依賴于某個(gè)視圖才可啟動(dòng),這里依賴于根布局對(duì)象并且開辟一個(gè)子線程,
            在子線程中g(shù)et坐標(biāo)對(duì),調(diào)用createRevealAnimator()創(chuàng)建并配置一個(gè)animator;--->> 2.3.
            然后開啟展開版揭露動(dòng)畫,即animator.start();
    2.3. createRevealAnimator():計(jì)算startRadius、endRadius,調(diào)用核心方法createCircularReveal()構(gòu)建出animator并做相關(guān)配置后return之;

          注意這里的思路:

            ?。?!這里的createCircularReveal()操作對(duì)象用的是根布局對(duì)象content;

            ?。。。?!
            (即先加載好整個(gè)布局,再把整個(gè)布局作為揭露對(duì)象從0徑到屏幕對(duì)角線徑揭露展開,
              展開過程中揭露層純色view在最頂層,所以感覺是View在做展開而已,
              而實(shí)際上并不是;展開完畢后,再把view層去掉,去掉之后下層的活動(dòng)內(nèi)容自然就顯示出來了。)
            ?。。。?!

            以及配置中用了animator.addListener(animatorListener0);添加一個(gè)動(dòng)畫監(jiān)聽器;--->> 2.4.
    2.4. Animator.AnimatorListener animatorListener1 

          注意這里的思路:
          ?。?!
          onAnimationEnd():展開版揭露動(dòng)畫結(jié)束時(shí),            
            mPuppet.startAnimation(createAlphaAnimation());//調(diào)用透明度動(dòng)畫,絲滑效果-->>2.5.
            mPuppet.setVisibility(View.INVISIBLE);//動(dòng)畫結(jié)束時(shí),揭露動(dòng)畫設(shè)置為不可見
          ?。?!

    2.5. createAlphaAnimation():定義透明度動(dòng)畫,返回一個(gè)AlphaAnimation對(duì)象;

    3. 兩個(gè)布局xml沒什么特別需要說的地方,
        注意第一個(gè)xml的view要android:visibility="gone",以及按照渲染先后層次關(guān)系按序書寫控件即是;

    4. styles.xml:android:windowAnimationStyle屬性置為null,取消掉Android默認(rèn)的轉(zhuǎn)場(chǎng)動(dòng)畫
    <style name="noAnimTheme" parent="AppTheme">
        <item name="android:windowAnimationStyle">@null</item>
    </style>
    
    5. AndroidManifest.xml:為參與的活動(dòng)添加剛剛設(shè)置好的主題;
      <activity
            android:name=".MainActivity"
            android:theme="@style/noAnimTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".next"
            android:theme="@style/noAnimTheme">
        </activity>

最后上代碼了,不同的功能基本上都放在了不同的方法內(nèi)實(shí)現(xiàn),結(jié)合注釋應(yīng)該不難理解了~

MainActivity.java:

package com.lwp.justtest;

import ...

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    FloatingActionButton fab;
    Intent intent;
    private View content;//根布局對(duì)象(用來控制整個(gè)布局)
    private View mPuppet0;//揭露層對(duì)象
    private int centerX;
    private int centerY;

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

        content = findViewById(R.id.reveal_content0);
        mPuppet0 = findViewById(R.id.view_puppet);
        intent = new Intent(MainActivity.this, next.class);
        fab = (FloatingActionButton)findViewById(R.id.fab);
        fab.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        int[] vLocation = new int[2];
        fab.getLocationInWindow(vLocation);
        centerX = vLocation[0] + fab.getMeasuredWidth() / 2;
        centerY = vLocation[1] + fab.getMeasuredHeight() / 2;
        intent.putExtra("cx",centerX);
        intent.putExtra("cy",centerY);
        startActivity(intent);
    }

    private Animator createRevealAnimator(int x, int y) {
        float startRadius = (float) Math.hypot(content.getHeight(), content.getWidth());
        float endRadius = fab.getMeasuredWidth() / 2 ;

        //注意揭露動(dòng)畫開啟時(shí)是用根布局作為操作對(duì)象,關(guān)閉時(shí)用揭露層作為操作對(duì)象
        Animator animator = ViewAnimationUtils.createCircularReveal(
                mPuppet0, x, y,
                startRadius,
                endRadius);
        animator.setDuration(500);
        animator.setInterpolator(new AccelerateDecelerateInterpolator());//設(shè)置插值器
        animator.addListener(animatorListener0);
        return animator;
    }

    //定義動(dòng)畫狀態(tài)監(jiān)聽器_按下返回鍵版
    private Animator.AnimatorListener animatorListener0 = new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
            mPuppet0.setVisibility(View.VISIBLE);//按下返回鍵時(shí),動(dòng)畫開啟,揭露層設(shè)置為可見
            fab.setVisibility(View.INVISIBLE);
        }
        @Override
        public void onAnimationEnd(Animator animation) {
            mPuppet0.setVisibility(View.INVISIBLE);
            fab.setVisibility(View.VISIBLE);
        }
        @Override
        public void onAnimationCancel(Animator animation) {
        }
        @Override
        public void onAnimationRepeat(Animator animation) {
        }
    };

    //第二個(gè)活動(dòng)退回來時(shí),回調(diào)本方法
    @Override
    protected void onRestart() {
        super.onRestart();

        //動(dòng)畫需要依賴于某個(gè)視圖才可啟動(dòng),
        // 這里依賴于根布局對(duì)象,并且開辟一個(gè)子線程,充分利用資源
        content.post(new Runnable() {
            @Override
            public void run() {
                int[] vLocation = new int[2];
                fab.getLocationInWindow(vLocation);
                centerX = vLocation[0] + fab.getMeasuredWidth() / 2;
                centerY = vLocation[1] + fab.getMeasuredHeight() / 2;
                Animator animator = createRevealAnimator(centerX, centerY);
                animator.start();
            }
        });
    }
}

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/reveal_content0"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lwp.justtest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Here is First Activity!"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="30sp"
        android:layout_gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:id="@+id/view_puppet"
        android:background="@color/colorPrimaryDark"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"/>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="16dp"
        android:backgroundTint="@color/colorPrimary"
        android:src="@drawable/map"
        app:pressedTranslationZ="10dp" />

</FrameLayout>

next.java:

package com.lwp.justtest;

import ...

public class next extends AppCompatActivity {

    private View content;//根布局對(duì)象(用來控制整個(gè)布局)
    private View mPuppet;//揭露層對(duì)象
    private int mX ;
    private int mY ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_next);//先加載好整個(gè)布局,后面再用整個(gè)布局作為揭露動(dòng)畫的操作對(duì)象,揭露完畢后再去掉揭露層
        content = findViewById(R.id.reveal_content);
        mPuppet = findViewById(R.id.view_puppet);

        //動(dòng)畫需要依賴于某個(gè)視圖才可啟動(dòng),
        // 這里依賴于根布局對(duì)象,并且開辟一個(gè)子線程,充分利用資源
        content.post(new Runnable() {
            @Override
            public void run() {
                mX = getIntent().getIntExtra("cx", 0);
                mY = getIntent().getIntExtra("cy", 0);
                Animator animator = createRevealAnimator(mX, mY);
                animator.start();
            }
        });
    }

    private Animator createRevealAnimator(int x, int y) {
        float startRadius = 0;
        float endRadius = (float) Math.hypot(content.getHeight(), content.getWidth());

        Animator animator = ViewAnimationUtils.createCircularReveal(
                content, x, y,
                startRadius,
                endRadius);
        animator.setDuration(660);
        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        //判斷標(biāo)志位reversed,true則為添加返回鍵版動(dòng)畫監(jiān)聽器,false則為跳轉(zhuǎn)動(dòng)畫開啟版
        // if (!reversed)
           animator.addListener(animatorListener1);
        return animator;
    }

    //定義動(dòng)畫狀態(tài)監(jiān)聽器_跳轉(zhuǎn)動(dòng)畫開啟版
    private Animator.AnimatorListener animatorListener1 = new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
//            content.setVisibility(View.VISIBLE);//跳轉(zhuǎn)進(jìn)來時(shí),(因?yàn)閒inish之前會(huì)將之設(shè)置為不可見,)
                                                 // 根布局要設(shè)置為可見,與finish部分的不可見相對(duì)應(yīng)
//            mPuppet.setAlpha(1);
        }
        @Override
        public void onAnimationEnd(Animator animation) {
            mPuppet.startAnimation(createAlphaAnimation());
            mPuppet.setVisibility(View.INVISIBLE);//動(dòng)畫結(jié)束時(shí),揭露動(dòng)畫設(shè)置為不可見
        }
        @Override
        public void onAnimationCancel(Animator animation) {
        }
        @Override
        public void onAnimationRepeat(Animator animation) {
        }
    };

    private AlphaAnimation createAlphaAnimation() {
        AlphaAnimation aa = new AlphaAnimation(1,0);
        aa.setDuration(400);
        aa.setInterpolator(new AccelerateDecelerateInterpolator());//設(shè)置插值器
        return aa;
    }
}

next.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/reveal_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lwp.justtest.next">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Here is Second Activity!"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="30sp"
        android:layout_gravity="center"/>

    <View
        android:id="@+id/view_puppet"
        android:background="@color/colorPrimaryDark"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>


</FrameLayout>

res/values/styles.xml:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="noAnimTheme" parent="AppTheme">
        <item name="android:windowAnimationStyle">@null</item>
    </style>

</resources>

AndroidManifest.xml:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:theme="@style/noAnimTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".next"
            android:theme="@style/noAnimTheme">
        </activity>
    </application>

最終效果圖:

本文的兩個(gè)demo就到此為止了,我相信以這個(gè)兩個(gè)demo為模板,結(jié)合筆者之前關(guān)于Material Design做的諸多筆記,應(yīng)該是可以做出不少很有趣的東西來的~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 14,007評(píng)論 2 59
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,062評(píng)論 25 709
  • 1、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,205評(píng)論 3 119
  • 昨夜狂風(fēng)攜雨的,很晚才入睡。 今早五點(diǎn)就自然醒了,如果在黃羊河的家里,這個(gè)點(diǎn)我是絕對(duì)醒不來的??磥?..
    有書薰衣草閱讀 653評(píng)論 2 34
  • 1 每天回來android 一集; 2. GUI Servlet Jsp JDBC SSH 以后要讓所有學(xué)生...
    雷一凡閱讀 324評(píng)論 0 0

友情鏈接更多精彩內(nèi)容