CoordinatorLayout与Behavior

翻译过来就是协调布局和依赖行为,这两个是内部类关系

在我这里有两种用途:看效果

android协调者布局图片高度不固定 安卓协调布局_android

第一种,两个空间的y坐标形成依赖关系,坐标依赖

第二种,滑动以来关系

上代码:

第一种:

当然了这种效果是基于协调布局开发的,所以布局必须使用协调布局

代码中button添加一个属性layout_behavior就是建立以来关系的属性,MyBehavior这个类是自定义的,这里属性值:自定义的类的包名+类名。

自定义的MyBehavior类:

package com.example.zxq.bsquxian.views;
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
/**
* Created by Administrator on 2017/7/25 0025.
*/
public class MyBehavior extends CoordinatorLayout.Behavior{
public MyBehavior(Context context, AttributeSet attrs)
{
super(context,attrs);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, Button child, View dependency) {
//如果dependency 是 ScrPositionTextView, 就依赖
return dependency instanceof ScrPositionTextView;
}
//每次dependency位置发生变化,都会执行onDependentViewChanged方法
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, Button btn, View dependency) {
//根据dependency的位置,设置Button的位置
int x = 0;
int y = (int) dependency.getY();
setPosition(btn, 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);
}
}在上面的layoutDependsOn方法中判断依赖对象,要依赖到哪个组件上。这里依赖了一个自定义TextView,当然这里也可以通过id判断依赖关系
自定义的TextView:
package com.example.zxq.bsquxian.views;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;
/**
* Created by Administrator on 2017/7/25 0025.
*/
public class ScrPositionTextView extends android.support.v7.widget.AppCompatTextView {
private int startx;
private int starty;
public ScrPositionTextView(Context context) {
super(context);
}
public ScrPositionTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public ScrPositionTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
startx= (int) event.getRawX();
starty= (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int lastX= (int) event.getRawX();
int lastY= (int) event.getRawY();
int movex= lastX-startx;
int movey= lastY-starty;
startx= lastX;
starty= lastY;
CoordinatorLayout.MarginLayoutParams layoutParams= (CoordinatorLayout.MarginLayoutParams) getLayoutParams();
int left = layoutParams.leftMargin+movex;
int top = layoutParams.topMargin+movey;
layoutParams.leftMargin=left;
layoutParams.topMargin=top;
setLayoutParams(layoutParams);
requestFocus();
break;
}
return true;
}

}这里动态改变textview的位置就ok,自己的y坐标会自动关联到那个button上去的。

第二种代码:

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

自定义的Behavior:这里需要重写以下几个方法

package com.example.zxq.bsquxian.views;
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by Administrator on 2017/7/27 0027.
*/
public class ScrollBehavior extends CoordinatorLayout.Behavior {
int offsetTotal = 0;
boolean scrolling = false;
public ScrollBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@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) {
//进行滑动事件处理
offset(child,dyConsumed);
}
@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);
}
@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);
}
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;
}
}

布局文件;

注意被依赖的View只有实现了NestedScrollingChild接口的才可以将事件传递给CoordinatorLayout。

但注意这个滑动事件是对于CoordinatorLayout的。所以只要CoordinatorLayout有NestedScrollingChild就会滑动,他滑动就会触发这几个回调。无论你是否依赖了那个View。

Imageview设置关联属性

有关自己的事件处理可以在这2个回调与View中的事件分发是一样的。所有Behavior能在子View之前收到CoordinatorLayout的所有触摸事件。可以进行拦截,如果拦截事件将不会流经子View。因为这2个方法都是在CoordinatorLayout的 回调中

其实之前讲的AppBarLayout效果也是这个原理:

AppBarLayout自带一个Behivior。直接在源码里注解声明的。这个Behivior也只能用于AppBarLayout。

作用是让他根据CoordinatorLayout上的滚动手势进行一些效果(比如收缩)。与ScrollingViewBehavior是无关的,加不加ScrollingViewBehavior不影响收缩。

只不过只有某些可滑动View才会把滑动事件响应给CoordinatorLayout才能继而响应给AppBarLayout。