Android:自定义CoordinatorLayout.behavior 简单的仿UC首页

      CoordinatorLayout顾名思义协调布局,是用来协调该布局下的子控件,最简单地使用就是头部伸缩和折叠了,配合着TabLayout,只需要设置一下AppBarLayout子控件的layout_scrollFlags以及底下滑动控件的layout_behavior就行了,组合起来效果非常不错,网上这种详细的教程有很多,这片文章主要讲述一下简单的自定义behavior。

     在behavior中可以设置触摸事件拦截onInterceptTouchEvent(),触摸事件响应onTouchEvent(),View依赖另一个ViewlayoutDependsOn()、onDependentViewChanged(),嵌套滑动事件处理onStartNestedScroll()、onStopNestedScroll()、onNestedScroll()、onNestedPreScroll()以及还有两个快速滑动的方法,

       这篇文章使用的是behavior的依赖方法,ViewlayoutDependsOn()和onDependentViewChanged()。

    ViewlayoutDependsOn(CoordinatorLayout parent, View child, View dependency):child是使用这个behavior的view,dependency则是child所依赖的view。何为依赖?在我看来,就是dependency改变的时候,child能根据dependency的变化,做出反应,如何反应?当 ViewlayoutDependsOn 返回true的时候就可以触发 onDependentViewChanged。

       反应动作写在onDependentViewChanged(CoordinatorLayout parent, View child, View dependency),比方说,可以通过dependency.getX  dependency.getY获取的坐标,设置给child,该View就会跟着依赖View动起来,或者让它反方向动,都可以,非常灵活,最后return true就会生效。

那么来尝试一下吧,UC中首页漂亮的交互动画非常的吸引人,自己也想学着做一个简单的页面。单独看这个页面的话,有三块布局,一个是底下的RecyclerView,一个是逐渐被遮住的导航栏,最后一个是在RecyclerView逐渐上移时候出现的UC头条和TabLayout。如下图(视频用UC转gif就变得好糊,好在还能看出动画):

      在我看来,实现方法有两个:1.通过监听RecyclerView的触摸,然后判断是否让他滑动,以及他在位置改变的时候,TabLayout跟着变动;2.那就是今天的主题了,自定义behavior。第一种方法以前写的时候尝试过,比较难的在于,滑动过程中RecyclerView高度和位置的变化,它并不是简单的上移,单纯上移的话,底下会缺一块;再来就是触摸事件的分发和滑动的拦截了,以前写的时候失败了,bug很严重,对于事件分发的确不是很扎实,还得多学学。采用第二种,其实也会碰到这些难点,但是今天在于简单的实践,最简单地使用CoordinatorLayout。相信大家都有所了解,在写了AppBarLayout,滑动布局添加

app:layout_behavior="@string/appbar_scrolling_view_behavior"

      滑动布局高度和滑动处理,就解决了,谷歌已经帮我们实现了。我们只需要把UC头条和tablayout依赖RecyclerView,根据RecyclerView的坐标做出改变就行了。下面给出代码,先是自定义Behavior,我使用了NestedScrollView代替RecyclerView,插数据比较好插,要依赖RecyclerView的自己替代一下:

public class MyBehavior extends CoordinatorLayout.Behavior<View> {
    private float allDistance = 0; // Head从和RecyclerView同样位置,移到顶部的距离
    private float dependencyDistance = 0; //RecyclerView需要移动的距离
    public MyBehavior() {
    }

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

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

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        if (allDistance == 0) {
            allDistance = dependency.getY();//获取child要移动的总距离,是dependency到顶部的距离
            Log.d("allDistance", String.valueOf(allDistance));
            dependencyDistance = allDistance - child.getHeight();//获取滑动控件所要移动的总距离,移动到childView下方
            Log.d("recyclerDistance", String.valueOf(dependencyDistance));
            child.setY(allDistance);//初始化child的位置,和dependency位置一样,不然child会在顶部
        } else {
            float distance = (allDistance - dependency.getY()) / dependencyDistance * allDistance;//child所需要移动的距离!
            child.setY(allDistance - distance <= 0 ? 0 : allDistance - distance);//通过距离,计算出child的坐标,最后为0
        }

        return true;
    }

}

这个behavior比较简单,根据dependency的Y坐标,计算出child的Y坐标。接下来是布局文件,比较重要:

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.env.cloud.showview.ui.CoordinatorActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#00ffffff">

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="150dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="250dp"
                android:gravity="center"
                android:text="导航栏"
                android:textColor="#000"
                android:textSize="25sp"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="2.7" />

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

    </android.support.design.widget.AppBarLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:background="#fff000"
        android:orientation="vertical"
        app:layout_behavior="com.env.cloud.showview.views.behavior.MyBehavior">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:gravity="center"
            android:text="UC头条和搜索框"
            android:textSize="25sp" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <android.support.design.widget.TabItem
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="关注" />

            <android.support.design.widget.TabItem
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="推荐" />
        </android.support.design.widget.TabLayout>

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

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="center"
                android:text="内容1"
                android:textSize="20sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="center"
                android:text="内容2"
                android:textSize="20sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="center"
                android:text="内容3"
                android:textSize="20sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="center"
                android:text="内容4"
                android:textSize="20sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="center"
                android:text="内容5"
                android:textSize="20sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="center"
                android:text="内容6"
                android:textSize="20sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="center"
                android:text="内容"
                android:textSize="20sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="center"
                android:text="内容7"
                android:textSize="20sp" />
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>

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

这边有几个点,需要说一下,一个是AppBarLayout设置了一个background为全透明,原因是因为,在折叠完成后,AppBarLayout本来应该在LinearLayout下方,它会跑上来,变成顶层,不设置透明的话,自带的颜色会遮住LinearLayout。LinearLayout中的点击事件应该是不会和CollapsingToolBarLayout冲突的,我没有尝试,需要的小伙伴可以试一下。

然后就是在CollapsingToolbarLayout中设置,设置layout_scrollFlags为scroll|exitUntilCollapsed,snap可选可不选,作用是回弹效果,、android:minHeight="150dp"来控制滑动View能滑动到的距离,这个高度应该和TabLayout+Uc导航栏和搜索框所在的LinearLayout高度一致,这样的话,滑动的View就刚好能在LinearLayout下方。

设置CollapsingToolBarLayout的子控件的折叠:

app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="2.7"

重点在于layout_collapseParallaxMultiplier,网上叫做视觉差系数,就是折叠快慢的控制,之所以设置成这么大,是由于,不够大的情况下,CollapsingToolBarLayout没有收缩完全,里面控件会到上层显示,把LinearLayout遮住,设置大一些的话,会完全折叠,这就是我觉得点击事件不会冲突的原因,因为完全消失了,并不在LinearLayout所在的区域,自然就不会有点击冲突。

 

关键点:折叠布局CollapsingToolbarLayout的最小高度,要和滑动出现的LinearLayout高度一致,这是为了控制滑动控件,比如RecyclerView,NestedScrollView的滑动距离;设置layout_collapseParallaxMultiplier系数大一点,可以自己设置小一点看看效果,上面的布局文件的话,导航栏三个字就会出现在LinearLayout所在的区域,下面上效果图:

额,大致是这样,后面尝试不使用AppBarLayout,再试试吧

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值