content: package com.jennifer.andy.nestedscrollingdemo.view;
  
  import android.animation.ValueAnimator;
  import android.content.Context;
  import android.support.annotation.NonNull;
  import android.support.annotation.Nullable;
  import android.support.v4.view.NestedScrollingParent;
  import android.support.v4.view.NestedScrollingParentHelper;
  import android.support.v4.view.ViewCompat;
  import android.support.v4.view.ViewPager;
  import android.util.AttributeSet;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.animation.DecelerateInterpolator;
  import android.widget.LinearLayout;
  
  import com.jennifer.andy.nestedscrollingdemo.R;
  
  /**
   * Author:  andy.xwt
   * Date:    2018/8/8 14:28
   * Description:NestedScrolling机制下的嵌套滑动 实现NestedScrollingParent接口
   */
  
  public class NestedScrollingParentLayout extends LinearLayout implements NestedScrollingParent {
  
      private View mTopView;
      private View mNavView;
      private View mViewPager;
      private int mTopViewHeight;
      private ValueAnimator mValueAnimator;
  
      private NestedScrollingParentHelper mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
  
      public NestedScrollingParentLayout(Context context) {
          this(context, null);
      }
  
      public NestedScrollingParentLayout(Context context, @Nullable AttributeSet attrs) {
          this(context, attrs, 0);
      }
  
      public NestedScrollingParentLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
          setOrientation(VERTICAL);
      }
  
  
      @Override
      public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes) {
          return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
      }
  
  
      @Override
      public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes) {
          mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
      }
  
      /**
       * 在嵌套滑动的子View未滑动之前，判断父view是否优先与子view处理(也就是父view可以先消耗，然后给子view消耗）
       *
       * @param target   具体嵌套滑动的那个子类
       * @param dx       水平方向嵌套滑动的子View想要变化的距离
       * @param dy       垂直方向嵌套滑动的子View想要变化的距离 dy<0向下滑动 dy>0 向上滑动
       * @param consumed 这个参数要我们在实现这个函数的时候指定，回头告诉子View当前父View消耗的距离
       *                 consumed[0] 水平消耗的距离，consumed[1] 垂直消耗的距离 好让子view做出相应的调整
       */
      @Override
      public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed) {
          boolean hideTop = dy > 0 && getScrollY() < mTopViewHeight;
          boolean showTop = dy < 0 && getScrollY() >= 0 && !target.canScrollVertically(-1);
          if (hideTop || showTop) {
              scrollBy(0, dy);
              consumed[1] = dy;
          }
      }
  
  
      @Override
      public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
  
      }
  
      @Override
      public boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY) {
          return false;
      }
  
      @Override
      public void onStopNestedScroll(@NonNull View target) {
          mNestedScrollingParentHelper.onStopNestedScroll(target);
      }
  
  
      @Override
      public boolean onNestedFling(@NonNull View target, float velocityX, float velocityY, boolean consumed) {
          final int distance = Math.abs(getScrollY());
          final int duration;
          if (velocityY > 0) {//向上滑
              duration = 3 * Math.round(1000 * (distance / velocityY));
              startAnimation(duration, getScrollY(), mTopViewHeight);
          } else if (velocityY < 0) {//向下滑动
              final float distanceRatio = (float) distance / getHeight();
              duration = (int) ((distanceRatio + 1) * 150);
              startAnimation(duration, getScrollY(), 0);
          }
  
          return true;
      }
  
      @Override
      public int getNestedScrollAxes() {
          return mNestedScrollingParentHelper.getNestedScrollAxes();
      }
  
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          //ViewPager修改后的高度= 总高度-导航栏高度
          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
          ViewGroup.LayoutParams layoutParams = mViewPager.getLayoutParams();
          layoutParams.height = getMeasuredHeight() - mNavView.getMeasuredHeight();
          mViewPager.setLayoutParams(layoutParams);
          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      }
  
      @Override
      protected void onFinishInflate() {
          super.onFinishInflate();
          mTopView = findViewById(R.id.iv_head_image);
          mNavView = findViewById(R.id.tab_layout);
          mViewPager = findViewById(R.id.view_pager);
          if (!(mViewPager instanceof ViewPager)) {
              throw new RuntimeException("id view_pager should be viewpager!");
          }
      }
  
      @Override
      protected void onSizeChanged(int w, int h, int oldw, int oldh) {
          super.onSizeChanged(w, h, oldw, oldh);
          mTopViewHeight = mTopView.getMeasuredHeight();
      }
  
      @Override
      public void scrollTo(int x, int y) {
          if (y < 0) {
              y = 0;
          }
          if (y > mTopViewHeight) {
              y = mTopViewHeight;
          }
          super.scrollTo(x, y);
      }
  
      private void startAnimation(long duration, int startY, int endY) {
          if (mValueAnimator == null) {
              mValueAnimator = new ValueAnimator();
              mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                  @Override
                  public void onAnimationUpdate(ValueAnimator animation) {
                      int animatedValue = (int) animation.getAnimatedValue();
                      scrollTo(0, animatedValue);
                  }
              });
          } else {
              mValueAnimator.cancel();
          }
          mValueAnimator.setInterpolator(new DecelerateInterpolator());
          mValueAnimator.setIntValues(startY, endY);
          mValueAnimator.setDuration(duration);
          mValueAnimator.start();
      }
  
  }
  