數行代碼教你實現Snapchat的Navigation bar

前提

最近在做一個關于Camera的app我們的ux設計師根據Snapchat設計了我現在正在做的app,剛開始打開Snapchat這個app的時候看他這個動畫確實很炫酷,很多細節上面的動畫,打開app的時候是在ios上的 我就懷疑android 是不是能實現一樣的效果,于是仔細的觀察了這個主頁的布局方式和動畫的效果。其實很好實現。下面我們來一一分析到底如何做到這樣的動畫。

原理分析

  • 惡心的是,這個app需要翻墻你才能用,那我們仔細看一下他這個動畫的過程
  • 主頁act 肯定是一個viewpager,然后三個fragment (我認為是兩個fragment,第二個只是個透明的fragment,占個茅坑而已)
  • 然后大家仔細看看當我在左右滑動的過程中,底部的三個icon 左右移動 放大縮小,同時還有一個icon 當我們移動到中間的時候會發現從底部移動上來了
  • 同時backgroundcolor也跟著動態的變色。
  • toolbar也是跟著不同的icon hide show title的改變。
  • 然后就是中間拍照的時候 長安會出現 一行表情動態 改面部識別,點擊每個icon 會有個從左往右 或相反的方向移動然后縮放。(這個功能也好做,一會慢慢講解)
  • 還有就是狀態欄顏色的動態改變,過渡顏色

上圖

snapchat.gif

小伙子們感覺怎么樣啊 是不是就是實現了你們想要的功能。

布局實現

  1. 最外層布局是ConstraintLayout 這個google提供的一個非常niubility的一個強大的RelativeLayout,如果還有小伙伴沒有用過的話,強烈建議去mark一下,讓你的布局適配所有機器ConstraintLayout學習鏈接分分鐘學會
  2. 然后就是viewpager and 很多icon 相互協調做出來的。
  3. 主要有一個中間按個大icon 和下放的那個小icon 需要用一個相對布局包裹起來。
    直接上布局文件 方便小伙伴的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 幾個布局嵌套就完成了這個Snapchat的叼叼的動畫效果,我也很懵逼,分析一下確實這樣。看起來很牛啊,其實實現起來很簡單,有需求的小伙伴可以去試試。那么布局實現了 肯定最主要的當然是在代碼中了。不廢話,來讓我們codeing吧

代碼

可能我的代碼會比較亂,因為當初是想著寫個demo看看效果的,所以就demo級別的代碼。

  1. 那么我們來解決原理分析中的第一個問題 viewpager中的fragment和三個fragment吧,這沒有什么含金量。就是寫個list集合添加到viewpager得adapter里面,然后把第二個fragment設置為透明狀態。over
  2. 第二個問題是,左右滑動icon的移動變大縮放的過程。大家想一想我們正常的view 是不是可以設置padding。那么padding是干嘛的。內邊距。好的進入主題。你設置了一個icon的寬高固定后。然后在設置相應的padding是不是對于的是不是相應的寬高就就會被padding 占了,icon這不就邊小了嗎?設置左右padding 這不就位移了嗎?那么問題來了
  3. 怎么才能控制滑動過程中padding的動態改變呢,這個不廢話嗎,viewpager干嘛的 viewpager是不是有addOnPageChangeListener這個方法,這個回調中是不是??onPageScrolled(int position, float positionOffset, int positionOffsetPixels)這個方法,我們稍微滑動一下,這里面的值都是一致在改變的,這就是設置動態設置padding的原理 獲取當前滑動的距離,做一下參數的調整即可實現第二個問題要做的事
  4. 第三個問題backgroundcolor的顏色改變。和上面第二個問題一樣。設置初始值startcolor 和endColor 來根據滑動的距離來得到當前的顏色。不懂原理的可以看一下我的另一篇文章:彩虹進度條
  5. toolbar的顏色改變也是一樣,設置alpha的值0-1 來動態的改變
  6. 那么最后一個問題也是一樣通過這個三方工具可以簡單的實現這個功能,問題四已經拿到了color
  7. 問題解決思路是這樣下面我就直接把代碼邏輯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();
                // 當前Pager的滑動距離
                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) {

            }
        });

這個就是核心代碼。根據上面的講解然后在看這段代碼的話應該很快的了解到原理實現。

ending

好了,基本的邏輯和布局上面已經都考出來了,我就不上傳github了,小伙伴們copy 一下功能就能完成了。今天就到這里了。88

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容