2019独角兽企业重金招聘Python工程师标准>>>

主页:http://cherylgood.cn/20170302/51

官网描述为:CoordinatorLayout是一个增强版的FrameLayout(继承自ViewGroup)

用途:

1、作为应用的顶层视图。

2、作为一个可以指定子View之间相互作用的容器,通过给CoordinatorLayout的子View指定CoordinatorLayout.Behavior 来定义子view之间的相互作用。(你可以想象成:CoordinatorLayout相当于在两个View之间充当中介,这样子的好处就是两个view之间的耦合度降低了,只需要跟coordinatorLayout打交到即可,而CoordinatorLayout.Behavior 相当于两个view之间的协议,即通过怎样的规则来约束双方的行为。)

设计概念:

  1. CoordinatorLayout:CoordinatorLayout 作为最顶层视图,将负责管理所有的子view,使其内部的子View彼此间产生一种联系。这个联系通过Behavior来实现(包括了滑动状态的处理以及View状态的处理)。
  2. AppBarLayout:AppBarLayout 继承自限性布局,作为增强版的线性布局,他增加了对滑动手势的处理。
  3. Behavior:Behavior 是google新提出的,能够让你以非侵入式的方式去处理目标View和其他View的交互行为。Behavior需要设置在触发事件(比如滚动)的view上,且这个View必须是CoordinatorLayout的第一层级下的子view,否则没有效果,因为Behavior的初始化是在CoordinatorLayout的LayoutParams中通过反射完成的。
    Behavior实例化方式:1、通过app:layout_behavior声明 ;2、在你的自定义View类上添加@DefaultBehavior(MyBehavior.class);
  4. Behavior只是个接口,其调用是由NestedScrollingParent与NestedScrollingChild接口负责调用。

接下来我们通过阅读部分源码进行学习:

首先,我们从两个view是如何通过coordinatorlayout产生关联来入手;看代码

