您当前的位置: 首页 > 
  • 0浏览

    0关注

    674博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

仿CoordinatorLayout原理完成Behavior事件转发

沙漠一只雕得儿得儿 发布时间:2020-05-03 19:19:59 ,浏览量:0

CoordinatorLayout 作用:
  1. 协调其子view们之间动作的一个父view,作为顶层应用的装饰; 
  2. 作为一个能响应特定的一个或多个子视图交互的容器。
  1. CoordinatorLayout须作为顶层父View
  2. 子View想要与CoordinatorLayout实现"联动性"效果的首要条件是这个View必须实现了NestedScrollingChild接口 RecyclerView,NestedScrollView等新的控件都实现这个接口,ListView这些旧的控件就无法使用了.
  3. 只有CoordinatorLayout的直接子View才会有效果,子View的子View无效
Behavior作用:

Behavior用于当前控件的父控件CoordinatorLayout中的其他子控件的关系,Behavior作为一个中间者,目的是协调子控件之间的触摸事件

  1. 使用Behavior的控件必须是直接从属于CoordinatorLayout,否者无效
  2. 自定义Behavior的时候必须覆盖下面的构造方法,因为通过反射实例化的时候用的就是该构造方法.

我们今天并不是学习如何使用CoordinatorLayout 这个组件,而是仿照这个组件的事件转发原理完成一个自定义的CoordinatorLayout ,完成和原版CoordinatorLayout 一样的效果,旨在学习其原理,真正在项目中使用还是用原版的CoordinatorLayout 即可。

下面来看下完成后的整体效果,项目完整地址:https://github.com/buder-cp/CustomView/tree/master/buder_DN_view/buderdn16

根据手指滑动距离,完成显示隐藏图片以及透明度的设置

获取自定义属性:

我们自定义的BehaviorCoordinatorLayout,首先仿照CoordinatorLayout封装LayoutParams以及使用反射获取自定义属性的代码:

 public static class LayoutParams extends RelativeLayout.LayoutParams {
        private static final String TAG = "touch";
        private Behavior behavior;

        public Behavior getBehavior() {
            return behavior;
        }

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);

            final TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.BeaviorCoordinatorLayout);
            behavior = parseBehavior(c, attrs, a.getString(R.styleable.BeaviorCoordinatorLayout_layout_behavior));
            Log.i(TAG, "LayoutParams:   名字   " + a.getString(R.styleable.BeaviorCoordinatorLayout_layout_behavior));
            a.recycle();

        }

        private Behavior parseBehavior(Context context, AttributeSet attrs, String name) {

            if (TextUtils.isEmpty(name)) {
                return null;
            }
            try {
                final Class clazz = Class.forName(name, true, context.getClassLoader());
                Constructor c = clazz.getConstructor(new Class[]{Context.class, AttributeSet.class});
                c.setAccessible(true);
                return (Behavior) c.newInstance(context, attrs);
            } catch (Exception e) {
                throw new RuntimeException("Could not inflate Behavior subclass " + name, e);
            }
        }

        public LayoutParams(int w, int h) {
            super(w, h);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }


    }
完成事件转发:

获取到Behavior之后,就需要完成事件的转发,例如我们需要监听滑动事件onNestedScroll,就需要我们将该事件进行转发到Behavior中去,

    /**
     * 最重要
     * // 参数target:同上
     * // 参数dxConsumed:表示target已经消费的x方向的距离
     * // 参数dyConsumed:表示target已经消费的y方向的距离
     * // 参数dxUnconsumed:表示x方向剩下的滑动距离
     * // 参数dyUnconsumed:表示y方向剩下的滑动距离
     */
    @Override
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            LayoutParams param = (LayoutParams) child.getLayoutParams();
            if (param.getBehavior() != null) {
                param.getBehavior().onNestedScroll(target, child, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
            }
        }

    }

这里需要注意的是需要实现onStartNestedScroll这个方法,否则无法将滑动事件转发到Behavior中:

    /**
     * ----------------滚动事件------------------move------------
     * move 肯定是拿不到
     * 一定返回 true
     * 实现了  NestedScrolling机制 的 滚动控件
     */

    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        return true;
    }

最后就是在需要监听滑动事件的地方完成具体业务逻辑即可,例如我们的ImageBehavior中需要根据上下的滑动距离进行图片露出高度的设置,在ToolBarBehavior中则改变透明度即可:

ToolBarBehavior完成透明度变化的设置:
public class ToolBarBehavior extends Behavior {
    private int maxHeight = 400;

    public ToolBarBehavior(Context context, AttributeSet set) {
        super(context, set);
    }

    /**
     * 进行透明度吧变换
     */
    @Override
    public void onNestedScroll(View scrollView, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(scrollView, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        if (scrollView.getScrollY()  0) {
            ViewGroup.LayoutParams parmas = target.getLayoutParams();
            Log.i(TAG, "onNestedScroll: parmas.height  " + parmas.height + "  originHeight  " + originHeight);
            parmas.height = parmas.height - Math.abs(dyConsumed);
            if (parmas.height < originHeight) {
                parmas.height = originHeight;
            }
            target.setLayoutParams(parmas);
        } else if (scrollView.getScrollY() == 0) {
            ViewGroup.LayoutParams params = target.getLayoutParams();
            params.height = params.height + Math.abs(dyUnconsumed);
            if (params.height >= maxHeight) {
                params.height = maxHeight;
            }
            target.setLayoutParams(params);
        }
    }
}

 

关注
打赏
1657159701
查看更多评论
立即登录/注册

微信扫码登录

0.0393s