转发请备注原文地址:https://www.niwoxuexi.com/blog/android/article/191.html
我在找了一些关于CoordinatorLayout
的教程,大部分文章都是讲解把CoordinatorLayout, AppbarLayout ,CollapsingToolbarLayout以及Toolbar 等缓和一起使用,这很容易是大家混淆,不知道如何利用CoordinatorLayout使用到不同的场景中。其实CoordinatorLayout的功能并不是局限于与AppBarLayout一起使用,它的功能非常强大,本文将针对CoordinatorLayout的使用进行详细介绍,在后面再介绍将AppBarLayout和CollapsingToolBarLayout整合CoordinatorLayout一起。那么到底CoordinatorLayout是如何使用的呢,那就听我细细道来吧~
CoordinatorLayout 到底是什么,能干什么?
先看一下官方的描述吧:
CoordinatorLayout is a super-powered FrameLayout
.
CoordinatorLayout is intended for two primary use cases:
- As a top-level application decor or chrome layout
- As a container for a specific interaction with one or more child views
简单的说CoordinatorLayout是一个超级的FrameLayout 布局,它的作用是帮助我们协调它的个个子View的布局,我们先看一个案例动画组:
稍微解释一下这个动画:小面的绿色小球是一个普通的View,上面的飞机是一个ImageView ,我们水平拖动小球,飞机向相反的方向运动;垂直方向拖动小球会跟着相
同的方向运动;
简而言之:水平方向反向运动,垂直方向同向运动;
这个例子就是运用CoordinatorLayout实现的,当然让你不用CoordinatorLayout
去实现,应该没有任何问题,但是代码的耦合度应该非常大,你的代码必须要持有
2个View
的引用,然后在<code>onTouchEvent里面做各种判断和逻辑处理,这耦合度未免太伤人伤力了~
而CoordinatorLayout
既然号称能帮我们协调子View的布局,我们接下来看看<code>CoordinatorLayout如何实现~
CoordinatorLayout 的使用
CoordinatorLayout的使用核心是Behavior,Behavior就是执行你定制的动作。
看先Behavior的官方解释吧:
Interaction behavior plugin for child views of CoordinatorLayout.
翻译:Behavior就是用来给CoordinatorLayout的子view们实现交互的。
在讲Behavior之前必须先理解两个概念:Child和Dependency,什么意思呢?Child当然是子View的意思了,是谁的子View呢,当然是CoordinatorLayout的子View;其实Child是指要执行动作的CoordinatorLayout的子View。而Dependency是指Child依赖的View。比如上面的gif图中,绿色的小球的View就是Dependency,上面的小飞机的ImgeView就是Child,上面小飞机的动作是依赖下面的绿色的View。简而言之,就是如过Dependency这个View发生了变化,那么Child这个View就要相应发生变化。发生变化是具体发生什么变化呢?这里就要引入Behavior,Child发生变化的具体执行的代码都是放在Behavior这个类里面。怎么使用Behavior呢,首先,我们定义一个类,继承CoordinatorLayout.Behavior<T>,其中,泛型参数T是我们要执行动作的View类,也就是Child。然后就是去实现
Behavior的两个方法:
/** * 判断child的布局是否依赖dependency */ @Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { //返回false表示child不依赖dependency,ture表示依赖 return true; } /** * 当dependency发生改变时(位置、宽高等),执行这个函数 * 返回true表示child的位置或者是宽高要发生改变,否则就返回false */ @Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { //根据dependency的位置,设置child的位置 return true; }
看了上面的概念后,我们看看具体怎么去实现吧~
为了响应跟随手指移动的操作,我们定义一个非常简单的View,这个View只响应跟随手指移动,将这个View作为Dependency。由于过于简单,这个View源码不粘贴,我们只需知道这个View的类名叫:DependentView。
先看一下:Behavior的实现:
package com.niwoxuexi.coordinatelayout; import android.content.Context; import android.support.design.widget.CoordinatorLayout; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.View; /** * Created by zhuxiaocheng on 2017/7/6. */ public class MyBehavior extends CoordinatorLayout.Behavior { private int screenWidth; public MyBehavior(Context context, AttributeSet attrs) { super(context, attrs); DisplayMetrics display = context.getResources().getDisplayMetrics(); screenWidth = display.widthPixels; } /** * 判断child的布局是否依赖dependency */ @Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { //返回false表示child不依赖dependency,ture表示依赖 return true; } /** * 当dependency发生改变时(位置、宽高等),执行这个函数 * 返回true表示child的位置或者是宽高要发生改变,否则就返回false */ @Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { //根据dependency的位置,设置child的位置 int top = dependency.getTop(); int left = dependency.getLeft(); int x = screenWidth - left - child.getWidth(); int y = top - 800; setPosition(child, x, y); return true; } private void setPosition(View v, int x, int y) { CoordinatorLayout.MarginLayoutParams layoutParams = (CoordinatorLayout.MarginLayoutParams) v.getLayoutParams(); layoutParams.leftMargin = x; layoutParams.topMargin = y; v.setLayoutParams(layoutParams); } }
再看一下DependentView的实现:
package com.niwoxuexi.coordinatelayout; import android.content.Context; import android.support.design.widget.CoordinatorLayout; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.View; /** * Created by zhuxiaocheng on 2017/7/6. */ public class MyBehavior extends CoordinatorLayout.Behavior { private int screenWidth; public MyBehavior(Context context, AttributeSet attrs) { super(context, attrs); DisplayMetrics display = context.getResources().getDisplayMetrics(); screenWidth = display.widthPixels; } /** * 判断child的布局是否依赖dependency */ @Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { //返回false表示child不依赖dependency,ture表示依赖 return true; } /** * 当dependency发生改变时(位置、宽高等),执行这个函数 * 返回true表示child的位置或者是宽高要发生改变,否则就返回false */ @Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { //根据dependency的位置,设置child的位置 int top = dependency.getTop(); int left = dependency.getLeft(); int x = screenWidth - left - child.getWidth(); int y = top - 800; setPosition(child, x, y); return true; } private void setPosition(View v, int x, int y) { CoordinatorLayout.MarginLayoutParams layoutParams = (CoordinatorLayout.MarginLayoutParams) v.getLayoutParams(); layoutParams.leftMargin = x; layoutParams.topMargin = y; v.setLayoutParams(layoutParams); } }
OK,现在我们有了Dependency 的控件DependentView,并且定义好了跟随Dependency一直变化的动作(Behavior)MyBehavior,接下来我们就要指定好为哪个具体的ImageView实例来绑定这些。
方法灰常简单,直接布局文件指定就好:
app:layout_behavior="com.niwoxuexi.coordinatelayout.MyBehavior"
直接上代码,大家自己体会吧
<?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.niwoxuexi.coordinatelayout.MainActivity"> <ImageView android:layout_width="50dp" android:layout_height="50dp" android:src="@drawable/plane" android:scaleType="fitCenter" android:layout_marginLeft="180dp" android:layout_marginTop="100dp" app:layout_behavior="com.niwoxuexi.coordinatelayout.MyBehavior" /> <com.niwoxuexi.coordinatelayout.DependentView android:layout_width="50dp" android:layout_height="50dp" android:background="@drawable/button" android:layout_marginLeft="180dp" android:layout_marginTop="460dp" /> </android.support.design.widget.CoordinatorLayout>
是不是很简单呢?我们只需关注Behavior的编写就好了,把Child和Dependency之间的在xml文件中设置就可以了~
最后是上代码时间喽:https://image.niwoxuexi.com/blog/downloadCoordinateLayout.zip