仿知乎首頁學習 CoordinateLayout

前言

第一次接觸CoordinateLayout的時候深深的被其炫酷的特效所吸引;想着何時在實際項目中可使用一下,無奈實際項目因行業特色,並不須要使用到CoordinateLayout這麼高端的交互體驗;因此本着學習的態度,便用CoordinateLayout模仿了一下知乎首頁效果,這也是如今掘金APP首頁的效果;這種效果其實很友好,能讓用戶最大限度的使用到手機屏幕。javascript

好了,廢話很少說,先看看模仿效果。php

index

discovery

message

userCenter

這裏用到的icon 大部分來源於iconfontjava

使用模擬器截取gif貌似永遠都是這樣模糊不清,有興趣的同窗能夠點github查看源碼,實際運行在手機上效果會比這裏好一些。android

綜述

CoordinateLayout是Android Design Support Library提供的一種佈局方式。git

查看源碼咱們能夠看到 CoordinateLayout繼承自ViewGroup,是一個「超級強大」的FrameLayout,FrameLayout 相信你們都很熟悉,使用也很簡單,FrameLayout能夠說是讓Android佈局中有了「」的概念,那麼這個CoordinateLayout又有什麼神奇之處呢,下面咱們就學習一下。github

Coordinate 按照字面意思理解,就是協調。它能夠方便的實現佈局內view協調app

那麼到底是怎麼個調節法呢,咱們來看一下。ide

CoordinateLayout 使用

結合Snackbar

關於CoordinateLayout最經典的例子就是其結合Snackbar的使用了。函數

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent">

    <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|bottom" android:layout_margin="16dp" android:src="@drawable/ic_done" />

</android.support.design.widget.CoordinatorLayout>複製代碼
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Snackbar.make(view,"FAB",Snackbar.LENGTH_LONG)
                        .setAction("cancel", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {

                            }
                        })
                        .show();
            }
        });
    }複製代碼

上面這份代碼應該是不少人對CoordinateLayout的第一印象,這也是關於CoordinateLayout最直觀的解釋。佈局

這裏實現的效果就是如上面第三幅動圖message中那樣,底部彈出一個SnackBar,FloatingActionButton自動上移;這就是所謂的協調,協調FloatingActionButton上移,不被頂部彈出的SnackBar所遮擋。

這裏若是沒有使用CoordinateLayout做爲根佈局,而是使用LinearLayout或RelativeLayout等,若是FloatingActionButton距離底部太近,那麼它將會被底部彈出的Snackbar所遮擋。

結合AppBarLayout使用

說到CoordinateLayout就不得不提這個AppBarLayout,他們倆簡直就是天生一對,兩者結合使用,那畫面真是太美了,想一想都以爲刺激。

這裏看一下咱們模仿首頁頂部搜索欄的代碼:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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/coordinatorLayout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".fragments.IndexFragment">

    <android.support.design.widget.AppBarLayout android:id="@+id/index_app_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay">

        <RelativeLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimary" app:layout_scrollFlags="scroll|enterAlways">

            <ImageView android:id="@+id/live" android:layout_width="24dp" android:layout_height="24dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="5dp" android:src="@drawable/live_button" />

            <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="10dp" android:layout_toLeftOf="@id/live" android:background="@color/searchmenu">

                <ImageView android:id="@+id/search" android:layout_width="24dp" android:layout_height="24dp" android:layout_centerVertical="true" android:layout_marginLeft="10dp" android:src="@drawable/ic_search" />

                <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="10dp" android:layout_toRightOf="@id/search" android:text="搜索話題、問題或人" android:textSize="16sp" />

            </RelativeLayout>
        </RelativeLayout>
    </android.support.design.widget.AppBarLayout>

        .......

</android.support.design.widget.CoordinatorLayout>複製代碼

這裏咱們在AppBarLayout內部嵌套了一個RelativeLayout,在這個RelativeLayout中咱們模仿了頂部的搜索欄的佈局效果,這個很簡單。這裏最核心的東西就是

app:layout_scrollFlags="scroll|enterAlways"複製代碼

