數(shù)行代碼教你實(shí)現(xiàn)Snapchat的Navigation bar

前提

最近在做一個(gè)關(guān)于Camera的app我們的ux設(shè)計(jì)師根據(jù)Snapchat設(shè)計(jì)了我現(xiàn)在正在做的app腾么,剛開(kāi)始打開(kāi)Snapchat這個(gè)app的時(shí)候看他這個(gè)動(dòng)畫(huà)確實(shí)很炫酷,很多細(xì)節(jié)上面的動(dòng)畫(huà)飘蚯,打開(kāi)app的時(shí)候是在ios上的 我就懷疑android 是不是能實(shí)現(xiàn)一樣的效果析命,于是仔細(xì)的觀察了這個(gè)主頁(yè)的布局方式和動(dòng)畫(huà)的效果兴泥。其實(shí)很好實(shí)現(xiàn)工育。下面我們來(lái)一一分析到底如何做到這樣的動(dòng)畫(huà)。

原理分析

  • 惡心的是搓彻,這個(gè)app需要翻墻你才能用如绸,那我們仔細(xì)看一下他這個(gè)動(dòng)畫(huà)的過(guò)程
  • 主頁(yè)act 肯定是一個(gè)viewpager,然后三個(gè)fragment (我認(rèn)為是兩個(gè)fragment旭贬,第二個(gè)只是個(gè)透明的fragment怔接,占個(gè)茅坑而已)
  • 然后大家仔細(xì)看看當(dāng)我在左右滑動(dòng)的過(guò)程中,底部的三個(gè)icon 左右移動(dòng) 放大縮小稀轨,同時(shí)還有一個(gè)icon 當(dāng)我們移動(dòng)到中間的時(shí)候會(huì)發(fā)現(xiàn)從底部移動(dòng)上來(lái)了
  • 同時(shí)backgroundcolor也跟著動(dòng)態(tài)的變色扼脐。
  • toolbar也是跟著不同的icon hide show title的改變。
  • 然后就是中間拍照的時(shí)候 長(zhǎng)安會(huì)出現(xiàn) 一行表情動(dòng)態(tài) 改面部識(shí)別奋刽,點(diǎn)擊每個(gè)icon 會(huì)有個(gè)從左往右 或相反的方向移動(dòng)然后縮放瓦侮。(這個(gè)功能也好做,一會(huì)慢慢講解)
  • 還有就是狀態(tài)欄顏色的動(dòng)態(tài)改變佣谐,過(guò)渡顏色

上圖

snapchat.gif

小伙子們感覺(jué)怎么樣啊 是不是就是實(shí)現(xiàn)了你們想要的功能肚吏。

布局實(shí)現(xiàn)

  1. 最外層布局是ConstraintLayout 這個(gè)google提供的一個(gè)非常niubility的一個(gè)強(qiáng)大的RelativeLayout,如果還有小伙伴沒(méi)有用過(guò)的話,強(qiáng)烈建議去mark一下狭魂,讓你的布局適配所有機(jī)器ConstraintLayout學(xué)習(xí)鏈接分分鐘學(xué)會(huì)
  2. 然后就是viewpager and 很多icon 相互協(xié)調(diào)做出來(lái)的罚攀。
  3. 主要有一個(gè)中間按個(gè)大icon 和下放的那個(gè)小icon 需要用一個(gè)相對(duì)布局包裹起來(lái)党觅。
    直接上布局文件 方便小伙伴的copy
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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/home_background"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="70dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="1.0" />

    
    <ImageView
        android:id="@+id/recommended"
        android:layout_width="100dp"
        android:layout_height="30dp"
        android:layout_margin="10dp"
        android:src="@drawable/choiceness_icon"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent" />


    <android.support.constraint.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent=".8" />


    <ImageView
        android:id="@+id/model_panorama"
        android:layout_width="70dp"
        android:layout_height="70dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/guideline"
        app:srcCompat="@mipmap/panorama_model" />

    <ImageView
        android:id="@+id/model_capture"
        android:layout_width="70dp"
        android:layout_height="50dp"
        android:layout_marginTop="15dp"
        app:layout_constraintRight_toLeftOf="@id/model_panorama"
        app:layout_constraintTop_toBottomOf="@id/guideline"
        app:srcCompat="@mipmap/capture_model" />


    <ImageView
        android:id="@+id/model_record"
        android:layout_width="70dp"
        android:layout_height="50dp"
        android:layout_marginTop="15dp"
        app:layout_constraintLeft_toRightOf="@+id/model_panorama"
        app:layout_constraintTop_toBottomOf="@id/guideline"
        app:srcCompat="@mipmap/record_model" />


    <ImageView
        android:id="@+id/gallery"
        android:layout_width="100dp"
        android:layout_height="30dp"
        android:layout_margin="10dp"
        android:src="@drawable/gallery_icon"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent" />


    <RelativeLayout
        android:id="@+id/container"
        android:layout_width="wrap_content"
        android:layout_height="150dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/guideline">

        <ImageView
            android:id="@+id/camera"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:src="@drawable/circle_sp" />

        <ImageView
            android:layout_marginTop="10dp"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@drawable/circle_sp"
            android:layout_below="@+id/camera"
            android:layout_centerHorizontal="true" />

    </RelativeLayout>


