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

你可能感兴趣的:(behavior)