【Android】這效果,我沒法描述

前言

最近接到一個(gè)需求,這需求讓我表示很尷尬。(下面是一些廢話)
要求的效果是這樣的,頂部有部分懸浮,接著是一些布局,在下面是幾個(gè)可切換的Tab頁(yè)面,然后滾動(dòng)的時(shí)候~~吧啦吧啦吧啦吧啦~~ 還是直接看圖吧

效果

主要就是頂部和Tab的懸浮,還有就是被頂?shù)舻哪莻€(gè)效果。

聽到要實(shí)現(xiàn)這樣的效果,我抽屜那把砍產(chǎn)品專用菜刀已經(jīng)蠢蠢欲動(dòng)了。

思路

先說(shuō)說(shuō)實(shí)現(xiàn)的思路吧,上面的效果大致可以分成兩個(gè)部分:

  • 1、Tab向上滾動(dòng)到頂部時(shí)懸浮
    Tab滾動(dòng)后懸浮在頂部嘛~~ 這效果使用CoordinatorLayout + AppBarLayout就能輕松實(shí)現(xiàn)。(什么?你還不懂這兩個(gè)控件怎么使用?額,應(yīng)該可以勉強(qiáng)看懂后面的內(nèi)容)
  • 2、頂部懸浮以及“被頂走”的效果
    只要在CoordinatorLayout外面套一層FrameLayout,然后把這個(gè)頂部的布局改在上面。接著監(jiān)聽AppBarLayout的滾動(dòng),利用topMargin實(shí)現(xiàn)被“頂上去”的效果

拆分完畢,接下來(lái)就是實(shí)現(xiàn)了

實(shí)現(xiàn)

  • Tab的懸浮效果
    利用CoordinatorLayoutAppBarLayoutTabLayoutViewPager來(lái)實(shí)現(xiàn)Tab的懸浮效果
<?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:background="#FFF">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFF">

        <LinearLayout
            android:id="@+id/ll"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/header"
                android:layout_width="match_parent"
                android:layout_height="260dp"
                android:scaleType="centerCrop"
                android:src="@drawable/bg_header"/>
        </LinearLayout>

        <android.support.design.widget.TabLayout
            android:id="@+id/table_layout"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#FBDD9C"
            app:tabGravity="fill"
            app:tabIndicatorColor="#5f00"
            app:tabIndicatorHeight="4dp"
            app:tabMode="fixed"
            app:tabSelectedTextColor="#FFFFFF"
            app:tabTextColor="#FFFFFF"/>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
  • LinearLayout中設(shè)置app:layout_scrollFlags="scroll|exitUntilCollapsed"TabLayout 不設(shè)置app:layout_scrollFlags屬性
  • ViewPager中使用app:layout_behavior="@string/appbar_scrolling_view_behavior"

layout_scrollFlags:AppBarLayout供Children View使用的屬性,一共有五種值:scroll,enterAlways,enterAlwaysCollapsed,snap,exitUntilCollapsed。具體的使用可以參考Android 詳細(xì)分析AppBarLayout的五種ScrollFlags
(CoordinatorLayout、AppBarLayout的詳細(xì)用法我就不多說(shuō)了)

