转载请注明出处 http://blog.csdn.net/u011453163/article/details/54405499
CoordinatorLayout是android.support.design的一个新的布局,很适合用来实现一些嵌套滚动之类的布局
依赖包 compile ‘com.android.support:design:25.0.1’
CoordinatorLayout协调布局,CoordinatorLayout可以非常方便的管理其内部子view的行为,之所以能非常方便的管理其内部子view的行为离不开CoordinatorLayout.Behavior,Behavior是CoordinatorLayout的一个内部抽象类,CoordinatorLayout内部的子view之间的协作关系都是通过Behavior来处理的。
绑定Behevior有两种方法
xml布局文件里直接绑定
<Button
android:id="@+id/bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_behavior="com.example.admin.myapplication.TestBehavior"
android:text="滚动"
/>
代码动态绑定
bt= (Button) findViewById(R.id.bt);
CoordinatorLayout.LayoutParams layoutParams= (CoordinatorLayout.LayoutParams) bt.getLayoutParams();
layoutParams.setBehavior(new TestBehavior(this,null));
源码执行流程
涉及到的滚动操作都是通过嵌套滚动机制执行的 涉及到嵌套机制的几个类。
NestedScrollingChildHelper
NestedScrollingChild
NestedScrollingParentHelper
NestedScrollingParent
关于嵌套滑动机制 可以参考下我的另一篇博客
http://blog.csdn.net/u011453163/article/details/52751110
CoordinatorLayout协调内部子view的行为也是借助嵌套滚动机制的。分析滚动的流程
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
int xConsumed = 0;
int yConsumed = 0;
boolean accepted = false;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (!lp.isNestedScrollAccepted()) {
continue;
}
final Behavior viewBehavior = lp.getBehavior();
if (viewBehavior != null) {
mTempIntPair[0] = mTempIntPair[1] = 0;
viewBehavior.onNestedPreScroll(this, view, target, dx, dy, mTempIntPair);
xConsumed = dx > 0 ? Math.max(xConsumed, mTempIntPair[0])
: Math.min(xConsumed, mTempIntPair[0]);
yConsumed = dy > 0 ? Math.max(yConsumed, mTempIntPair[1])
: Math.min(yConsumed, mTempIntPair[1]);
accepted = true;
}
}
consumed[0] = xConsumed;
consumed[1] = yConsumed;
if (accepted) {
onChildViewsChanged(EVENT_NESTED_SCROLL);
}
}
核心代码 也是CoordinatorLayout和Behavior的关系,调用同名方法。
final Behavior viewBehavior = lp.getBehavior();
if (viewBehavior != null) {
mTempIntPair[0] = mTempIntPair[1] = 0;
viewBehavior.onNestedPreScroll(this, view, target, dx, dy, mTempIntPair);
xConsumed = dx > 0 ? Math.max(xConsumed, mTempIntPair[0])
: Math.min(xConsumed, mTempIntPair[0]);
yConsumed = dy > 0 ? Math.max(yConsumed, mTempIntPair[1])
: Math.min(yConsumed, mTempIntPair[1]);
accepted = true;
}
我们来简单的自定义一个Behavior 粗糙的举个例子 只证实事件的传递
public class TestBehavior extends CoordinatorLayout.Behavior<View> {
public TestBehavior() {
}
public TestBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return true;
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
child.setX(dx);
child.setY(dy);
}
}
如果是在布局文件中绑定的话 必须重写构造函数
public TestBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
如果动态绑定可以不重写构造函数
自定义的Behavior很简单是实现了 单A view 移动的时候 B view也跟着移动。
然后是自定义一个view 从最原始的滚动开始,其实google已经有相应的捆绑方法了,这个我打算在下一篇文章探究一下。
public class TestView extends View implements NestedScrollingChild{
private NestedScrollingChildHelper nestedScrollingChildHelper;
public TestView(Context context) {
this(context,null);
}
public TestView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
nestedScrollingChildHelper=new NestedScrollingChildHelper(this);
nestedScrollingChildHelper.setNestedScrollingEnabled(true);
}
private int fx;
private int fy;
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){
nestedScrollingChildHelper.startNestedScroll(1);
fx= (int) event.getRawX();
fy= (int) event.getRawY();
}
if (event.getAction()==MotionEvent.ACTION_MOVE){
nestedScrollingChildHelper.dispatchNestedPreScroll((int)event.getRawX()-fx,(int)event.getRawY()-fy,null,null);
this.setX((int)event.getRawX()-this.getWidth()/2);
this.setY((int)event.getRawY()-this.getHeight()/2);
}
return true;
}
}
一个简单的view 通过实现NestedScrollingChild接口 把自己的滑动事件上报给父view,然后父view再做一个派发。
最后的效果是这样的
关于CoordinatorLayout和CoordinatorLayout.Behavior 的一些事件派遣分析就到此结束。
欢迎指正。