android.support.design库组件(CoordinatorLayout和CoordinatorLayout.Behavior)

转载请注明出处 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 的一些事件派遣分析就到此结束。

欢迎指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值