這行代碼。什麼意思呢?這個app:layout_scrollFlags有下面幾個值:

  • scroll: 全部想滾動出屏幕的view都須要設置這個flag, 沒有設置這個flag的view將被固定在屏幕頂部。

  • enterAlways: 設置這個flag時,向下的滾動都會致使該view變爲可見。

  • enterAlwaysCollapsed: 當你的視圖已經設置minHeight屬性又使用此標誌時,你的視圖只能已最小高度進入,只有當滾動視圖到達頂部時才擴大到完整高度。

  • exitUntilCollapsed: 滾動退出屏幕,最後摺疊在頂端。

  • snap: 視圖在滾動時會有一種「就近原則」,怎麼說呢,就是當視圖展開時,若是滑動中展 開的內容超過視圖的75%,那麼視圖依舊會保持展開;當視圖處於關閉時,若是滑動中展開的部分小於視圖的25%,那麼視圖會保持關閉。總的來講,就是會讓動畫有一種彈性的視覺效果。

這裏咱們使用了scroll 和 enterAlways ,就很容易的實現了向下滑動時頂部隱藏,向下滑動時頂部出現的效果。

結合TabLayout使用

注意,這裏所說的TabLayout是android.support.design.widget.TabLayout,不是好久之前的那個TabLayout。

使用這個TabLayout能夠產生一種滑動時tab 懸停的效果,這裏咱們模仿的時候,用於種種緣由沒能使用TabLayout的動態效果,只是簡單的結合ViewPager使用了一下,第二個頁面discovery就是使用TabLayout做爲頂部的Indicator使用;這個很簡單,就不展開說了;具體實現看查看源碼。

結合CollapsingToolbarLayout使用

我的感受,這是整個CoordinateLayout中最拉風的動畫特效,主要是實現一種「摺疊」的動畫效果。咱們在模仿我的中心的時候就是用到了這個功能:

看一下我的中心的佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="256dp" android:fitsSystemWindows="true" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:expandedTitleMarginEnd="64dp" app:expandedTitleMarginStart="48dp" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/user_bg" app:layout_collapseMode="parallax">

                <de.hdodenhof.circleimageview.CircleImageView android:layout_width="68dp" android:layout_height="68dp" android:layout_centerInParent="true" android:src="@drawable/profile" />

            </RelativeLayout>

            <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingTop="10dp">

            <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitStart" android:src="@drawable/fake" />

        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

    <android.support.design.widget.FloatingActionButton android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="16dp" android:clickable="true" android:src="@drawable/ic_edit" app:layout_anchor="@id/appbar" app:layout_anchorGravity="bottom|right|end" />

</android.support.design.widget.CoordinatorLayout>複製代碼

  • 首先,咱們在AppBarLayout中嵌套一個CollapsingToolbarLayout,並指定其
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"複製代碼

這個屬性前面介紹過了,這裏三種屬性結合就可實現滾動中「摺疊視差」的效果了。

  • 接下來,咱們又在CollapsingToolbarLayout放置了一個RelativeLayout。這個RelativeLayout有一個很重要的設置;
app:layout_collapseMode="parallax"複製代碼

這個layout_collapseMode就是用來設置整個RelativeLayout的摺疊效果的,有兩種取值,「pin」:固定模式,在摺疊的時候最後固定在頂端;「parallax」:視差模式,在摺疊的時候會有個視差摺疊的效果。

  • 最後是Toolbar,能夠看到Toolbar的collapseMode設置爲pin,這樣向上滑動時,當RelativeLayout的內容徹底摺疊後,Toolbar將顯示在頂部;而向下滑動時,Toolbar將消失,而RelativeLayout的內容會動態的摺疊展開,並且因爲設置了snap,會有一種輕微的彈性效果。

這裏須要注意,這個時候,咱們須要將AppBarLayout的高度設置爲固定值

CoordinatorLayout 還提供了一個 layout_anchor 的屬性,連同 layout_anchorGravity 一塊兒,能夠用來放置與其餘視圖關聯在一塊兒的懸浮視圖(如 FloatingActionButton)。

這裏若是咱們將floatingActionButton設置爲:

android:layout_gravity="bottom|right|end"複製代碼

FloatingActionButton將位於整個屏幕的右下角。

使用細節

這裏須要注意的是,使用AppBarLayout時,爲了實現其滾動時的效果,在其下面必須有一個可滾動的View,而且須要爲其設置app:layout_behavior屬性。

