CoordinatorLayout与Behavior总结


在项目中遇到了Behavior的使用,觉得很神奇,就记录一下。
Behavior大致介绍是:CoordinatorLayout是用来卸掉其字VIew们之间动作的一个父View,而Behavior就是用来给CoordinatorLayout的子View们实现交互。

  1. Behavior
    在自定义Behaviors的时候,就要熟悉两个元素Childsdeoendency。其中要改变行为的那个View就是child,dependency是作为触发器影响child的那个View。
  2. 创建步骤:
    1. 继承CoordinatorLayout.Behavior<T>,其中T就是child的类型,之后重写layoutDependsOnonDependentVIewChanged。在每次UI变化的时候就会调用layoutDependsOn,鉴定完deoendency后一定要返回true。自动调用的layourDeoendsOn是用来控制child的行为。
 @Override
   public boolean layoutDependsOn(

      CoordinatorLayout parent, 
      CircleImageView, child, 
      View dependency) {

      return dependency instanceof Toolbar; 
  }

layoutDependsOn返回true后就开始调用onDependentViewChanged,在这个方法中我们利用dependency来实现动画,转换,动作。

public boolean onDependentViewChanged(

      CoordinatorLayout parent, 
      CircleImageView avatar, 
      View dependency) {


      modifyAvatarDependingDependencyState(avatar, dependency);
   }

   private void modifyAvatarDependingDependencyState(
    CircleImageView avatar, View dependency) {
        //  avatar.setY(dependency.getY());
        //  avatar.setBlahBlat(dependency.blah / blah);
    }

接下来就实现知乎的效果
单独出场的底栏也可以利用上面一样的方法来设置隐藏或显示,我的底栏是和AppBarLayout一起出场,所以我就让底栏从属于AppBarLayout活动。

public class MyBottomBarBehavior extends CoordinatorLayout.Behavior<View> {

public MyBottomBarBehavior(Context context, AttributeSet attrs) {
    super(context, attrs);
}

//确定所提供的子视图是否有另一个特定的同级视图作为布局从属。
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
//这个方法是说明这个子控件是依赖AppBarLayout的
    return dependency instanceof AppBarLayout;
}

//用于响应从属布局的变化
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {

    float translationY = Math.abs(dependency.getTop());//获取更随布局的顶部位置

    child.setTranslationY(translationY);
    return true;
}

}
  1. FloatingActionButton和底栏上配置的是我们接下来要自定义的Behavior
ublic class ScaleDownShowBehavior extends FloatingActionButton.Behavior {
    /**
     * 退出动画是否正在执行。
     */
    private boolean isAnimatingOut = false;

    private OnStateChangedListener mOnStateChangedListener;

    public ScaleDownShowBehavior(Context context, AttributeSet attrs) {
        super();
    }


//在嵌套滑动开始前回调
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }

//在嵌套滑动进行时,对象消费滚动距离前回调
    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {

//dyConsumed 大于0是向上滚动 小于0是向下滚动
        if (((dyConsumed > 0 && dyUnconsumed == 0) || (dyConsumed == 0 && dyUnconsumed > 0)) && child.getVisibility() != View.VISIBLE) {// 显示
            AnimatorUtil.scaleShow(child, null);
            if (mOnStateChangedListener != null) {
                mOnStateChangedListener.onChanged(false);
            }
        } else if (((dyConsumed < 0 && dyUnconsumed == 0) || (dyConsumed == 0 && dyUnconsumed < 0)) && child.getVisibility() != View.GONE && !isAnimatingOut) {
            AnimatorUtil.scaleHide(child, viewPropertyAnimatorListener);
            if (mOnStateChangedListener != null) {
                mOnStateChangedListener.onChanged(true);
            }
        }
    }

    public void setOnStateChangedListener(OnStateChangedListener mOnStateChangedListener) {
        this.mOnStateChangedListener = mOnStateChangedListener;
    }

    // 外部监听显示和隐藏。
    public interface OnStateChangedListener {
        void onChanged(boolean isShow);
    }

    public static <V extends View> ScaleDownShowBehavior from(V view) {
        ViewGroup.LayoutParams params = view.getLayoutParams();
        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
            throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
        }
        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params).getBehavior();
        if (!(behavior instanceof ScaleDownShowBehavior)) {
            throw new IllegalArgumentException("The view is not associated with ScaleDownShowBehavior");
        }
        return (ScaleDownShowBehavior) behavior;
    }

    private ViewPropertyAnimatorListener viewPropertyAnimatorListener = new ViewPropertyAnimatorListener() {

        @Override
        public void onAnimationStart(View view) {
            isAnimatingOut = true;
        }

        @Override
        public void onAnimationEnd(View view) {
            isAnimatingOut = false;
            view.setVisibility(View.GONE);
        }

        @Override
        public void onAnimationCancel(View arg0) {
            isAnimatingOut = false;
        }
    };
}

我们通过重写Behavior中关于嵌套滑动的两个回调完成了FloatingActionButton的隐藏和显示判断及操作。

参考网站:
1. 一个神奇的控件——Android CoordinatorLayout与Behavior使用指南
字数1108 阅读16186 评论41 喜欢227

2. 关于CoordinatorLayout与Behavior的一点分析
3. CoordinatorLayout 自定义Behavior并不难,由简到难手把手带你撸三款
4. android-[译]掌握CoordinatorLayout
5. 深入理解CoordinatorLayout.Behavior

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值