</android.support.constraint.ConstraintLayout>

看到了吧,ImageView viewpager RelativeLayout 幾個(gè)布局嵌套就完成了這個(gè)Snapchat的叼叼的動(dòng)畫(huà)效果斋泄,我也很懵逼杯瞻,分析一下確實(shí)這樣§牌看起來(lái)很牛啊又兵,其實(shí)實(shí)現(xiàn)起來(lái)很簡(jiǎn)單,有需求的小伙伴可以去試試卒废。那么布局實(shí)現(xiàn)了 肯定最主要的當(dāng)然是在代碼中了沛厨。不廢話,來(lái)讓我們codeing吧

代碼

可能我的代碼會(huì)比較亂摔认,因?yàn)楫?dāng)初是想著寫(xiě)個(gè)demo看看效果的逆皮,所以就demo級(jí)別的代碼。

  1. 那么我們來(lái)解決原理分析中的第一個(gè)問(wèn)題 viewpager中的fragment和三個(gè)fragment吧参袱,這沒(méi)有什么含金量电谣。就是寫(xiě)個(gè)list集合添加到viewpager得adapter里面,然后把第二個(gè)fragment設(shè)置為透明狀態(tài)抹蚀。over
  2. 第二個(gè)問(wèn)題是剿牺,左右滑動(dòng)icon的移動(dòng)變大縮放的過(guò)程。大家想一想我們正常的view 是不是可以設(shè)置padding环壤。那么padding是干嘛的晒来。內(nèi)邊距。好的進(jìn)入主題郑现。你設(shè)置了一個(gè)icon的寬高固定后湃崩。然后在設(shè)置相應(yīng)的padding是不是對(duì)于的是不是相應(yīng)的寬高就就會(huì)被padding 占了,icon這不就邊小了嗎接箫?設(shè)置左右padding 這不就位移了嗎攒读?那么問(wèn)題來(lái)了
  3. 怎么才能控制滑動(dòng)過(guò)程中padding的動(dòng)態(tài)改變呢,這個(gè)不廢話嗎辛友,viewpager干嘛的 viewpager是不是有addOnPageChangeListener這個(gè)方法薄扁,這個(gè)回調(diào)中是不是??onPageScrolled(int position, float positionOffset, int positionOffsetPixels)這個(gè)方法,我們稍微滑動(dòng)一下废累,這里面的值都是一致在改變的邓梅,這就是設(shè)置動(dòng)態(tài)設(shè)置padding的原理 獲取當(dāng)前滑動(dòng)的距離,做一下參數(shù)的調(diào)整即可實(shí)現(xiàn)第二個(gè)問(wèn)題要做的事
  4. 第三個(gè)問(wèn)題backgroundcolor的顏色改變九默。和上面第二個(gè)問(wèn)題一樣震放。設(shè)置初始值startcolor 和endColor 來(lái)根據(jù)滑動(dòng)的距離來(lái)得到當(dāng)前的顏色。不懂原理的可以看一下我的另一篇文章:彩虹進(jìn)度條
  5. toolbar的顏色改變也是一樣驼修,設(shè)置alpha的值0-1 來(lái)動(dòng)態(tài)的改變
  6. 那么最后一個(gè)問(wèn)題也是一樣通過(guò)這個(gè)三方工具可以簡(jiǎn)單的實(shí)現(xiàn)這個(gè)功能殿遂,問(wèn)題四已經(jīng)拿到了color
  7. 問(wèn)題解決思路是這樣下面我就直接把代碼邏輯copy上了有不懂得可以留言

