【Android】这效果,我没法描述

来源:互联网 发布:淘宝一元捡漏 编辑:程序博客网 时间:2024/05/22 03:42

前言

最近接到一个需求,这需求让我表示很尴尬。(下面是一些废话)
要求的效果是这样的,顶部有部分悬浮,接着是一些布局,在下面是几个可切换的Tab页面,然后滚动的时候~~吧啦吧啦吧啦吧啦~~ 还是直接看图吧

效果
效果

主要就是顶部和Tab的悬浮,还有就是被顶掉的那个效果。

听到要实现这样的效果,我抽屉那把砍产品专用菜刀已经蠢蠢欲动了。

思路

先说说实现的思路吧,上面的效果大致可以分成两个部分:

  • 1、Tab向上滚动到顶部时悬浮
    Tab滚动后悬浮在顶部嘛~~ 这效果使用CoordinatorLayout + AppBarLayout就能轻松实现。(什么?你还不懂这两个控件怎么使用?额,应该可以勉强看懂后面的内容)
  • 2、顶部悬浮以及“被顶走”的效果
    只要在CoordinatorLayout外面套一层FrameLayout,然后把这个顶部的布局改在上面。接着监听AppBarLayout的滚动,利用topMargin实现被“顶上去”的效果

拆分完毕,接下来就是实现了

实现

  • Tab的悬浮效果
    利用CoordinatorLayoutAppBarLayoutTabLayoutViewPager来实现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中设置app:layout_scrollFlags="scroll|exitUntilCollapsed"TabLayout 不设置app:layout_scrollFlags属性
  • ViewPager中使用app:layout_behavior="@string/appbar_scrolling_view_behavior"

layout_scrollFlags:AppBarLayout供Children View使用的属性,一共有五种值:scroll,enterAlways,enterAlwaysCollapsed,snap,exitUntilCollapsed。具体的使用可以参考Android 详细分析AppBarLayout的五种ScrollFlags
(CoordinatorLayout、AppBarLayout的详细用法我就不多说了)

然后,只要在Java代码中为ViewPager添加几个列表Fragment就能看到以下的效果(注意:列表不可以是ListView,需要用RecyclerView

效果
效果

到目前为止,效果已经实现了大半。最后值需要实现“被顶走”的效果就好了。

  • 顶部“被顶走”的效果
    这时候,布局稍微改变下。
<?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="除了悬浮 我还会动"        android:gravity="center"        android:textSize="16sp"        android:background="#39b9e9"/></FrameLayout>

在原有的基础上,套了个FrameLayout,顶部的悬浮部分可以通过FrameLayout来实现。这样也导致下面的布局被盖住了一部分,因此在LinearLayout中加了与悬浮部分相同高度的空View

布局是完成了,那个“被顶走”的效果怎么实现呢?这时候只要在MainActivity中对AppBarLayout的滚动进行监听即可。

    @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);            }        });}

这里通过AppBarLayout滚动的进行监听(向上滚动时,verticalOffset值的变化为:0、-1 、-2 … -n-1、-n)来计算margin值。通过改变topMargin,实现“被顶走”的效果。
再看一眼效果:

效果
效果

敲到这里,我才默默的收起了那把砍产品专用菜刀。

Tips

  • 问题:使用CoordinatorLayout时,滚动不流畅问题
    解决方案:可以写个Behavior添加到AppBarLayout中。具体的解决方案
  • 问题:如果你在想要刷新功能,在CoordinatorLayout外面套了一个SwipeRefreshLayout,一不小心就触发了刷新~~(自己体会)
    解决方案:这个问题可以通过对AppBarLayout的监听,设置swipeLayout的Enabled来处理
mAblAppBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {   if (verticalOffset == 0) {      swipeLayout.setEnabled(true);   } else {       if (!swipeLayout.isRefreshing()) {          swipeLayout.setEnabled(false);       }   }});

源码地址

Github

以上有错误之处,感谢指出


http://www.jianshu.com/p/89908e1c9801
原创粉丝点击