好比咱們在結合結合CollapsingToolbarLayout使用時,
在AppBarLayout的下面放置了一個NestedScrollView,並設置其app:layout_behavior="@string/appbar_scrolling_view_behavior"。

而在其餘頁面,咱們AppBarLayout的下面放置了ViewPager或者是FrameLayout都設置了相應的屬性;具體可參考源碼。

Behavior

上面咱們提到了layout_behavior,這是個什麼意思呢?

這裏就不得不說這個Behavior了,能夠說Behavior是整個CoordinateLayout最核心的東西。還記得咱們最開始的列子嗎?FloatingActionButton會隨着Snackbar的出現,自動的調節本身的位置,這是怎樣的實現的呢?

咱們經過追蹤查看 Snackbar 的 show() 這個方法,最終會在Snack的源碼中找到以下實現:

final void showView() {
        if (mView.getParent() == null) {
            final ViewGroup.LayoutParams lp = mView.getLayoutParams();

            if (lp instanceof CoordinatorLayout.LayoutParams) {
                // If our LayoutParams are from a CoordinatorLayout, we'll setup our Behavior
                final CoordinatorLayout.LayoutParams clp = (CoordinatorLayout.LayoutParams) lp;

                final Behavior behavior = new Behavior();
                behavior.setStartAlphaSwipeDistance(0.1f);
                behavior.setEndAlphaSwipeDistance(0.6f);
                behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_START_TO_END);
                behavior.setListener(new SwipeDismissBehavior.OnDismissListener() {
                    @Override
                    public void onDismiss(View view) {
                        view.setVisibility(View.GONE);
                        dispatchDismiss(Callback.DISMISS_EVENT_SWIPE);
                    }

                    @Override
                    public void onDragStateChanged(int state) {
                        switch (state) {
                            case SwipeDismissBehavior.STATE_DRAGGING:
                            case SwipeDismissBehavior.STATE_SETTLING:
                                // If the view is being dragged or settling, cancel the timeout
                                SnackbarManager.getInstance().cancelTimeout(mManagerCallback);
                                break;
                            case SwipeDismissBehavior.STATE_IDLE:
                                // If the view has been released and is idle, restore the timeout
                                SnackbarManager.getInstance().restoreTimeout(mManagerCallback);
                                break;
                        }
                    }
                });
                clp.setBehavior(behavior);
                // Also set the inset edge so that views can dodge the snackbar correctly
                clp.insetEdge = Gravity.BOTTOM;
            }

            mTargetParent.addView(mView);
        }


    ......

    }複製代碼

咱們能夠看到,當Snack執行show方法的時候,會生成一個Behavior對象,而後將這個對象set給CoordinateLayout,而CoordinateLayout會根據這個Behavior執行動做。這個方法下面省略的代碼大致上就是一個Translation屬性動畫的實現,這裏就不展開來講了。

回到咱們以前所說,咱們須要爲帶有滾動屬性的view設置layout_behavior這個屬性,咱們爲其設置的值

app:layout_behavior="@string/appbar_scrolling_view_behavior"複製代碼
<string name="appbar_scrolling_view_behavior" translatable="false">android.support.design.widget.AppBarLayout$ScrollingViewBehavior</string>複製代碼

咱們能夠在AppBarLayout的源碼中找到這個ScrollingViewBehavior,其最終也是繼承自Behavior實現了特定的效果。

如今或許你有疑問,這個神祕的Behavior究竟是個什麼鬼?

Behavior 核心概念

Behavior 就是行爲,他定義了View的行爲。

CoordinatorLayout的工做原理是搜索定義了CoordinatorLayout Behavior的子view,不論是經過在xml中使用app:layout_behavior標籤仍是經過在代碼中對view類使用@DefaultBehavior修飾符來添加註解。當滾動發生的時候,CoordinatorLayout會嘗試觸發那些聲明瞭依賴的子view。

Behavior最基礎的兩個方法是:layoutDependsOn() 和onDependentViewChanged();這兩個方法的說明以下:

public boolean layoutDependsOn(CoordinatorLayout parent, T child, View dependency) {
    boolean result;
    //返回false表示child不依賴dependency,ture表示依賴
    return result;    
}複製代碼
/** * 當dependency發生改變時(位置、寬高等),執行這個函數 * 返回true表示child的位置或者是寬高要發生改變,不然就返回false */
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, T child, View dependency) {
     //child要執行的具體動做
        return true;
}複製代碼

