CoordinatorLayout inside another CoordinatorLayout

后端 未结 8 1833
梦如初夏
梦如初夏 2020-12-02 11:41

CorodinatorLayout inside another CoordinatorLayout such that scrolling the child-view should also scroll the Parent CoordinatorLayout.

相关标签:
8条回答
  • 2020-12-02 11:47

    I have wrote one ChildCoordinatorLayout in my repo nestrefresh. In this repo, I wrap one AppBarLayout with ChildCoordinatorLayout and also add pull refresh for the ChildCoordinatorLayout with pull refresh behavior. And dyUnConsumed give parent firstly then to the child. This is the code:

    class ChildCoordinatorLayout @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
    ) : CoordinatorLayout(context, attrs, defStyleAttr), NestedScrollingChild2 {
    
        private lateinit var childHelper: NestedScrollingChildHelper
    
        init {
            init()
        }
    
        private fun init() {
            childHelper = NestedScrollingChildHelper(this)
            childHelper.isNestedScrollingEnabled = true
        }
    
        override fun setNestedScrollingEnabled(enabled: Boolean) {
            childHelper.isNestedScrollingEnabled = enabled
        }
    
        override fun isNestedScrollingEnabled(): Boolean {
            return childHelper.isNestedScrollingEnabled
        }
    
        override fun startNestedScroll(i: Int, i1: Int): Boolean {
            return childHelper.startNestedScroll(i, i1)
        }
    
        override fun stopNestedScroll(i: Int) {
            childHelper.stopNestedScroll(i)
        }
    
        override fun hasNestedScrollingParent(i: Int): Boolean {
            return childHelper.hasNestedScrollingParent()
        }
    
        override fun dispatchNestedScroll(i: Int, i1: Int, i2: Int, i3: Int, ints: IntArray?, i4: Int): Boolean {
            return childHelper.dispatchNestedScroll(i, i1, i2, i3, ints, i4)
        }
    
        override fun dispatchNestedPreScroll(i: Int, i1: Int, ints: IntArray?, ints1: IntArray?, i2: Int): Boolean {
            return childHelper.dispatchNestedPreScroll(i, i1, ints, ints1, i2)
        }
    
        override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float): Boolean {
            return childHelper.dispatchNestedPreFling(velocityX, velocityY)
        }
    
        override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {
            return childHelper.dispatchNestedFling(velocityX, velocityY, consumed)
        }
    
        override fun onStartNestedScroll(child: View, target: View, axes: Int, type: Int): Boolean {
            if (type == TYPE_TOUCH) {
                stopNestedScroll(TYPE_NON_TOUCH)
                ViewCompat.stopNestedScroll(child, TYPE_NON_TOUCH)
            }
            val handle = super.onStartNestedScroll(child, target, axes, type)
            return startNestedScroll(axes, type) || handle
        }
    
        override fun onStopNestedScroll(target: View, type: Int) {
            super.onStopNestedScroll(target, type)
            stopNestedScroll(type)
        }
    
        override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
            val thisConsume = IntArray(2)
            dispatchNestedPreScroll(dx, dy, thisConsume, null, type)
            consumed[0] += thisConsume[0]
            consumed[1] += thisConsume[1]
            thisConsume[0] = 0
            thisConsume[1] = 0
            super.onNestedPreScroll(target, dx - consumed[0], dy - consumed[1], thisConsume, type)
            consumed[0] += thisConsume[0]
            consumed[1] += thisConsume[1]
    
        }
    
        override fun onNestedScroll(
            target: View,
            dxConsumed: Int,
            dyConsumed: Int,
            dxUnconsumed: Int,
            dyUnconsumed: Int,
            type: Int
        ) {
    
            val offsetInWindow = IntArray(2)
            target.getLocationInWindow(offsetInWindow)
            val startX = offsetInWindow[0]
            val startY = offsetInWindow[1]
            super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type)
            target.getLocationInWindow(offsetInWindow)
            offsetInWindow[0] -= startX
            offsetInWindow[1] -= startY
            dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed + offsetInWindow[0]
                , dyUnconsumed + offsetInWindow[1], null, type)
        }
    
        override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {
            val handled = super.onNestedPreFling(target, velocityX, velocityY)
            return dispatchNestedPreFling(velocityX, velocityY) || handled
        }
    
        override fun onNestedFling(target: View, velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {
            val handled = super.onNestedFling(target, velocityX, velocityY, consumed)
            return dispatchNestedFling(velocityX, velocityY, consumed) || handled
        }
    
    }
    
    0 讨论(0)
  • 2020-12-02 11:48

    Unfortunately, this is not supported by CoordinatorLayout.

    Check the code in NestedScrollingChildHelper.startNestedScroll() and CoordinatorLayout.onStartNestedScroll(), the nested scrolling event is "consumed" if one of Behaviors of your inner CoordinatorLayout consumes it, and won't be further propagated.

    0 讨论(0)
  • 2020-12-02 11:55

    I made this a library, see it on GitHub.

    You just use <NestedScrollCoordinatorLayout> in your layout.

    0 讨论(0)
  • 2020-12-02 11:56

    Hopefully, this will help others. The idea I implemented during preScroll calculates how much the parent is able to consume, if it is already 0, then call super.onNestedPreScroll.

    Here's the code:

    import android.content.Context;
    import android.support.annotation.Nullable;
    import android.support.design.widget.CoordinatorLayout;
    import android.support.v4.view.NestedScrollingChild2;
    import android.support.v4.view.NestedScrollingChildHelper;
    import android.util.AttributeSet;
    import android.view.View;
    
    public class NestedScrollCoordinatorLayout extends CoordinatorLayout implements NestedScrollingChild2 {
    
      private NestedScrollingChildHelper mChildHelper;
    
      public NestedScrollCoordinatorLayout(Context context) {
        super(context);
        mChildHelper = new NestedScrollingChildHelper(this);
        setNestedScrollingEnabled(true);
      }
    
      public NestedScrollCoordinatorLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mChildHelper = new NestedScrollingChildHelper(this);
        setNestedScrollingEnabled(true);
      }
    
      public NestedScrollCoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mChildHelper = new NestedScrollingChildHelper(this);
        setNestedScrollingEnabled(true);
      }
    
      @Override
      public boolean isNestedScrollingEnabled() {
        return mChildHelper.isNestedScrollingEnabled();
      }
    
      @Override
      public void setNestedScrollingEnabled(boolean enabled) {
        mChildHelper.setNestedScrollingEnabled(enabled);
      }
    
      @Override
      public boolean hasNestedScrollingParent() {
        return mChildHelper.hasNestedScrollingParent();
      }
    
      @Override
      public boolean hasNestedScrollingParent(int type) {
        return mChildHelper.hasNestedScrollingParent(type);
      }
    
      @Override
      public boolean onStartNestedScroll(View child, View target, int axes, int type) {
        boolean superResult = super.onStartNestedScroll(child, target, axes, type);
        return startNestedScroll(axes, type) || superResult;
      }
    
      @Override
      public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        boolean superResult = super.onStartNestedScroll(child, target, nestedScrollAxes);
        return startNestedScroll(nestedScrollAxes) || superResult;
      }
    
      @Override
      public void onNestedPreScroll(View target, int dx, int dy, int[] consumed, int type) {
        dispatchNestedPreScroll(dx, dy, consumed, null);
        if (consumed[1] == 0) {
          super.onNestedPreScroll(target, dx, dy, consumed, type);
        }
      }
    
      @Override
      public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        dispatchNestedPreScroll(dx, dy, consumed, null);
        if (consumed[1] == 0) {
          super.onNestedPreScroll(target, dx, dy, consumed);
        }
      }
    
      @Override
      public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
        dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null, type);
      }
    
      @Override
      public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
      }
    
      @Override
      public void onStopNestedScroll(View target, int type) {
        super.onStopNestedScroll(target, type);
        stopNestedScroll(type);
      }
    
      @Override
      public void onStopNestedScroll(View target) {
        super.onStopNestedScroll(target);
        stopNestedScroll();
      }
    
      @Override
      public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
        boolean superResult = super.onNestedPreFling(target, velocityX, velocityY);
        return dispatchNestedPreFling(velocityX, velocityY) || superResult;
      }
    
      @Override
      public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
        boolean superResult = super.onNestedFling(target, velocityX, velocityY, consumed);
        return dispatchNestedFling(velocityX, velocityY, consumed) || superResult;
      }
    
      @Override
      public boolean startNestedScroll(int axes, int type) {
        return mChildHelper.startNestedScroll(axes, type);
      }
    
      @Override
      public boolean startNestedScroll(int axes) {
        return mChildHelper.startNestedScroll(axes);
      }
    
      @Override
      public void stopNestedScroll() {
        mChildHelper.stopNestedScroll();
      }
    
      @Override
      public void stopNestedScroll(int type) {
        mChildHelper.stopNestedScroll(type);
      }
    
      @Override
      public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow, int type) {
        return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow, type);
      }
    
      @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 dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow, int type) {
        return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type);
      }
    
      @Override
      public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
        return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
      }
    
      @Override
      public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
        return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
      }
    }

    See also this gist on GithHub

    0 讨论(0)
  • 2020-12-02 12:00

    Here's a simple implementation of a nested coordinator layout.

    
    /**
     * This variation of CoordinatorLayout also serves as a nested scrolling child,
     * which supports passing nested scrolling operations to it's parent when it's
     * own nested scrolling is locked.
     */
    public class NestedCoordinatorLayout extends CoordinatorLayout implements NestedScrollingChild {
    
        private NestedScrollingChildHelper mChildHelper;
        private volatile boolean mPassToParent;
    
        public NestedCoordinatorLayout(Context context) {
            super(context);
            mChildHelper = new NestedScrollingChildHelper(this);
            setNestedScrollingEnabled(true);
        }
    
        public NestedCoordinatorLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
            mChildHelper = new NestedScrollingChildHelper(this);
            setNestedScrollingEnabled(true);
        }
    
        public NestedCoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mChildHelper = new NestedScrollingChildHelper(this);
            setNestedScrollingEnabled(true);
        }
    
        /**
         * Locks the nested scrolling. Further scroll events will
         * be passed to the nested scrolling parent.
         */
        public void lockNestedScrolling() {
            mPassToParent = true;
        }
    
        /**
         * Unlocks the nested scrolling. Further scroll events will
         * be dispatched to this layout's own scrolling children.
         */
        public void unlockNestedScrolling() {
            mPassToParent = false;
        }
    
        /*
         * NestedScrollingParent implementation
         */
    
        @Override
        public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
            /* Enable the scrolling behavior of our own children */
            super.onStartNestedScroll(child, target, nestedScrollAxes);
            /* Enable the scrolling behavior of the parent's other children  */
            startNestedScroll(nestedScrollAxes);
            /* Start tracking the current scroll */
            return true;
        }
    
        @Override
        public void onStopNestedScroll(View target) {
            /* Disable the scrolling behavior of our own children */
            super.onStopNestedScroll(target);
            /* Disable the scrolling behavior of the parent's other children  */
            stopNestedScroll();
        }
    
        @Override
        public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
            if (mPassToParent) {
                dispatchNestedPreScroll(dx, dy, consumed, null);
            } else {
                super.onNestedPreScroll(target, dx, dy, consumed);
            }
        }
    
        @Override
        public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
                                   int dxUnconsumed, int dyUnconsumed) {
            if (mPassToParent) {
                dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
            } else {
                super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
            }
        }
    
        @Override
        public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
            if (mPassToParent) {
                return dispatchNestedPreFling(velocityX, velocityY);
            } else {
                return super.onNestedPreFling(target, velocityX, velocityY);
            }
        }
    
        @Override
        public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
            if (mPassToParent) {
                return dispatchNestedFling(velocityX, velocityY, consumed);
            } else {
                return super.onNestedFling(target, velocityX, velocityY, consumed);
            }
        }
    
        /*
         * NestedScrollingChild implementation
         */
    
        @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, int[] offsetInWindow) {
            return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed,
                    dyUnconsumed, offsetInWindow);
        }
    
        @Override
        public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, 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);
        }
    }
    
    0 讨论(0)
  • 2020-12-02 12:02

    You need to custom your CHILD CoordinatorLayout, let it implement NestedScrollingChild (ori coordinatorlayout didn't implement it) and override some functions to enable dispatching nested scroll event to your PARENT CoordinatorLayout.

    0 讨论(0)
提交回复
热议问题