然后,只要在Java代碼中為ViewPager添加幾個(gè)列表Fragment就能看到以下的效果(注意:列表不可以是ListView,需要用RecyclerView

效果

到目前為止,效果已經(jīng)實(shí)現(xiàn)了大半。最后值需要實(shí)現(xiàn)“被頂走”的效果就好了。

  • 頂部“被頂走”的效果
    這時(shí)候,布局稍微改變下。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#FFF">

        <android.support.design.widget.AppBarLayout
            android:id="@+id/app_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#FFF">

            <LinearLayout
                android:id="@+id/ll"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">

                <View
                    android:layout_width="match_parent"
                    android:layout_height="50dp"/>

                <ImageView
                    android:id="@+id/header"
                    android:layout_width="match_parent"
                    android:layout_height="260dp"
                    android:scaleType="centerCrop"
                    android:src="@drawable/bg_header"/>
            </LinearLayout>

            <android.support.design.widget.TabLayout
                android:id="@+id/table_layout"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:background="#FBDD9C"
                app:tabGravity="fill"
                app:tabIndicatorColor="#5f00"
                app:tabIndicatorHeight="4dp"
                app:tabMode="fixed"
                app:tabSelectedTextColor="#FFFFFF"
                app:tabTextColor="#FFFFFF"/>
        </android.support.design.widget.AppBarLayout>

        <android.support.v4.view.ViewPager
            android:id="@+id/vp"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
    </android.support.design.widget.CoordinatorLayout>

    <TextView
        android:id="@+id/sticky_view"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:textColor="#FFFFFF"
        android:text="除了懸浮 我還會(huì)動(dòng)"
        android:gravity="center"
        android:textSize="16sp"
        android:background="#39b9e9"/>
</FrameLayout>

在原有的基礎(chǔ)上,套了個(gè)FrameLayout,頂部的懸浮部分可以通過(guò)FrameLayout來(lái)實(shí)現(xiàn)。這樣也導(dǎo)致下面的布局被蓋住了一部分,因此在LinearLayout中加了與懸浮部分相同高度的空View

布局是完成了,那個(gè)“被頂走”的效果怎么實(shí)現(xiàn)呢?這時(shí)候只要在MainActivity中對(duì)AppBarLayout的滾動(dòng)進(jìn)行監(jiān)聽即可。

    @BindView(R.id.app_bar)
    AppBarLayout mAppBar;
    @BindView(R.id.sticky_view)
    View mStickyView;
    @BindView(R.id.header)
    View mHeader;

    private void setAppBarListener() {
        mAppBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                //頭部高度(除去被頂部覆蓋的部分)
                int minScrollHeight = mHeader.getMeasuredHeight();
                int margin = minScrollHeight + verticalOffset;
                margin = margin > 0 ? 0 : margin;
                FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mStickyView.getLayoutParams();
                layoutParams.topMargin = margin;
                mStickyView.setLayoutParams(layoutParams);
            }
        });
}

這里通過(guò)AppBarLayout滾動(dòng)的進(jìn)行監(jiān)聽(向上滾動(dòng)時(shí),verticalOffset值的變化為:0、-1 、-2 ... -n-1、-n)來(lái)計(jì)算margin值。通過(guò)改變topMargin,實(shí)現(xiàn)“被頂走”的效果。
再看一眼效果:

效果

敲到這里,我才默默的收起了那把砍產(chǎn)品專用菜刀。

Tips

  • 問(wèn)題:使用CoordinatorLayout時(shí),滾動(dòng)不流暢問(wèn)題
    解決方案:可以寫個(gè)Behavior添加到AppBarLayout中。具體的解決方案
  • 問(wèn)題:如果你在想要刷新功能,在CoordinatorLayout外面套了一個(gè)SwipeRefreshLayout,一不小心就觸發(fā)了刷新~~(自己體會(huì))
    解決方案:這個(gè)問(wèn)題可以通過(guò)對(duì)AppBarLayout的監(jiān)聽,設(shè)置swipeLayout的Enabled來(lái)處理
mAblAppBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {
   if (verticalOffset == 0) {
      swipeLayout.setEnabled(true);
   } else {
       if (!swipeLayout.isRefreshing()) {
          swipeLayout.setEnabled(false);
       }
   }
});

源碼地址

Github

以上有錯(cuò)誤之處,感謝指出

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,065評(píng)論 25 708
  • CoordinatorLayout與滾動(dòng)的處理 CoordinatorLayout實(shí)現(xiàn)了多種Material De...
    cxm11閱讀 6,614評(píng)論 1 15
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,876評(píng)論 22 665
  • 本文出自 “阿敏其人” 簡(jiǎn)書博客,轉(zhuǎn)載或引用請(qǐng)注明出處。 本文主要涉及android里面md設(shè)計(jì)的幾個(gè)控件Coor...
    阿敏其人閱讀 10,508評(píng)論 9 43
  • 吃過(guò)飯后,我來(lái)到陽(yáng)臺(tái)。 打開窗戶,一陣飯菜的香味傳來(lái)。 陽(yáng)臺(tái)上滿布著花生,朝地下望去,車旁灑落了許多花生,我們家的...
    呆呆Y閱讀 275評(píng)論 0 1