FloatingActionButton 的Behavior

咱們用Android Studio查看FloatingActionButton的源碼,會發現他包含了一個Behavior的註解:

@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)
public class FloatingActionButton extends VisibilityAwareImageButton {
.....
}複製代碼

這裏咱們看一下FloatingActionButton的註解參數FloatingActionButton.Behavior.class 是怎樣實現的。經過源碼咱們發現這個FloatingActionButton的Behavior繼承自CoordinateLayout的Behavior,並且只實現了onDependentViewChanged方法,咱們看一下:

public static class Behavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
        private static final boolean AUTO_HIDE_DEFAULT = true;

        private Rect mTmpRect;
        private OnVisibilityChangedListener mInternalAutoHideListener;
        private boolean mAutoHideEnabled;

        public Behavior() {
            super();
            mAutoHideEnabled = AUTO_HIDE_DEFAULT;
        }

        public Behavior(Context context, AttributeSet attrs) {
            super(context, attrs);
            TypedArray a = context.obtainStyledAttributes(attrs,
                    R.styleable.FloatingActionButton_Behavior_Layout);
            mAutoHideEnabled = a.getBoolean(
                    R.styleable.FloatingActionButton_Behavior_Layout_behavior_autoHide,
                    AUTO_HIDE_DEFAULT);
            a.recycle();
        }

        @Override
        public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
            if (dependency instanceof AppBarLayout) {
                // If we're depending on an AppBarLayout we will show/hide it automatically
                // if the FAB is anchored to the AppBarLayout
                updateFabVisibilityForAppBarLayout(parent, (AppBarLayout) dependency, child);
            } else if (isBottomSheet(dependency)) {
                updateFabVisibilityForBottomSheet(dependency, child);
            }
            return false;
        }


    }複製代碼

能夠看到他在onDependentViewChanged中直接判斷了當前依賴的view。咱們在模仿我的中心時,設置的FloatingActionButton的dependency就是AppBarLayout。而在這個方法中,他就會根據此執行特定的操做,也就是updateFabVisibilityForAppBarLayout 這個方法中的內容。

自定義Behavior

好了,說了這麼多,下面咱們說一下自定義Behavior。咱們在模仿知乎底部用於切換Fragment的Tab時,便使用了一個自定義的Behavior。

BottomViewBehavior
public class BottomViewBehavior extends CoordinatorLayout.Behavior<View> {
    public BottomViewBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return dependency instanceof AppBarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        float translationY = Math.abs(dependency.getTop());
        child.setTranslationY(translationY);
        return true;
    }

}複製代碼

這裏咱們的思路很簡單,就是咱們的View 要依賴於頂部的AppBarLayout,而用其距離屏幕的距離,做爲底部(tab)相對於屏幕的距離,這樣當頂部的AppBarLayout 滑動出屏幕時,底部也將作相應的位移,固然這裏底部tab 的高度是須要作限制的,不能大於頂部AppBarLayout的高度。

<LinearLayout android:id="@+id/bottom" android:layout_width="match_parent" android:layout_height="48dp" android:layout_gravity="bottom" android:background="@color/white" android:orientation="horizontal" app:layout_behavior="home.smart.fly.zhihuindex.behavior.BottomViewBehavior">

        <RadioGroup android:id="@+id/tabs_rg" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:paddingLeft="5dp" android:paddingRight="5dp">

            <RadioButton android:id="@+id/home_tab" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#00000000" android:button="@null" android:checked="true" android:drawableTop="@drawable/home_sel" android:gravity="center|bottom" android:paddingTop="5dp" />

            <RadioButton android:id="@+id/explore_tab" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#00000000" android:button="@null" android:drawableTop="@drawable/explore_sel" android:gravity="center|bottom" android:paddingTop="5dp" />

            <RadioButton android:id="@+id/notify_tab" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#00000000" android:button="@null" android:drawableTop="@drawable/notify_sel" android:gravity="center|bottom" android:paddingTop="5dp" />

            <RadioButton android:id="@+id/user_tab" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#00000000" android:button="@null" android:drawableTop="@drawable/user_sel" android:gravity="center|bottom" android:paddingTop="5dp" />
        </RadioGroup>

    </LinearLayout>複製代碼

