2. Behavior如何进行代理的
我们按照以下三种情况分析如何用Behavior进行代理的:
2.1 子view依赖子view状态变化
2.2 嵌套滑动
2.3 Behavior拦截一切事件
具体调用Behavior的方法对应如下:
2.1
public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency) {
return false;
}
public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) {
return false;
}
2.2
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,
V child, View directTargetChild, View target, int nestedScrollAxes) {
return false;
}
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;
}
2.3
public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
return false;
}
public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
return false;
}
2.1 layoutDependsOn和OndependentViewChanged调用过程
一个view随着另一个view的拖动向反方向移动这种效果,是通过重写Behavior的下面两个方法实现的:
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof TempView;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
int top = dependency.getTop();
int left = dependency.getLeft();
int x = width - left - child.getWidth();
int y = top;
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);
}
那我看下为什么实现layoutDependsOn和OndependentViewChanged是怎么被调用的:
View.measure
CoordinatorLayout.onMeasure
CoordinatorLayout.ensurePreDrawListener
CoordinatorLayout.hasDependencies
CoordinatorLayout.addPreDrawListener
CoordinatorLayout.dispatchOnDependentViewChanged
CoordinatorLayout$LayoutParams.dependsOn
Dependent2Behavior.layoutDependsOn
我们详细看下dispatchOnDependentViewChanged方法:
void dispatchOnDependentViewChanged(final boolean fromNestedScroll) {
...
// Update any behavior-dependent views for the change
for (int j = i + 1; j < childCount; j++) {
....
if (b != null && b.layoutDependsOn(this, checkChild, child)) {
...
final boolean handled = b.onDependentViewChanged(this, checkChild, child);
....
}
}
}
每次重绘时,dispatchOnDependentViewChanged会判断是否依赖,如果依赖,就去根据自己的需要,对child进行移动或者其他处理。
2.2 onStartNestedScroll和onNestedPreScroll实现原理
父view嵌套子view滑动,上滑时,先滑动父view,子view随着动,向下滑动时,先滑动子view,再滑动父view这种效果的实现,是嵌套滑动,通过重写Behavior的下面的方法实现:
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return true;
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
offset(child, dyConsumed);
}
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;
}
为了方便理解,我们全面理解一下嵌套滑动机制(NestedScroll)。