ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CoordinateLayout的实现原理

2021-09-02 02:01:17  阅读:218  来源: 互联网

标签:CoordinateLayout behavior LayoutParams 实现 Behavior 原理 对应 View


引言

CoordinateLayout的主要用法:
1、作为顶层应用的装饰或者chrome布局
2、作为一个能响应特定的一个或多个子视图交互的容器
也就是说,CoordinateLayout本身不具备布局的能力,它只是作为一个将Behavior和子View绑定的容器,将收到的事件几乎原封不动的分发给子View对应的Behavior。

例如,BottomSheetDialog的布局:

<FrameLayout
    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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

  <androidx.coordinatorlayout.widget.CoordinatorLayout
      android:id="@+id/coordinator"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:fitsSystemWindows="true">

    <View
        android:id="@+id/touch_outside"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:importantForAccessibility="no"
        android:soundEffectsEnabled="false"
        tools:ignore="UnusedAttribute"/>

    <FrameLayout
        android:id="@+id/design_bottom_sheet"
        style="?attr/bottomSheetStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal|top"
        app:layout_behavior="@string/bottom_sheet_behavior"/>

  </androidx.coordinatorlayout.widget.CoordinatorLayout>

</FrameLayout>

我们将子View add到design_bottom_sheet的FrameLayout中之后,就能实现从底部弹窗的效果。
我们找到这个Behavior发现对应了一个java类,发现了里面包含了大量事件处理的函数。

<string name="bottom_sheet_behavior" translatable="false">com.google.android.material.bottomsheet.BottomSheetBehavior</string>

引发我们思考几个问题:
1、这个layout_behavior属性为什么加在子View上面?
2、上面的Behavior又是如何跟对应的View关联的,为何Behavoir能处理子View对应的行为?

实现原理

针对上述原理,我们进一步探究CoordinateLayout的实现原理。
如引言所说,coordinateLayout只是一个代理,只是仅仅作为事件转发给对应的Behavior,那么是如何转发的呢?以及Behavior又是如何跟对应的子View绑定的呢?
针对第2个问题:
我们回到bottomSheet那个例子,发现在对应的子View上指定了layout_behavior这个属性。
事实上coordianteLayout将子View上的属性解析出来,然后获取layout_behavior上的值,也就是对应的class类名。
之后就可以通过反射class对应的类,构造Behavior对象。
CoordinateLayout继承于ViewGroup,拥有响应事件的能力,因此,它将事件进一步转发给子类的所有Behavior。

其中还有一个关键的问题,就是CoordinateBehavior何时能够获取到子View的Attribute。
事实上,子View在被addView到Parent中的时候,会先看下子View有没有提供LayoutParams,如果没有提供,就会调用父ViewGroup的generatorLayoutParams()生成对应的LayoutParams,在此时接收了子View的Attribute参数。

伪代码:

public class CoordinateLayout extends ViewGroup {
  // 拿到AttributeSet,生成自己的LayoutParams。
  @Override
  public LayoutParams generateLayoutParams(AttributeSet attrs) {
      return new LayoutParams(getContext(), attrs);
  }
  
  private static class LayoutParams {
    Behavor behavior;
    public LayoutParams(Context context, AttributeSet attrs) {
      // get layout_behavior attribute from attrs
      TypedArray typedArray = c.obtainStyledAttributes(attrs, R.styleable.BehaviorCoordinateLayout);
      String behaviorClassName = typedArray.getString(R.styleable.BehaviorCoordinateLayout_layout_behavior);
      // Generate the Behavior object use reflection
      behavior = parseBehavior(behaviorClassName, c, attrs);
      typedArray.recycle();
    }
  }
    

  public void onTouchEvent(MotionEvent event) {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            LayoutParams lp = (LayoutParams) child.getLayoutParams();
            if (lp.behavior != null) {
                lp.behavior.onTouchEvent(this, child, event);
            }
        }
        return false;
  }

  // .. 其他代码省略
}

我们通过在generatorLayoutParams中生成自己的LayoutParams返回,并在LayoutParams中绑定自己对应的Behavior,之后在CoordinateLayout收到某个事件的时候,直接传递给所有子View的Behavior。
需要消费该事件的子View只需要实现Behavior对应的方法,即可完成事件的处理。
Behavior对应的伪代码很简单:

public class Behavior {
    public Behavior(Context context, AttributeSet attrs) {}
    public void onTouchEvent(View parent, View child, MotionEvent ev) { }
}

例如,在BottomSheetDialog中,子View就绑定对应的BottomSheetBehavior,进而在该Behavior中进一步通过viewDragHelper来完成手势等操作,置于viewDragHelper如何使用请自行参考其他文章。

总结

本文主要介绍了CoordinateLayout的原理,描述了其如何绑定子View对应的Behavior,以及如何将对应的Event转发给对应的子View进行处理。

标签:CoordinateLayout,behavior,LayoutParams,实现,Behavior,原理,对应,View
来源: https://www.cnblogs.com/csluoyao/p/15212888.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有