上次简单的说了一下CoordinatorLayout的基本用法(android特性之CoordinatorLayout用法探析实例)。其中CoordinatorLayout给我们提供了一种新的事件的处理方式,Behavior。还记得那一串字符串吗?

app:layout_behavior="@string/appbar_scrolling_view_behavior"
其实它并不是一个字符串资源,而它代表的是一个类,就是一个Behavior,这玩意其实还可以自定义的。

首先,来让我见识一下它的真面目:

public static abstract class Behavior<V extends View> {...}
Behavior是 CoordinatorLayout的一个内部泛型抽象类。内部类中指定的view类型规定了哪种类型的view的可以使用才Behavior。因此,如果没有特殊需求,直接指定view为View就行了。

1.某个view需要根据监听另一个的行为来控制自己的行为,这个时候我们需要重写2个方法:

 public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency) {            return false;        }
 public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) {            return false;        }
2.我们的view需要根据监听 CoordinatorLayout中的子view的滚动行为来改变自己的状态,现在我们就需要重写下面的方法了:

        public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,                V child, View directTargetChild, View target, int nestedScrollAxes) {            return false;        }
        public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target,                int dx, int dy, int[] consumed) {            // Do nothing        }
下面我们先来看一下情况1,让一个view跟随另一个view的行为而实现状态的改变。我们定义一个Behavior,名字叫:FooterBehavior,代码如下:

package com.lingyun.coordinatorlayoutdemo;import android.content.Context;import android.support.design.widget.AppBarLayout;import android.support.design.widget.CoordinatorLayout;import android.util.AttributeSet;import android.view.View;/** * Created by dandy on 2016/7/4. */public class FooterBehavior extends CoordinatorLayout.Behavior<View>{    public FooterBehavior(Context context,AttributeSet attributeSet){        super(context,attributeSet);    }    @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 scaleY = Math.abs(dependency.getY()) / dependency.getHeight();        child.setTranslationY(child.getHeight() * scaleY);        return true;    }}
我们在自定义的Behavior中 ,带有参数的这个构造必须要重载,因为在CoordinatorLayout里利用反射去获取这个Behavior的时候就是拿的这个构造。
在layoutDependsOn中,我们设置 让View的状态来跟随AppBarLayout,也就是说只有AppBarLayout的状态发生变化才会影响到View。

接下来就是在onDependentViewChanged中对View做出相应的状态改变。在代码中,我们做的改变是,跟随dependedcy一起在Y轴方向移动,来达到显示和隐藏的目的。先布局如下:

activity_main.xml布局:

<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.CoordinatorLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <include layout="@layout/appbar_main"/>    <include layout="@layout/content_main" />    <include layout="@layout/footer_main"/></android.support.design.widget.CoordinatorLayout>
appbar_main.xml布局如下:

<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.AppBarLayout    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="wrap_content"    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">    <android.support.v7.widget.Toolbar        android:id="@+id/toolbar"        android:layout_width="match_parent"        android:layout_height="?attr/actionBarSize"        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"        android:background="?attr/colorPrimary"        app:layout_scrollFlags="scroll|enterAlways"/></android.support.design.widget.AppBarLayout>
content_main.xml布局如下:

