側(cè)滑菜單+圓形揭示動(dòng)畫

前言

由于工作需要客叉,小編對(duì)最近十分炫酷的android動(dòng)畫效果進(jìn)行了一波瘋狂搜集缎除。經(jīng)過一下午的努力,小編終于成功的將大部分好看的動(dòng)畫瀏覽了一遍冲九,差點(diǎn)閃瞎我的24k鈦合金狗眼。所以跟束,小編本著渴望裝逼的心情娘侍,將好的動(dòng)畫的實(shí)現(xiàn)原理,所使用的框架一個(gè)一個(gè)的整理出來泳炉。逼王之路憾筏,指日可待!;ǘ臁氧腰!

正文

今天小編帶給各位大佬的是側(cè)滑菜單+圓形揭示動(dòng)畫的實(shí)現(xiàn)。廢話少說刨肃,看效果先古拴。


side-menu.jpg

怎么樣?是不是很炫酷真友?下面我們就一起來看看這個(gè)效果是如何實(shí)現(xiàn)的黄痪?

動(dòng)畫實(shí)現(xiàn)方式

點(diǎn)擊demo地址獲得實(shí)現(xiàn)代碼。
關(guān)于動(dòng)畫實(shí)現(xiàn)其實(shí)十分簡(jiǎn)單盔然。

  • 導(dǎo)入庫:
    在文件的build.gradle文件中添加以下內(nèi)容:
repositories {
    maven {
        url "https://jitpack.io"
    }
}

dependencies {
    compile 'com.github.ozodrukh:CircularReveal:1.0.4'
    compile 'com.github.yalantis:Side-Menu.Android:1.0.1'
}
  • 主布局文件
    我們需要在主布局文件中進(jìn)行以下內(nèi)容添加:
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <io.codetail.widget.RevealFrameLayout
        android:id="@+id/container_frame"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:id="@+id/content_overlay"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"/>

        <LinearLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"/>

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:minHeight="?attr/actionBarSize"
            android:background="?attr/colorPrimary"/>

    </io.codetail.widget.RevealFrameLayout>

    <ScrollView
        android:id="@+id/scrollView"
        android:scrollbarThumbVertical="@android:color/transparent"
        android:layout_width="@dimen/sliding_menu_width"
        android:layout_height="match_parent"
        android:layout_gravity="start|bottom">

        <LinearLayout
            android:id="@+id/left_drawer"
            android:orientation="vertical"
            android:layout_width="@dimen/sliding_menu_width"
            android:layout_height="wrap_content"
            android:divider="@android:color/transparent"
            android:background="@android:color/transparent">
        </LinearLayout>
    </ScrollView>
</android.support.v4.widget.DrawerLayout>

