android material design 学习

CoordinatorLayout super-powered FrameLayout

CoordinatorLayout是新推出的布局ViewGroup类,主要是作为协调布局,核心是协调子View的滑动动画,也就是Behaviors类的使用,通过Behaviors来调度子View.Behavior是CoordinatorLayout的子抽象类,代码如下:
CoordinatorLayout$Behavior

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public static abstract class Behavior<V extends View>{
public Behavior(){}
public Behavior(Context context,AttributeSet attrs){}
public boolean OnInterceptTouchEvent(CoordinatorLayout parent,V child, MotionEvent ev){}
return false;
}
public boolean onTouchEvent(CoordinatorLayout parent,V child,MotionEvent ev){
return false;
}
public int getScrimColor(CoordinatorLayout parent, V child) {
return Color.BLACK;
}
public float getScrimOpacity(CoordinatorLayout parent, V child) {
return 0.f;
}
public boolean blocksInteractionBelow(CoordinatorLayout parent, V child) {
return getScrimOpacity(parent, child) > 0.f;
}
public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency) {
return false;
}
public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) {
return false;
}
public void onDependentViewRemoved(CoordinatorLayout parent, V child, View dependency) {
}
public boolean isDirty(CoordinatorLayout parent, V child) {
return false;
}
public boolean onMeasureChild(CoordinatorLayout parent, V child,
int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed)
{

return false;
}
public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
return false;
}
public static void setTag(View child, Object tag) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
lp.mBehaviorTag = tag;
}
public static Object getTag(View child) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
return lp.mBehaviorTag;
}
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,
V child, View directTargetChild, View target, int nestedScrollAxes)
{

return false;
}
public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, V child,
View directTargetChild, View target, int nestedScrollAxes)
{

// Do nothing
}
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
// Do nothing
}
public void onNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target,
int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)
{

// Do nothing
}
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target,
int dx, int dy, int[] consumed)
{

// Do nothing
}
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, V child, View target,
float velocityX, float velocityY, boolean consumed)
{

return false;
}
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target,
float velocityX, float velocityY)
{

return false;
}
public WindowInsetsCompat onApplyWindowInsets(CoordinatorLayout coordinatorLayout,
V child, WindowInsetsCompat insets)
{

return insets;
}
public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
// no-op
}
public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
return BaseSavedState.EMPTY_STATE;
}

Behavior就是CoordinatorLayout用来与各个子View通信用的代理类,CoordinatorLayout通过Behavior去控制子视图,也代表behavior的数据传导基本上是单向的.
picture
查看CoordinatorLayout的源码,当CoordinatorLayout进行measure,layout的时候,会调用相关子视图behavior的OnMeasureChild和OnLayoutChild方法.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
...
final Behavior b = lp.getBehavior();
if (b == null || !b.onMeasureChild(this, child, childWidthMeasureSpec, keylineWidthUsed,
childHeightMeasureSpec, 0)) {
onMeasureChild(child, childWidthMeasureSpec, keylineWidthUsed,
childHeightMeasureSpec, 0);
}
...
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int layoutDirection = ViewCompat.getLayoutDirection(this);
final int childCount = mDependencySortedChildren.size();
for (int i = 0; i < childCount; i++) {
final View child = mDependencySortedChildren.get(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final Behavior behavior = lp.getBehavior();

if (behavior == null || !behavior.onLayoutChild(this, child, layoutDirection)) {
onLayoutChild(child, layoutDirection);
}
}
}

但CoordinatorLayout控制Behavior的关键,主要是两个触摸时间:
1.OnInterceptTouchEvent
2.OnTouchEvent
而CoordinatorLayout对触摸事件的处理,是通过NestedScrollingParent接口,NestedScrollingParent与NestedScrollingChild接口协同调用,所以CoordinatorLayout的子视图一定要实现NestedScrollingChild才可以很好的发挥CoordinatorLayout的作用.CoordinatorLayout从NestedScrollingParent相关接口获取嵌套滚动的相关参数,再通过Behavior传到各个子视图中,包含Behavior的View处理相关滚动操作,消费一些参数后再把消费掉的数值传回发生触摸事件的View中,达到交互的目的.
picture

文章目录
  1. 1. CoordinatorLayout super-powered FrameLayout
,