<?xml version="1.0" encoding="utf-8"?><android.support.v4.widget.NestedScrollView    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"    app:layout_behavior="@string/appbar_scrolling_view_behavior">    <TextView        android:layout_width="match_parent"        android:layout_height="match_parent"        android:gravity="center"        android:text="你是谁?你从哪里来?你到哪里去?"/></android.support.v4.widget.NestedScrollView>
footer_main.xml布局如下:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:orientation="horizontal"    android:layout_width="match_parent"    android:layout_height="60dp"    android:layout_gravity="bottom"    android:background="?attr/colorPrimary"    app:layout_behavior="com.lingyun.coordinatorlayoutdemo.FooterBehavior">    <TextView        android:layout_width="0dp"        android:layout_height="match_parent"        android:text="Tab1"        android:layout_weight="1"        android:gravity="center"        android:textColor="@android:color/white"/>    <TextView        android:layout_width="0dp"        android:layout_height="match_parent"        android:text="Tab2"        android:layout_weight="1"        android:gravity="center"        android:textColor="@android:color/white"/>    <TextView        android:layout_width="0dp"        android:layout_height="match_parent"        android:text="Tab3"        android:layout_weight="1"        android:gravity="center"        android:textColor="@android:color/white"/></LinearLayout>
注意看,在footer_main.xml中我们设置了
app:layout_behavior="com.lingyun.coordinatorlayoutdemo.FooterBehavior"
这正好就是我们自定义的FooterBehavior的绝对路径。下面我们来看一下效果图:


在效果图上我们看到,当我们上下滑动屏幕的时候,底部footer布局和标题Toolbar一起移动,实现了显示和隐藏的效果。

学会了第一张简单的自定义Behavior之后,接下来我们再来看一下第二种情况,滑动。因为这个是根据CoordinatorLayout里子view的滚动行为来改变我们的状态的,所以情况1中的2个方法我们就不需要重写了。下面,我们用情况2来实现上面的效果。

先来看一下下面几个参数:

child:简单点说,就是用到当前CoordinatorLayout的子View,响应此Behavior。

target:CoordinatorLayout的子View,引起滚动的view,其实child的状态改变是根据target来实现的。

package com.lingyun.coordinatorlayoutdemo;import android.content.Context;import android.support.design.widget.CoordinatorLayout;import android.support.v4.view.ViewCompat;import android.util.AttributeSet;import android.view.View;/** * Created by dandy on 2016/7/4. */public class FooterBehavior extends CoordinatorLayout.Behavior<View>{    private float targetY = -1;    private static final String TAG = "FooterBehavior";    public FooterBehavior(Context context,AttributeSet attributeSet){        super(context, attributeSet);    }    @Override    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child,                                       View directTargetChild, View target, int nestedScrollAxes) {        if(targetY == -1){            targetY = target.getY();        }        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;    }    @Override    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target,                                  int dx, int dy, int[] consumed) {        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);        float scrooY = targetY - Math.abs(target.getY());        float scaleY = scrooY / targetY;        child.setTranslationY(child.getHeight() * scaleY);    }}
在方法onStartNestedScroll中,首先获取target在Y轴上距离屏幕顶端的距离,然后判断是否是在Y轴上滚动。

方法onNestPreScroll中,就是时时根据target距离屏幕顶端的距离计算出滚动的距离,然后根据比例计算出child移动的距离。

截图和上面比较没啥区别:



基本的自定义Behavior就是这样了,



更多相关文章

  1. 《第一行代码》学习笔记 第 3 章
  2. android检测网络连接状态示例讲解
  3. 安卓入门.控件样式
  4. android 布局相关
  5. android 使用Google地图步骤要点
  6. Android(安卓)中文 API 文档 (45) —— AbsoluteLayout.LayoutPara
  7. 揭秘uc浏览器三
  8. Android的ViewAnimator及其子类ViewSwitcher-android学习之旅(三
  9. 1.2android——UI界面之ScrollView实现上下文滚动

随机推荐

  1. 从入门到入土(三)RocketMQ 怎么保证的消息
  2. Java集合面试题(2021最新版)
  3. 函数的返回值,参数
  4. 孙卫琴的《精通JPA与Hibernate》的读书笔
  5. 孙卫琴的《精通JPA与Hibernate》的读书笔
  6. IntelliJ IDEA破解2021.5月亲测实战详细
  7. 大咖访谈 | 李少鹏的网安江湖
  8. 孙卫琴的《精通JPA与Hibernate》的读书笔
  9. 孙卫琴的《精通JPA与Hibernate》的读书笔
  10. 孙卫琴的《精通JPA与Hibernate》的读书笔