我們也看到了桅打,主布局文件相當(dāng)簡(jiǎn)單。其中content_overlay層蓋在content_frame之上愈案,顯示圓形揭露效果挺尾。left_drawer盛放多個(gè)菜單項(xiàng)。

  • 新建fragment
    此處我們需要新建一個(gè)fragment來盛放需要展示的內(nèi)容站绪,也就是可以使用圓形揭露方式進(jìn)行內(nèi)容刷新遭铺,切換的區(qū)域。需要注意的是恢准,此fragment必須實(shí)現(xiàn)ScreenShotable接口魂挂。而ScreenShotable內(nèi)部只包含兩個(gè)抽象方法如下:
 //此方法將此時(shí)fragment區(qū)域的View做了一個(gè)截圖并保存到ContentFragment.this.bitmap
 @Override
    public void takeScreenShot() {
        Thread thread = new Thread() {
            @Override
            public void run() {
                Bitmap bitmap = Bitmap.createBitmap(containerView.getWidth(),
                        containerView.getHeight(), Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(bitmap);
                containerView.draw(canvas);
                ContentFragment.this.bitmap = bitmap;
            }
        };

        thread.start();

    }

    //這里提供了可以從外界獲取ContentFragment.this.bitmap的方法。
    @Override
    public Bitmap getBitmap() {
        return bitmap;
    }
  • 圓形揭示動(dòng)畫
    上述動(dòng)圖所展示圓形揭示效果就由下面代碼完成馁筐。
     //此處進(jìn)行fragment的圖片的替換
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private ScreenShotable replaceFragment(ScreenShotable screenShotable, int topPosition) {
        this.res = this.res == R.drawable.content_music ? R.drawable.content_films : R.drawable.content_music;
        View view = findViewById(R.id.content_frame);
        int finalRadius = Math.max(view.getWidth(), view.getHeight());
        //這里定義圓形揭露動(dòng)畫涂召。
        Animator animator = ViewAnimationUtils.createCircularReveal(view, 0, topPosition, 0, finalRadius);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.setDuration(ViewAnimator.CIRCULAR_REVEAL_ANIMATION_DURATION);
        //在動(dòng)畫執(zhí)行前將之前獲得的fragment區(qū)域的截圖覆蓋到真正的fragment之上。
        findViewById(R.id.content_overlay).setBackgroundDrawable(new BitmapDrawable(getResources(), screenShotable.getBitmap()));
        animator.start();
        //在動(dòng)畫執(zhí)行中更換真正的新的fragment眯漩。
        ContentFragment contentFragment = ContentFragment.newInstance(this.res);
        getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, contentFragment).commit();
        return contentFragment;
    }
  • 側(cè)滑菜單實(shí)現(xiàn)
    看完了上述代碼芹扭,我們圓形揭示的動(dòng)畫效果的核心部分已經(jīng)結(jié)束麻顶,接下來我們看一下側(cè)滑菜單以及它是如何與圓形揭露動(dòng)畫交互的。需要實(shí)現(xiàn)側(cè)滑菜單舱卡,首先需要在Activity實(shí)現(xiàn)接口ViewAnimator.ViewAnimatorListener辅肾,ViewAnimator類就是我們上面通過compile 'com.github.yalantis:Side-Menu.Android:1.0.1'導(dǎo)入的類。在使用時(shí)轮锥,我們需要實(shí)例化一個(gè)ViewAnimator 類的實(shí)例矫钓,并且在側(cè)滑菜單開始滑動(dòng)時(shí),調(diào)用showMenuContent方法舍杜。那么如何啟動(dòng)側(cè)滑菜單并且監(jiān)聽呢新娜?答案就是ActionBarDrawerToggle,具體代碼如下:
    private void setActionBar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        //定義左上角圖標(biāo)是否可以點(diǎn)擊
        getSupportActionBar().setHomeButtonEnabled(true);
        //在左邊添加向左箭頭返回鍵
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        //注冊(cè)側(cè)滑菜單監(jiān)聽器
        drawerToggle = new ActionBarDrawerToggle(
                this,/* host Activity */
                drawerLayout,/* DrawerLayout object */
                toolbar,  /* nav drawer icon to replace 'Up' caret */
                R.string.drawer_open,  /* "open drawer" description */
                R.string.drawer_close  /* "close drawer" description */
        ) {

            //當(dāng)側(cè)滑菜單關(guān)閉時(shí)
            @Override
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                linearLayout.removeAllViews();
                linearLayout.invalidate();
            }

            //當(dāng)側(cè)滑菜單滑動(dòng)時(shí)
            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                super.onDrawerSlide(drawerView, slideOffset);
                if (slideOffset > 0.6 && linearLayout.getChildCount() == 0)
                    viewAnimator.showMenuContent();
            }

            //當(dāng)側(cè)滑菜單打開時(shí)
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
            }
        };
        drawerLayout.setDrawerListener(drawerToggle);
    }

值得注意的是ActionBarDrawerToggle只能在onPostCreateonConfigurationChanged之間使用既绩。

 //當(dāng)onCreate徹底執(zhí)行完畢
    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        //ActionBarDrawerToggle的syncState()方法會(huì)和Toolbar關(guān)聯(lián)概龄,將圖標(biāo)放入到Toolbar上。
        drawerToggle.syncState();
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        //當(dāng)狀態(tài)改變時(shí)圖標(biāo)也改變
        drawerToggle.onConfigurationChanged(newConfig);
    }

經(jīng)過上述代碼我們可以知道該動(dòng)畫通過activity中對(duì)側(cè)滑菜單狀態(tài)進(jìn)行監(jiān)聽饲握,實(shí)現(xiàn)關(guān)于側(cè)滑菜單的動(dòng)效私杜。而實(shí)現(xiàn)部分全部放在ViewAnimator之中,那么我們來看看ViewAnimator內(nèi)部都做了什么?從調(diào)用方式就可以知道救欧,其中只有一個(gè)外部方法那就是showMenuContent衰粹。

 public void showMenuContent() {
        setViewsClickable(false);
        viewList.clear();
        double size = list.size();
        for (int i = 0; i < size; i++) {
            View viewMenu = appCompatActivity.getLayoutInflater().inflate(R.layout.menu_list_item, null);
            final int finalI = i;
            //為viewMenu添加事件監(jiān)聽
            viewMenu.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int[] location = {0, 0};
                    v.getLocationOnScreen(location);
                    switchItem(list.get(finalI), location[1] + v.getHeight() / 2);
                }
            });
            ((ImageView) viewMenu.findViewById(R.id.menu_item_image)).setImageResource(list.get(i).getImageRes());
            viewMenu.setVisibility(View.GONE);
            viewMenu.setEnabled(false);
            viewList.add(viewMenu);
            animatorListener.addViewToContainer(viewMenu);
            final double position = i;
            final double delay = 3 * ANIMATION_DURATION * (position / size);
            //執(zhí)行逐個(gè)滑出動(dòng)畫并保存每個(gè)fragment當(dāng)前顯示的截圖。
            new Handler().postDelayed(new Runnable() {
                public void run() {
                    if (position < viewList.size()) {
                        animateView((int) position);
                    }
                    if (position == viewList.size() - 1) {
                        screenShotable.takeScreenShot();
                        setViewsClickable(true);
                    }
                }
            }, (long) delay);
        }
    }