咱們將自定義的Behavior設置爲這個bottom的app:layout_behavior就能夠實現相似於知乎首頁的那種效果了。

FabBehavior

這裏咱們用到的FloatingActionButton也能夠自定義Behavior。

public class FabBehavior extends CoordinatorLayout.Behavior<View> {
    private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();
    /** * 控件距離coordinatorLayout底部距離 */
    private float viewDistance;
    private boolean aninmating;

    public FabBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {

        if(child.getVisibility() == View.VISIBLE&& viewDistance ==0){
            //獲取控件距離父佈局(coordinatorLayout)底部距離
            viewDistance =coordinatorLayout.getHeight()-child.getY();
        }

        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;//判斷是否豎直滾動
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
        //dy大於0是向上滾動 小於0是向下滾動

        if (dy >=0&&!aninmating &&child.getVisibility()==View.VISIBLE) {
            hide(child);
        } else if (dy <0&&!aninmating &&child.getVisibility()==View.GONE) {
            show(child);
        }
    }

    private void hide(final View view) {
        ViewPropertyAnimator animator = view.animate().translationY(viewDistance).setInterpolator(INTERPOLATOR).setDuration(200);

        animator.setListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                aninmating =true;
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                view.setVisibility(View.GONE);
                aninmating =false;
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                show(view);
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });
        animator.start();
    }

    private void show(final View view) {
        ViewPropertyAnimator animator = view.animate().translationY(0).setInterpolator(INTERPOLATOR).setDuration(200);
        animator.setListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                view.setVisibility(View.VISIBLE);
                aninmating =true;
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                aninmating =false;
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                hide(view);
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });
        animator.start();
    }
}複製代碼

這裏咱們並無去實現layoutDependsOn() 和onDependentViewChanged()這兩個方法,前面咱們看FloatingActionButton源碼的時候知道他已經實現了onDependentViewChanged,咱們這裏咱們從自身需求出發,就其滑動時的特性,作了一個滑動屏幕時FloatingActionButton快速從底部彈出或隱藏的Behavior。結合註釋,代碼很容易理解。

好了,這就是全部關於CoordinateLayout的東西了,能夠看到Behavior是這個控件的核心,也是最難理解的東西。自定義Behavior可讓咱們的滑動動畫有無限的可能。

總結

關於這個模仿知乎首頁的實現,最初真的只是想研究一下「首頁」是怎麼實現的。結果隨着Demo的展開,加上輕微強迫症的做祟,便成了如今這個樣子。

到這裏,不得不說一下,我的感受,真正的知乎首頁應該是沒有使用CoordinateLayout;由於按如今這種Activity+n*Fragment 的套路,使用CoordinateLayout徹底是給本身添亂,由於CoordinateLayout是滑動特性是沒法嵌套使用的(或者說很複雜,我沒發現),當我在最外層的Activity中使用了CoordinateLayout後,內部的Fragment中再次使用CoordinateLayout時,就會發生意想不到的各類bug,因此你會發現咱們模擬的我的中心是有問題的,這裏就是嵌套CoordinateLayout後外部的CoordinateLayout失效了,致使底部的Behavior也失效。

不過在整個模仿的過程,也算是對CoordinateLayout的一次深刻了解吧,順便也對SwipeRefreshLayout的內容和Tween Animation的使用作了一次鞏固。首頁RecycleView item中仿照Toolbar的彈出菜單,真的是耗費了很多時間。

源碼地址

好了,按照慣例再次給出github地址,歡迎star&fork。


後話

以前學習CoordinateLayout模仿知乎首頁的效果,斷斷續續的大概用了一週時間;如今回過頭來再看,其實關於CoordinateLayout的使用很簡單,甚至有些無聊;由於app:layout_scrollFlags和 app:layout_collapseMode 這兩個屬性的可選值都也就那麼幾個;這實際上是一種侷限性,你們在應用中使用這個東西,產生的滑動視差效果幾乎就是類似的,惟一就是顏色及主題風格的差別;這很容易讓用戶產生審美疲勞;惟一變化的就是Behavior,這是咱們能夠自定義的東西,所以這也是最難掌握的東西。知乎首頁以及掘金首頁的效果比我在這裏實現的要更加柔和舒服,至於其是否使用了CoordinateLayout就不得而知了。

相關文章
相關標籤/搜索