LayoutParams(Context context, AttributeSet attrs) {super(context, attrs);final TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.CoordinatorLayout_Layout);this.gravity = a.getInteger(R.styleable.CoordinatorLayout_Layout_android_layout_gravity,Gravity.NO_GRAVITY);mAnchorId = a.getResourceId(R.styleable.CoordinatorLayout_Layout_layout_anchor,View.NO_ID);this.anchorGravity = a.getInteger(R.styleable.CoordinatorLayout_Layout_layout_anchorGravity,Gravity.NO_GRAVITY);this.keyline = a.getInteger(R.styleable.CoordinatorLayout_Layout_layout_keyline,-1);insetEdge = a.getInt(R.styleable.CoordinatorLayout_Layout_layout_insetEdge, 0);dodgeInsetEdges = a.getInt(R.styleable.CoordinatorLayout_Layout_layout_dodgeInsetEdges, 0);mBehaviorResolved = a.hasValue(R.styleable.CoordinatorLayout_Layout_layout_behavior);if (mBehaviorResolved) {mBehavior = parseBehavior(context, attrs, a.getString(R.styleable.CoordinatorLayout_Layout_layout_behavior));}a.recycle();if (mBehavior != null) {// If we have a Behavior, dispatch that it has been attachedmBehavior.onAttachedToLayoutParams(this);}}

mBehaviorResolved = a.hasValue(R.styleable.CoordinatorLayout_Layout_layout_behavior);
if (mBehaviorResolved) {mBehavior = parseBehavior(context, attrs, a.getString(R.styleable.CoordinatorLayout_Layout_layout_behavior));
}
这几句我们可以看到。
mBehaviorResolved 是个boolean 变量,如果
R.styleable.CoordinatorLayout_Layout_layout_behavior CoordinatorLayout的
layout_behavior这个字段设置有值,
1、mBehaviorResolved = true -》调用parseBehavior方法,将所需参数传入通过java的反射技术返回一个Behavior实例。
static Behavior parseBehavior(Context context, AttributeSet attrs, String name) {if (TextUtils.isEmpty(name)) {return null;}final String fullName;if (name.startsWith(".")) {// Relative to the app package. Prepend the app package name.fullName = context.getPackageName() + name;} else if (name.indexOf('.') >= 0) {// Fully qualified package name.fullName = name;} else {// Assume stock behavior in this package (if we have one)fullName = !TextUtils.isEmpty(WIDGET_PACKAGE_NAME)? (WIDGET_PACKAGE_NAME + '.' + name): name;}try {Map<String, Constructor> constructors = sConstructors.get();if (constructors == null) {constructors = new HashMap<>();sConstructors.set(constructors);}Constructor c = constructors.get(fullName);if (c == null) {final Class clazz = (Class) Class.forName(fullName, true,context.getClassLoader());c = clazz.getConstructor(CONSTRUCTOR_PARAMS);c.setAccessible(true);constructors.put(fullName, c);}return c.newInstance(context, attrs);} catch (Exception e) {throw new RuntimeException("Could not inflate Behavior subclass " + fullName, e);}}
通过这一段我们可以知道,最后是通过调用Behavior的参数为(context,attrs)的构造函数进行实例化。
实例化出Behavior之后我们会调用behavior的onAttachedToLayoutParams方法 将LayoutParams的实例对象传进去mBehavior.onAttachedToLayoutParams(this);
mBehavior.onAttachedToLayoutParams是一个当LayoutParams被实例化后的回调方法。通过这里,我们的
CoordinatorLayout就能够跟用layout_behavior标识的子View产生联系。当子View发生变化时,CoordinatorLayout又是如何处理的的,请看下面代码:
final void onChildViewsChanged(@DispatchChangeEvent final int type) {final int layoutDirection = ViewCompat.getLayoutDirection(this);final int childCount = mDependencySortedChildren.size();final Rect inset = acquireTempRect();final Rect drawRect = acquireTempRect();final Rect lastDrawRect = acquireTempRect();for (int i = 0; i < childCount; i++) {final View child = mDependencySortedChildren.get(i);final LayoutParams lp = (LayoutParams) child.getLayoutParams();if (type == EVENT_PRE_DRAW && child.getVisibility() == View.GONE) {// Do not try to update GONE child views in pre draw updates.continue;}// Check child views before for anchorfor (int j = 0; j < i; j++) {final View checkChild = mDependencySortedChildren.get(j);if (lp.mAnchorDirectChild == checkChild) {offsetChildToAnchor(child, layoutDirection);}}// Get the current draw rect of the viewgetChildRect(child, true, drawRect);// Accumulate inset sizesif (lp.insetEdge != Gravity.NO_GRAVITY && !drawRect.isEmpty()) {final int absInsetEdge = GravityCompat.getAbsoluteGravity(lp.insetEdge, layoutDirection);switch (absInsetEdge & Gravity.VERTICAL_GRAVITY_MASK) {case Gravity.TOP:inset.top = Math.max(inset.top, drawRect.bottom);break;case Gravity.BOTTOM:inset.bottom = Math.max(inset.bottom, getHeight() - drawRect.top);break;}switch (absInsetEdge & Gravity.HORIZONTAL_GRAVITY_MASK) {case Gravity.LEFT:inset.left = Math.max(inset.left, drawRect.right);break;case Gravity.RIGHT:inset.right = Math.max(inset.right, getWidth() - drawRect.left);break;}}// Dodge inset edges if necessaryif (lp.dodgeInsetEdges != Gravity.NO_GRAVITY && child.getVisibility() == View.VISIBLE) {offsetChildByInset(child, inset, layoutDirection);}if (type == EVENT_PRE_DRAW) {// Did it change? if not continuegetLastChildRect(child, lastDrawRect);if (lastDrawRect.equals(drawRect)) {continue;}recordLastChildRect(child, drawRect);}// Update any behavior-dependent views for the changefor (int j = i + 1; j < childCount; j++) {final View checkChild = mDependencySortedChildren.get(j);final LayoutParams checkLp = (LayoutParams) checkChild.getLayoutParams();final Behavior b = checkLp.getBehavior();if (b != null && b.layoutDependsOn(this, checkChild, child)) {if (type == EVENT_PRE_DRAW && checkLp.getChangedAfterNestedScroll()) {// If this is from a pre-draw and we have already been changed// from a nested scroll, skip the dispatch and reset the flagcheckLp.resetChangedAfterNestedScroll();continue;}final boolean handled;switch (type) {case EVENT_VIEW_REMOVED:// EVENT_VIEW_REMOVED means that we need to dispatch// onDependentViewRemoved() insteadb.onDependentViewRemoved(this, checkChild, child);handled = true;break;default:// Otherwise we dispatch onDependentViewChanged()handled = b.onDependentViewChanged(this, checkChild, child);break;}if (type == EVENT_NESTED_SCROLL) {// If this is from a nested scroll, set the flag so that we may skip// any resulting onPreDraw dispatch (if needed)checkLp.setChangedAfterNestedScroll(handled);}}}}releaseTempRect(inset);releaseTempRect(drawRect);releaseTempRect(lastDrawRect);}
我们可以看到文档说明,大概意思是当子view发生变化会调用该方法。该方法会遍历所有的子view,
然后调用如下代码,layoutDependsOn()这个方法是做什么的呢?我们接下来看下该方法。
if (b != null && b.layoutDependsOn(this, checkChild, child)) {if (type == EVENT_PRE_DRAW && checkLp.getChangedAfterNestedScroll()) {// If this is from a pre-draw and we have already been changed// from a nested scroll, skip the dispatch and reset the flagcheckLp.resetChangedAfterNestedScroll();continue;}final boolean handled;switch (type) {case EVENT_VIEW_REMOVED:// EVENT_VIEW_REMOVED means that we need to dispatch// onDependentViewRemoved() insteadb.onDependentViewRemoved(this, checkChild, child);handled = true;break;default:// Otherwise we dispatch onDependentViewChanged()handled = b.onDependentViewChanged(this, checkChild, child);break;}if (type == EVENT_NESTED_SCROLL) {// If this is from a nested scroll, set the flag so that we may skip// any resulting onPreDraw dispatch (if needed)checkLp.setChangedAfterNestedScroll(handled);}}
/*** Determine whether the supplied child view has another specific sibling view as a* layout dependency.**

This method will be called at least once in response to a layout request. If it * returns true for a given child and dependency view pair, the parent CoordinatorLayout * will:

*
  1. *
  2. Always lay out this child after the dependent child is laid out, regardless * of child order.
  3. *
  4. Call {@link #onDependentViewChanged} when the dependency view's layout or * position changes.
  5. *
** @param parent the parent view of the given child* @param child the child view to test* @param dependency the proposed dependency of child* @return true if child's layout depends on the proposed dependency's layout,*         false otherwise** @see #onDependentViewChanged(CoordinatorLayout, android.view.View, android.view.View)*/public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency) {return false;}
这个方法,大概意思是如果我们返回true,说明当前发生变化的子view发生变化时。也就是该方法决定我们用
layout_behavior标识的view是否应该做出相应的变化。默认返回false,该方法需要我们在创建自己的Behavior时重写。
当返回true的话,可以看到会调用
b.onDependentViewRemoved(this, checkChild, child);
handled = b.onDependentViewChanged(this, checkChild, child);为了更好理解这两句代码,我们举个例子,假设有ViewA和ViewB ,当ViewB发生移动时,ViewA要向反方向移动。
1、当ViewB被移除时会调用
b.onDependentViewRemoved(this, checkChild, child);
2、当ViewB发生变化时,会调用
handled = b.onDependentViewChanged(this, checkChild, child);
那么我们就可以在
b.onDependentViewChanged里面写我们的功能代码了。通过以上的分析,希望能帮到大家对CoordinatorLayout的协作调用过程有一些些的帮助。
http://cherylgood.cn/20170302/55
 
 

转载于:https://my.oschina.net/zaizaiangels/blog/849727

Android开发之CoordinatorLayout使用详解一相关推荐

  1. android中oncreate方法,android开发之onCreate( )方法详解

    这里我们只关注一句话:This is where you should do all of your normal static set up.其中我们只关注normal static, normal ...

  2. android开发之onCreate( )方法详解

    android开发之onCreate( )方法详解 onCreate( )方法是android应用程序中最常见的方法之一,那么,我们在使用onCreate()方法的时候应该注意哪些问题呢? 先看看Go ...

  3. Android开发之EditText属性详解+++ImageView的属性

    Button的使用 不要阴影Button ---> TextView   (5.0新特性) <!-- 去按钮立体效果 --> <item name="android: ...

  4. Android 开发之EditText属性详解

    EditText & TextView 属性详解: android:layout_gravity="center_vertical" 设置控件显示的位置:默认top. an ...

  5. android开发之Parcelable使用详解

    想要在两个activity之间传递对象,那么这个对象必须序列化,android中序列化一个对象有两种方式,一种是实现Serializable接口,这个非常简单,只需要声明一下就可以了,不痛不痒.但是a ...

  6. Android快速开发之appBase——(4).详解com.snicesoft.Application和BaseActivity

    转载请注明本文出自JFlex的博客http://blog.csdn.net/jflex/article/details/46441571,请尊重他人的辛勤劳动成果,谢谢! Android快速开发之ap ...

  7. android idata 模式,Android快速开发之appBase——(3).详解IHolder和IData

    Android快速开发之appBase--(3).详解IHolder和IData IHolder和IData是AVLib的两个组件,在前面已经使用过了,那么这一篇将会详细说明这两个组件的用法. IHo ...

  8. iOS开发之Accounts框架详解

    2019独角兽企业重金招聘Python工程师标准>>> iOS开发之Accounts框架详解 Accounts框架是iOS原生提供的一套账户管理框架,其支持Facebook,新浪微博 ...

  9. 安卓开发之IPC机制详解

    IPC(Inter-Process Communication),意为进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程.前面在学习Handler机制时提到过线程与进程的概念,在安卓中一个进 ...

最新文章

  1. CentOS下的Autoconf和AutoMake(实践篇) 2
  2. 电荷泵式开关电源的基本电路
  3. ajax常见问题汇总(二)
  4. vue设置全局变量和修改
  5. bp神经网络预测python代码_机器学习之多层神经网络(附Python代码和数据)
  6. mysql解锁_mysql 解锁
  7. 论文浅尝 | 基于深度强化学习的远程监督数据集的降噪
  8. java 图片组合 分解_切分和组合图片(二)
  9. 织梦熊掌号提交urls.php,织梦熊掌号api自动提交代码
  10. 五分钟深入 Hadoop 内核
  11. 哈尔滨冰景:映衬时代主题
  12. windows 7系统的无损分区软件
  13. 第三方易支付系统源码
  14. Ubuntu完全教程,让你成为Ubuntu高手
  15. C语言pow()函数的运用(x的y次幂)
  16. 心肺运动试验----各类参数分析笔记
  17. Python的学习(十八)---- 单元测试工具nose
  18. 数学建模之倚天剑与屠龙刀
  19. Java JMF 多媒体框架
  20. 引领时代变化的人都是“骗子”

热门文章

  1. 毕业设计:基于Web实现多用户宿舍管理系统
  2. JSP实现停车场收费管理系统
  3. pandas-datareader
  4. Effective C#: Item 1 Always use properties instead of accessible data members
  5. Python:高级主题之(属性取值和赋值过程、属性描述符、装饰器)
  6. ios手势识别-单击
  7. 《LeetCode力扣练习》第121题 买卖股票的最佳时机 Java
  8. 现浇板弹性计算还是塑性计算,板塑性和弹性
  9. python getattr_python __getattr__ 巧妙应用
  10. 通过计算机管理-共享文件夹,通过“计算机管理”管理工具(MMC)管理本机共享资源...