美文网首页
nestedscrollparent/children

nestedscrollparent/children

作者: 细雨么么 | 来源:发表于2019-07-30 16:16 被阅读0次
    package com.vortex.scrolltest;
    
    import android.content.Context;
    import android.support.annotation.Nullable;
    import android.support.v4.view.NestedScrollingParent;
    import android.support.v4.view.NestedScrollingParentHelper;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.VelocityTracker;
    import android.view.View;
    import android.view.ViewTreeObserver;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.OverScroller;
    import android.widget.TextView;
    
    /**
     * Created by Administrator (chenPS) on 2019/7/29.
     */
    
    public class MyNestedScrollParent extends LinearLayout implements NestedScrollingParent {
        private ImageView iv;
        private TextView tv;
        private MyNestedScrollChild mMyNestedScrollChild;
    
        private NestedScrollingParentHelper mParentHelper;
        private OverScroller mScroller;
    
        private int ivHeight;
        private int tvHeight;
    
        public MyNestedScrollParent(Context context) {
            super(context);
        }
    
        public MyNestedScrollParent(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            mParentHelper = new NestedScrollingParentHelper(this);
            mScroller = new OverScroller(context);
        }
    
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            iv = (ImageView) getChildAt(0);
            tv = (TextView) getChildAt(1);
            mMyNestedScrollChild = (MyNestedScrollChild) getChildAt(2);
            iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (ivHeight <= 0) {
                        ivHeight = iv.getMeasuredHeight();
                    }
                }
            });
            tv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (tvHeight <= 0) {
                        tvHeight = tv.getMeasuredHeight();
                    }
                }
            });
        }
    
        /**
         *
         * @param dy  滚动距离 大于0 是网上滚   逐渐显示图片
         * @return  getscrollY的值是逐渐减小的。一旦为0说明滑到顶部了
         */
        private boolean showIv(int dy) {
            if (dy > 0) {
                Log.v("test",getScrollY()+"   showIv");
                if (getScrollY() > 0 && mMyNestedScrollChild.getScrollY() == 0) {
                    return true;
                }
            }
            return false;
        }
        /**
         *
         * @param dy  滚动距离 小于0 是向下滑滚 逐渐隐藏图片
         * @return  getscrollY是父的滑动距离  一旦滑动到iv的高度  说明 已经完全不见了,就不需要在滑动父布局了
         * getscrolly 的值是逐渐增大的
         */
        private boolean hideIv(int dy) {
            if (dy < 0) {
                Log.v("test",getScrollY()+"   showIv");
                if (getScrollY() < ivHeight) {
                    return true;
                }
            }
            return false;
        }
    
    
        @Override
        public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
            if (target instanceof MyNestedScrollChild) {
                return true;
            }
            return false;
        }
    
        private void fling(int velocityY) {
            mScroller.fling(0, getScrollY(), 0, velocityY, 0, 0, 0, ivHeight);
            invalidate();
        }
    
        @Override
        public void onNestedScrollAccepted(View child, View target, int axes) {
            mParentHelper.onNestedScrollAccepted(child, target, axes);
        }
    
        @Override
        public void onStopNestedScroll(View child) {
            mParentHelper.onStopNestedScroll(child);
        }
    
        //先与 child 滚动
    
        /**
         *  在显示 隐藏图片的过程中  也代表这个时候 需要显示 /隐藏的是 父布局的移动效果
         *  不需要去操纵 子布局的滑动
         *  下滑 dy小于0  上滑dy大于0
         */
        @Override
        public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
            if (showIv(dy) || hideIv(dy)) {
                Log.v("test", "onNestedPreScroll  先于child滚动" + dy);
                scrollBy(0, -dy);
                consumed[1] = dy;
            }
        }
    
        // child滚动后
        @Override
        public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
            Log.d("test","onNestedScroll"+dyUnconsumed);
            if (dyUnconsumed > 0) {
                scrollBy(0, -dyUnconsumed);
            }
        }
    
        @Override
        public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
            if (getScrollY() >= 0 && getScrollY() < ivHeight) {
                fling((int) velocityY);
                return true;
            }
            return false;
        }
    
        @Override
        public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
            if (!consumed) {
                fling((int) velocityX);
                return true;
            }
            return false;
        }
    
        @Override
        public int getNestedScrollAxes() {
            return mParentHelper.getNestedScrollAxes();
        }
    
        @Override
        public void scrollTo(int x, int y) {
            if (y < 0) {
                y = 0;
            }
            if (y > ivHeight) {
                y = ivHeight;
            }
    
            super.scrollTo(x, y);
        }
    
        @Override
        public void computeScroll() {
            super.computeScroll();
            if (mScroller.computeScrollOffset()) {
                scrollTo(0, mScroller.getCurrY());
                postInvalidate();
            }
        }
    
    
        private int lastY;
        private VelocityTracker mVelocityTracker;
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (mVelocityTracker == null) {
                mVelocityTracker = VelocityTracker.obtain();
            }
            mVelocityTracker.addMovement(event);
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    lastY = (int) event.getRawY();
                    if (!mScroller.isFinished()) {
                        mScroller.abortAnimation();
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    int y = (int) event.getRawY();
                    int dy = y - lastY;
                    lastY = y;
                    scrollTo(0, -dy);
                    break;
                case MotionEvent.ACTION_UP:
                    mVelocityTracker.computeCurrentVelocity(1000);
                    int vy = (int) mVelocityTracker.getYVelocity();
                    fling(-vy);
                    break;
            }
    
    
            return true;
        }
    }
    
    package com.vortex.scrolltest;
    
    import android.content.Context;
    import android.support.annotation.Nullable;
    import android.support.v4.view.NestedScrollingChild;
    import android.support.v4.view.NestedScrollingChildHelper;
    import android.support.v4.view.ViewCompat;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.VelocityTracker;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.LinearLayout;
    import android.widget.OverScroller;
    
    /**
     * Created by Administrator (chenPS) on 2019/7/29.
     */
    
    public class MyNestedScrollChild extends LinearLayout implements NestedScrollingChild {
    
        private NestedScrollingChildHelper mChildHelper;
        private OverScroller mScroller;
        private int maxScrollY;
        private VelocityTracker mVelocityTracker;
        private int lastY;
        private final int[] offset = new int[2]; //偏移量
        private final int[] consumed = new int[2]; //消费
    
        public MyNestedScrollChild(Context context) {
            super(context);
        }
    
        public MyNestedScrollChild(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            mChildHelper = new NestedScrollingChildHelper(this);
            setNestedScrollingEnabled(true);
            mScroller = new OverScroller(context);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int contentHeight = 0;
            for (int i = 0; i < getChildCount(); i++) {
                View view = getChildAt(i);
                measureChild(view, widthMeasureSpec, heightMeasureSpec);
                contentHeight += view.getMeasuredHeight();
            }
            int parentHeight = ((ViewGroup) getParent()).getMeasuredHeight();
            int pinTopHeight = (int) (getResources().getDisplayMetrics().density * 50 + 0.5); //50dp转 对应的像素  固定头的高度
            int visibleHieght = parentHeight - pinTopHeight;
            maxScrollY = contentHeight - visibleHieght;
            setMeasuredDimension(getMeasuredWidth(), visibleHieght);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            if (mVelocityTracker == null) {
                mVelocityTracker = VelocityTracker.obtain();
            }
            mVelocityTracker.addMovement(event);
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    lastY = (int) event.getRawY();
                    if (!mScroller.isFinished()) {
                        mScroller.abortAnimation();
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    int y = (int) event.getRawY();
                    int dy = y - lastY;
                    lastY = y;
    
                    /**
                     *  public boolean startNestedScroll(int axes);
    
                       开启嵌套滚动流程(实际上是进行了一些嵌套滚动前准备工作)。
                       当找到了能够配合当前子view进行嵌套滚动的父view时,返回值为true
                     (Returns:true if a cooperative parent was found and nested scrolling
                     has been enabled for the current gesture)。
    
                       public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);
    
                       在子view自己进行滚动之前调用此方法,询问父view是否要在子view之前进行滚动。
                       此方法的前两个参数用于告诉父View此次要滚动的距离;而第三第四个参数用于子view获取父view消费掉的距离和父view位置的偏移量。
                       第一第二个参数为输入参数,即常规的函数参数,调用函数的时候我们需要为其传递确切的值。而第三第四个参数为输出参数,调用函数时我们只需要传递容器(在这里就是两个数组),在调用结束后,我们就可以从容器中获取函数输出的值。
                       如果parent消费了一部分或全部距离,则此方法返回true。
                     */
                    if (startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL) &&   //找到了配合滑动的父view
                            dispatchNestedPreScroll(0, dy, consumed, offset)) {  //父类消费距离
    
                        /**
                         * 猜测下 这两个数组 第一位表示 x 第二位表示y值
                         */
    
                        int remain = dy - consumed[1];
    
                        if (remain != 0) {
                            scrollBy(0, -remain);
                        }
                    } else {
                        scrollBy(0, -dy);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    mVelocityTracker.computeCurrentVelocity(1000);
                    float vy = mVelocityTracker.getYVelocity();
                    if (!dispatchNestedPreFling(0, -vy)) { // 如果父类没有消费滑动事件  自己滑动
                        fling(-vy);
                    }
                    break;
    
            }
            return true;
        }
    
        private void fling(float velocityY) {
            mScroller.fling(0, getScrollY(), 0, (int) velocityY, 0, 0, 0, maxScrollY);
            invalidate();
        }
    
        @Override
        public void scrollTo(int x, int y) {
            if (y > maxScrollY) {
                y = maxScrollY;
            }
            if (y < 0) {
                y = 0;
            }
            super.scrollTo(x, y);
        }
    
        @Override
        public void computeScroll() {
            super.computeScroll();
            if (mScroller.computeScrollOffset()) {  //如果还在滑动
                scrollTo(0, mScroller.getCurrY());
                postInvalidate();
            }
        }
    
        @Override
        public void setNestedScrollingEnabled(boolean enabled) {
            mChildHelper.setNestedScrollingEnabled(enabled);
        }
    
        @Override
        public boolean isNestedScrollingEnabled() {
            return mChildHelper.isNestedScrollingEnabled();
        }
    
        @Override
        public boolean startNestedScroll(int axes) {
            return mChildHelper.startNestedScroll(axes);
        }
    
        @Override
        public void stopNestedScroll() {
            mChildHelper.stopNestedScroll();
        }
    
    
        @Override
        public boolean hasNestedScrollingParent() {
            return mChildHelper.hasNestedScrollingParent();
        }
    
        @Override
        public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) {
            return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
        }
    
        @Override
        public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow) {
            return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
        }
    
        @Override
        public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
            return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
    
        }
    
        @Override
        public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
            return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
        }
    }
    
    

    笔记
    这里有个bug 上滑 会有个白色的底部空白。暂时放下

    参考文章
    https://blog.csdn.net/mchenys/article/details/80041618

    相关文章

      网友评论

          本文标题:nestedscrollparent/children

          本文链接:https://www.haomeiwen.com/subject/smmnrctx.html