`
iaiai
  • 浏览: 2180969 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

关于CoordinatorLayout与Behavior的一点分析

 
阅读更多
Behavior是Android新出的Design库里新增的布局概念。Behavior只有是CoordinatorLayout的直接子View才有意义。可以为任何View添加一个Behavior。
Behavior是一系列回调。让你有机会以非侵入的为View添加动态的依赖布局,和处理父布局(CoordinatorLayout)滑动手势的机会。不过官方只有少数几个Behavior的例子。对于理解Behavior实在不易。开发过程中也是很多坑,下面总结一下CoordinatorLayout与Behavior。

依赖

首先自定义一个Behavior。
    public class MyBehavior extends CoordinatorLayout.Behavior{
        public MyBehavior(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    }

一定要重写这个构造函数。因为CoordinatorLayout源码中parseBehavior()函数中直接反射调用这个构造函数。
static final Class<?>[] CONSTRUCTOR_PARAMS = new Class<?>[] {
        Context.class,
        AttributeSet.class
};

下面反射生成Behavior实例在实例化CoordinatorLayout.LayoutParams时:
final Class<Behavior> clazz = (Class<Behavior>) Class.forName(fullName, true,
                 context.getClassLoader());
c = clazz.getConstructor(CONSTRUCTOR_PARAMS);
c.setAccessible(true);
constructors.put(fullName, c);
return c.newInstance(context, attrs)

在任意View中添加:
app:layout_behavior=“你的Behavior包含包名的类名”

然后CoordinatorLayout就会反射生成你的Behavior。

另外一种方法如果你的自定义View默认使用一个Behavior。
在你的自定义View类上添加@DefaultBehavior(你的Behavior.class)这句注解。
你的View就默认使用这个Behavior。就像AppBarLayout一样。
@DefaultBehavior(AppBarLayout.Behavior.class)
public class AppBarLayout extends LinearLayout {}

生成Behavior后第一件事就是确定依赖关系。重写Behavior的这个方法来确定你依赖哪些View。
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
    return dependency.getId() == R.id.first;
}

child 是指应用behavior的View ,dependency 担任触发behavior的角色,并与child进行互动。
确定你是否依赖于这个View。CoordinatorLayout会将自己所有View遍历判断。
如果确定依赖。这个方法很重要。当所依赖的View变动时会回调这个方法。
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
    return true;
}

下面这个例子:
    <declare-styleable name="Follow">
        <attr name="target" format="reference"/>
    </declare-styleable>

先自定义target这个属性。
  public class FollowBehavior extends CoordinatorLayout.Behavior {
  private int targetId;

  public FollowBehavior(Context context, AttributeSet attrs) {
      super(context, attrs);
      TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Follow);
      for (int i = 0; i < a.getIndexCount(); i++) {
          int attr = a.getIndex(i);
          if(a.getIndex(i) == R.styleable.Follow_target){
              targetId = a.getResourceId(attr, -1);
          }
      }
      a.recycle();
  }

  @Override
  public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
       child.setY(dependency.getY()+dependency.getHeight());
      return true;
  }

  @Override
  public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
      return dependency.getId() == targetId;
  }
}

xml中:
<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:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <View
        android:id="@+id/first"
        android:layout_width="match_parent"
        android:layout_height="128dp"
        android:background="@android:color/holo_blue_light"/>

    <View
        android:id="@+id/second"
        android:layout_width="match_parent"
        android:layout_height="128dp"
        app:layout_behavior=".FollowBehavior"
        app:target="@id/first"
        android:background="@android:color/holo_green_light"/>


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

效果是不管first怎么移动。second都会在他下面。

滑动

Behavior最大的用处在于对滑动事件的处理。就像CollapsingToolbarLayout的那个酷炫效果一样。

主要是这3个方法,所依赖对象的滑动事件都将通知进来:
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
    return true;//这里返回true,才会接受到后续滑动事件。
}

@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
//进行滑动事件处理
}

@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) {
//当进行快速滑动
    return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
}

注意被依赖的View只有实现了NestedScrollingChild接口的才可以将事件传递给CoordinatorLayout。
但注意这个滑动事件是对于CoordinatorLayout的。所以只要CoordinatorLayout有NestedScrollingChild就会滑动,他滑动就会触发这几个回调。无论你是否依赖了那个View。
下面就是一个简单的View跟随ScrollView滑入滑出屏幕的例子。可以是Toolbar或其他任何View。
public class ScrollToTopBehavior extends CoordinatorLayout.Behavior<View>{
    int offsetTotal = 0;
    boolean scrolling = false;

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

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

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        offset(child, dyConsumed);
    }

    public void offset(View child,int dy){
        int old = offsetTotal;
        int top = offsetTotal - dy;
        top = Math.max(top, -child.getHeight());
        top = Math.min(top, 0);
        offsetTotal = top;
        if (old == offsetTotal){
            scrolling = false;
            return;
        }
        int delta = offsetTotal-old;
        child.offsetTopAndBottom(delta);
        scrolling = true;
    }

}

xml中:
<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:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="false"
    tools:context=".MainActivity">

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/second"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="128dp"
                style="@style/TextAppearance.AppCompat.Display3"
                android:text="A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ"
                android:background="@android:color/holo_red_light"/>
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>

    <View
        android:id="@+id/first"
        android:layout_width="match_parent"
        android:layout_height="128dp"
        app:layout_behavior=".ScrollToTopBehavior"
        android:background="@android:color/holo_blue_light"/>

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

当NestedScrollView滑动的时候,first也能跟着滑动。toolbar和fab的上滑隐藏都可以这样实现。

事件处理

这2个回调与View中的事件分发是一样的。所有Behavior能在子View之前收到CoordinatorLayout的所有触摸事件。可以进行拦截,如果拦截事件将不会流经子View。因为这2个方法都是在CoordinatorLayout的 回调中
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {
    return super.onInterceptTouchEvent(parent, child, ev);
}

@Override
public boolean onTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {
    return super.onTouchEvent(parent, child, ev);
}

AppBarLayout的收缩原理分析
示例中给可滑动View设的Behavior是
@string/appbar_scrolling_view_behavior(android.support.design.widget.AppBarLayout$ScrollingViewBehavior)。
它的源码不多,看得出唯一的作用是把自己放到AppBarLayout的下面...(不能理解为什么叫ScrollingViewBehavior)
所有View都能使用这个Behavior。

AppBarLayout自带一个Behivior。直接在源码里注解声明的。这个Behivior也只能用于AppBarLayout。
作用是让他根据CoordinatorLayout上的滚动手势进行一些效果。与@string/appbar_scrolling_view_behavior是无关的,加不加这个Behivior都没关系。
只不过只有某些可滑动View才会把滑动事件响应给CoordinatorLayout才能继而响应给AppBarLayout。
  • 大小: 32.7 KB
  • 大小: 402.9 KB
分享到:
评论

相关推荐

    CoordinatorLayout之Behavior使用

    `CoordinatorLayout`的主要特点是可以实现各种复杂的布局动画和交互效果,比如悬浮按钮(FloatingActionButton)跟随滚动行为、Header视图的隐藏与显示等。在本文中,我们将深入探讨`CoordinatorLayout`中的`...

    Coordinatorlayout嵌套滑动,自定义Behavior的Demo

    `Behavior`是`CoordinatorLayout`的一个关键组件,它定义了子视图在特定事件(如滚动)下的行为。 `Behavior`的概念是`CoordinatorLayout`的核心特性,它允许开发者自定义特定视图的行为,尤其是当这个视图和其他...

    CoordinatorLayout自定义Behavior

    这篇博客的文章标题是“CoordinatorLayout自定义Behavior”,显然,它将引导我们深入理解如何为`CoordinatorLayout` 创建自定义的行为。 `Behavior` 是`CoordinatorLayout` 的一个重要组成部分,它定义了特定视图在...

    CoordinatorLayout+Behavior实现复杂联动效果

    CoordinatorLayout 是 Google 在 Design Support 包中提供的一个十分强大的布局视图,它允许开发者通过制定 Behavior 从而实现各种复杂的 UI 效果。工程导入可以直接运行。。。

    Android-CoordinatorLayout与Behavior的实际使用示例

    本示例将详细介绍`CoordinatorLayout`与`Behavior`的实际使用,帮助开发者理解和掌握这一强大的布局组件。 `CoordinatorLayout`是一个顶级布局容器,它可以智能地协调其子视图的行为。它最显著的特点就是能够处理子...

    learn-coordinatorlayout-behavior:CoordinatorLayout 自定义Behavior 高仿美团商家详情界面 实现页面内容复杂联动效果

    该项目是为了练习-&gt; 使用CoordinatorLayout.Behavior 实现页面复杂联动效果 代码模仿实现美团商家详情界面内容联动 开发使用知识点顺带涉及到: Scroller+Handler 实现View自动滑动 View属性动画 触摸事件分发机制 ...

    CoordinatorLayout扩展behavior

    4. **处理ImageView**:与`Toolbar`类似,我们也可以为`ImageView` 创建一个`Behavior`,使其在下拉时显示,上滑时隐藏。关键在于调整`ImageView` 的位置和可见性,这可以通过修改`Behavior` 中的滚动处理逻辑实现。...

    Android代码-自定义CoordinatorLayout.Behavior仿美团商家详情界面实现内容复杂联动

    该项目是为了练习-&gt; 使用CoordinatorLayout.Behavior 实现页面复杂联动效果 代码模仿实现美团商家详情界面内容联动 download apk 开发使用知识点顺带涉及到: Scroller Handler 实现View自动滑动 View属性动画 ...

    Android CoordinatorLayout高级用法之自定义Behavior

    其中CoordinatorLayout给我们提供了一种新的事件的处理方式,Behavior。还记得那一串字符串吗? app:layout_behavior=@string/appbar_scrolling_view_behavior 其实它并不是一个字符串资源,而它代表的是一个类,...

    自定义behavior监听控件的滑动事件

    在Android开发中,Behavior是Android Design Support ...在实现过程中,理解Behavior的工作原理以及如何与 CoordinatorLayout 配合是至关重要的。参考链接中的博客文章提供了具体实例,可以作为学习和实践的起点。

    CoordinatorLayoutBehaviorSample:CoordinatorLayout.Behavior的示例程序

    CoordinatorLayout.Behavior的示例程序。 惊人的行为 这是CoordinatorLayout行为的示例。 它包含具有自定义行为的可拖动TextView。 自定义行为将使对象无论在何处都遵循可拖动的“ TextView”。 屏幕截图 每个人都在...

    Android-使用Behavior高仿实现UC浏览器首页上下滑动效果

    Behavior是 CoordinatorLayout 的一部分,它允许自定义布局的滚动行为,从而实现复杂而流畅的用户界面动画。 首先,Behavior 是一个抽象类,需要我们去继承并重写其中的关键方法,如 `onNestedScroll` 和 `...

    CoordinatorLayout

    `Behavior`是`CoordinatorLayout`特有的接口,定义了子视图与`CoordinatorLayout`之间的交互规则。通过实现`Behavior`,你可以自定义视图的行为,如响应滑动事件、改变视图位置等。`Behavior`可以通过XML或代码动态...

    Coordinatorlayout

    2. 自定义`Behavior`:如果项目中包含了自定义的`Behavior`类,那么开发者可能已经扩展了`CoordinatorLayout.Behavior`,以便为特定的视图添加自定义的滚动行为。 3. 主题和样式:可能包含了自定义的主题和样式资源...

    CoordinatorLayout控件的基本使用

    `CoordinatorLayout`的主要功能是协调其子视图的行为,尤其是与滚动行为相关的交互,例如,它能实现fab(浮动操作按钮)的动画效果、顶部栏的滑动隐藏等高级UI效果。 ### CoordinatorLayout的基础概念 `...

    自定义Behavior简单教程

    自定义Behavior Demo,可以结合任何View使用,可以自定义动画等!详解请移步严振杰的博客:http://blog.csdn.net/yanzhenjie1003/article/details/52205665

Global site tag (gtag.js) - Google Analytics