上述代碼一共做了兩件事笆怠,第一件:為viewMenu添加事件監(jiān)聽铝耻,第二件,執(zhí)行逐個(gè)滑出動(dòng)畫并保存每個(gè)fragment當(dāng)前顯示的截圖蹬刷。其中進(jìn)行圓形揭示的方法為

private void switchItem(Resourceble slideMenuItem, int topPosition) {
        this.screenShotable = animatorListener.onSwitch(slideMenuItem, screenShotable, topPosition);
        hideMenuContent();
    }

我們可以看到瓢捉,它就是調(diào)用了我們?cè)贏ctivity中實(shí)現(xiàn)的接口方法onSwitch執(zhí)行揭露動(dòng)畫,之后執(zhí)行側(cè)滑菜單退回的動(dòng)畫箍铭。
最后我們來看看其余三個(gè)接口方法是干嘛的:

 @Override
    public void disableHomeButton() {
        //定義左上角圖標(biāo)是否可以點(diǎn)擊
        getSupportActionBar().setHomeButtonEnabled(false);

    }

    @Override
    public void enableHomeButton() {
        getSupportActionBar().setHomeButtonEnabled(true);
        drawerLayout.closeDrawers();

    }

    @Override
    public void addViewToContainer(View view) {
        linearLayout.addView(view);
    }

剩余的三個(gè)接口方法其實(shí)就是對(duì)toolbar按鈕的一些控制泊柬,還有對(duì)側(cè)滑菜單區(qū)域view的管理椎镣。內(nèi)容很簡(jiǎn)單诈火,就不細(xì)說了。

總述

終于搞完了状答,可能是第一次總結(jié)這種類型的東西冷守,總感覺有點(diǎn)繁雜,還是希望幫到大家惊科。


文章參考
http://www.reibang.com/p/d2b1689a23bf
https://github.com/Yalantis/Side-Menu.Android

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拍摇,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子馆截,更是在濱河造成了極大的恐慌充活,老刑警劉巖蜂莉,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異混卵,居然都是意外死亡映穗,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門幕随,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蚁滋,“玉大人,你說我怎么就攤上這事赘淮≡迹” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵梢卸,是天一觀的道長(zhǎng)走诞。 經(jīng)常有香客問我,道長(zhǎng)蛤高,這世上最難降的妖魔是什么速梗? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮襟齿,結(jié)果婚禮上姻锁,老公的妹妹穿的比我還像新娘。我一直安慰自己猜欺,他們只是感情好位隶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著开皿,像睡著了一般涧黄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赋荆,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天笋妥,我揣著相機(jī)與錄音,去河邊找鬼窄潭。 笑死春宣,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嫉你。 我是一名探鬼主播月帝,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼幽污!你這毒婦竟也來了嚷辅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤距误,失蹤者是張志新(化名)和其女友劉穎簸搞,沒想到半個(gè)月后扁位,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡趁俊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年贤牛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片则酝。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡殉簸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沽讹,到底是詐尸還是另有隱情般卑,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布爽雄,位于F島的核電站蝠检,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏挚瘟。R本人自食惡果不足惜叹谁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乘盖。 院中可真熱鬧焰檩,春花似錦、人聲如沸订框。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽穿扳。三九已至衩侥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間矛物,已是汗流浹背茫死。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留履羞,地道東北人峦萎。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像吧雹,于是被迫代替她去往敵國(guó)和親骨杂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1雄卷、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,982評(píng)論 3 119
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,187評(píng)論 25 707
  • 四周終于安靜下來,可以沏一杯茶了蛤售。丁鹉。妒潭。 呼吸吐納,再吸氣呼氣十次揣钦,心好像還無法徹底靜下來雳灾!腦子里始終無法停在當(dāng)下!...
    嫣然579閱讀 659評(píng)論 1 3
  • 一:概念現(xiàn)金流量表是公司資金一張進(jìn)進(jìn)出出的表冯凹。正值代表流入公司谎亩,負(fù)值代表流出公司。主要包括三項(xiàng);營(yíng)業(yè)活動(dòng)現(xiàn)金流量宇姚,...
    郵吻閱讀 285評(píng)論 0 0
  • 《莊子》解匈庭,每章一讀。 文: 莊子將死浑劳,弟子欲厚葬之阱持。莊子曰:“吾以天地為棺槨,以日月為連璧魔熏,星辰為珠璣衷咽,萬物為赍...
    千里飄蓬閱讀 1,353評(píng)論 0 0