代碼

  viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {


            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                float widthOfPagers = viewPager.getWidth() * (adapter.getCount() - 1);
                float top = 160.0f;
                float LeftRight = 20.0f;
                float alpha = 1.0f;

                float ratioTop = top / viewPager.getWidth();
                float ratioLeftRight = LeftRight / viewPager.getWidth();
                float ratioAlpha = alpha/viewPager.getWidth();
                // 當(dāng)前Pager的滑動(dòng)距離
                float currentPosOfPager = position * viewPager.getWidth() + positionOffsetPixels;

                if (position >= 1) {
                    startColor = Color.parseColor("#9D52CB");
                    endColor = Color.parseColor("#ffffff");
                    currentPosOfPager = widthOfPagers - currentPosOfPager;

                } else {
                    startColor = Color.parseColor("#08A9F3");
                    endColor = Color.parseColor("#ffffff");
                }


                float sizeTop = (currentPosOfPager * ratioTop);
                float sizeLeftRight = (currentPosOfPager * ratioLeftRight);
                float sizeAlpha = currentPosOfPager * ratioAlpha;

                container.setPadding(0, ((int) (top - sizeTop)), 0, 0);
                camera.setPadding(((int) (LeftRight - sizeLeftRight)), ((int) (LeftRight - sizeLeftRight)), ((int) (LeftRight - sizeLeftRight)), ((int) (LeftRight - sizeLeftRight)));

                recommended.setPadding(((int) (top - sizeTop)), 0, 0, 0);
                gallery.setPadding(0, 0, ((int) (top - sizeTop)), 0);

                float progress = (currentPosOfPager / ((float) viewPager.getWidth())) * 100.0f;
                LogUtil.e(progress);
                int currentColor = getCurrentColor((int) progress);
                homeBackground.setBackgroundColor(currentColor);
                StatusBarUtil.setColor(mContext, currentColor, 0);

                modelCapture.setAlpha(sizeAlpha);
                modelPanorama.setAlpha(sizeAlpha);
                modelRecord.setAlpha(sizeAlpha);
                LogUtil.e("    "+currentColor);

            }

            @Override
            public void onPageSelected(int position) {
                if (position == 1){
                    modelCapture.setVisibility(View.VISIBLE);
                    modelRecord.setVisibility(View.VISIBLE);
                    modelPanorama.setVisibility(View.VISIBLE);
                }else{
                    modelCapture.setVisibility(View.GONE);
                    modelRecord.setVisibility(View.GONE);
                    modelPanorama.setVisibility(View.GONE);
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

這個(gè)就是核心代碼诈铛。根據(jù)上面的講解然后在看這段代碼的話應(yīng)該很快的了解到原理實(shí)現(xiàn)。

ending

好了墨礁,基本的邏輯和布局上面已經(jīng)都考出來(lái)了幢竹,我就不上傳github了,小伙伴們copy 一下功能就能完成了恩静。今天就到這里了焕毫。88

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市驶乾,隨后出現(xiàn)的幾起案子邑飒,更是在濱河造成了極大的恐慌,老刑警劉巖级乐,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疙咸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡风科,警方通過(guò)查閱死者的電腦和手機(jī)撒轮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)贼穆,“玉大人题山,你說(shuō)我怎么就攤上這事」嗜” “怎么了顶瞳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)崖蜜。 經(jīng)常有香客問(wèn)我浊仆,道長(zhǎng),這世上最難降的妖魔是什么豫领? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮舔琅,結(jié)果婚禮上等恐,老公的妹妹穿的比我還像新娘。我一直安慰自己备蚓,他們只是感情好课蔬,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著郊尝,像睡著了一般二跋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上流昏,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天扎即,我揣著相機(jī)與錄音吞获,去河邊找鬼。 笑死谚鄙,一個(gè)胖子當(dāng)著我的面吹牛各拷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闷营,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼烤黍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了傻盟?” 一聲冷哼從身側(cè)響起速蕊,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎娘赴,沒(méi)想到半個(gè)月后互例,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡筝闹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年媳叨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片关顷。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡糊秆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出议双,到底是詐尸還是另有隱情痘番,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布平痰,位于F島的核電站汞舱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宗雇。R本人自食惡果不足惜昂芜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赔蒲。 院中可真熱鬧泌神,春花似錦、人聲如沸舞虱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)矾兜。三九已至损趋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間椅寺,已是汗流浹背浑槽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工蒋失, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人括荡。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓高镐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親畸冲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嫉髓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,519評(píng)論 25 707
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,712評(píng)論 22 664
  • classViewController:UIViewController,UITableViewDataSourc...
    笨的很想飛閱讀 279評(píng)論 0 1
  • 印象筆記:輸入文字和存儲(chǔ)所有類型筆記的工具 Notability:主要用于手寫(xiě) 主要功能:1.可輸入文字、手寫(xiě)邑闲,邊...
    CJJShare閱讀 1,109評(píng)論 0 1
  • 我在公路上飛馳 眼角瞥見(jiàn)一只黃色的蝴蝶 她在花草中閃爍 如同燈光在夜空中眨眼 只有一只蝴蝶的公路上 還有一個(gè)吃風(fēng)的...
    生命溫度加1閱讀 180評(píng)論 1 1