NestedScrollingChildHelper.java revision ac5fe7c617c66850fff75a9fce9979c6e5674b0f
1ce796e78a57018f186b062199c75d94545318acaPablo Ceballos/*
2ce796e78a57018f186b062199c75d94545318acaPablo Ceballos * Copyright 2018 The Android Open Source Project
3ce796e78a57018f186b062199c75d94545318acaPablo Ceballos *
4ce796e78a57018f186b062199c75d94545318acaPablo Ceballos * Licensed under the Apache License, Version 2.0 (the "License");
5ce796e78a57018f186b062199c75d94545318acaPablo Ceballos * you may not use this file except in compliance with the License.
6ce796e78a57018f186b062199c75d94545318acaPablo Ceballos * You may obtain a copy of the License at
7ce796e78a57018f186b062199c75d94545318acaPablo Ceballos *
8ce796e78a57018f186b062199c75d94545318acaPablo Ceballos *      http://www.apache.org/licenses/LICENSE-2.0
9ce796e78a57018f186b062199c75d94545318acaPablo Ceballos *
10ce796e78a57018f186b062199c75d94545318acaPablo Ceballos * Unless required by applicable law or agreed to in writing, software
11ce796e78a57018f186b062199c75d94545318acaPablo Ceballos * distributed under the License is distributed on an "AS IS" BASIS,
12ce796e78a57018f186b062199c75d94545318acaPablo Ceballos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ce796e78a57018f186b062199c75d94545318acaPablo Ceballos * See the License for the specific language governing permissions and
14ce796e78a57018f186b062199c75d94545318acaPablo Ceballos * limitations under the License.
15ce796e78a57018f186b062199c75d94545318acaPablo Ceballos */
16ce796e78a57018f186b062199c75d94545318acaPablo Ceballos
17ce796e78a57018f186b062199c75d94545318acaPablo Ceballos
18ce796e78a57018f186b062199c75d94545318acaPablo Ceballospackage androidx.core.view;
19ce796e78a57018f186b062199c75d94545318acaPablo Ceballos
20d6927fb1143398370c0885844bfb58923ef740b7Brian Andersonimport static androidx.core.view.ViewCompat.TYPE_NON_TOUCH;
21ce796e78a57018f186b062199c75d94545318acaPablo Ceballosimport static androidx.core.view.ViewCompat.TYPE_TOUCH;
22d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson
23d6927fb1143398370c0885844bfb58923ef740b7Brian Andersonimport androidx.annotation.NonNull;
24d6927fb1143398370c0885844bfb58923ef740b7Brian Andersonimport androidx.annotation.Nullable;
25d6927fb1143398370c0885844bfb58923ef740b7Brian Andersonimport androidx.core.view.ViewCompat.NestedScrollType;
263890c3995c4a52439844faeb80b5503d42b977d8Brian Andersonimport androidx.core.view.ViewCompat.ScrollAxis;
273890c3995c4a52439844faeb80b5503d42b977d8Brian Andersonimport android.view.View;
28ce796e78a57018f186b062199c75d94545318acaPablo Ceballosimport android.view.ViewParent;
29ce796e78a57018f186b062199c75d94545318acaPablo Ceballos
30ce796e78a57018f186b062199c75d94545318acaPablo Ceballos/**
31d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson * Helper class for implementing nested scrolling child views compatible with Android platform
32d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson * versions earlier than Android 5.0 Lollipop (API 21).
333890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson *
34d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson * <p>{@link android.view.View View} subclasses should instantiate a final instance of this
35d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson * class as a field at construction. For each <code>View</code> method that has a matching
36d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson * method signature in this class, delegate the operation to the helper instance in an overridden
373890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson * method implementation. This implements the standard framework policy for nested scrolling.</p>
383890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson *
39069b365163470d2736eb6f591c354d208b5da23bBrian Anderson * <p>Views invoking nested scrolling functionality should always do so from the relevant
403890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson * {@link androidx.core.view.ViewCompat}, {@link androidx.core.view.ViewGroupCompat} or
41069b365163470d2736eb6f591c354d208b5da23bBrian Anderson * {@link androidx.core.view.ViewParentCompat} compatibility
423890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson * shim static methods. This ensures interoperability with nested scrolling views on Android
433890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson * 5.0 Lollipop and newer.</p>
443890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson */
453890c3995c4a52439844faeb80b5503d42b977d8Brian Andersonpublic class NestedScrollingChildHelper {
463890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    private ViewParent mNestedScrollingParentTouch;
473890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    private ViewParent mNestedScrollingParentNonTouch;
483890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    private final View mView;
49ce796e78a57018f186b062199c75d94545318acaPablo Ceballos    private boolean mIsNestedScrollingEnabled;
50ce796e78a57018f186b062199c75d94545318acaPablo Ceballos    private int[] mTempNestedScrollConsumed;
51d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson
52d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    /**
53d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * Construct a new helper for a given view.
543890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     */
553890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    public NestedScrollingChildHelper(@NonNull View view) {
563890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        mView = view;
573890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    }
583890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson
593890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    /**
603890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * Enable nested scrolling.
613890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
623890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
633890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
643890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * signature to implement the standard policy.</p>
65d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     *
66d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * @param enabled true to enable nested scrolling dispatch from this view, false otherwise
67d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     */
683890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    public void setNestedScrollingEnabled(boolean enabled) {
693890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        if (mIsNestedScrollingEnabled) {
703890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            ViewCompat.stopNestedScroll(mView);
713890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        }
72d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson        mIsNestedScrollingEnabled = enabled;
73d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    }
74d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson
75d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    /**
76d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * Check if nested scrolling is enabled for this view.
77d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     *
78d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
79d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
803890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * signature to implement the standard policy.</p>
81d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     *
82d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * @return true if nested scrolling is enabled for this view
83d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     */
84d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    public boolean isNestedScrollingEnabled() {
85d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson        return mIsNestedScrollingEnabled;
86d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    }
87d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson
88d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    /**
89d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * Check if this view has a nested scrolling parent view currently receiving events for
90d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * a nested scroll in progress with the type of touch.
91d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     *
92d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
93d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
94d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * signature to implement the standard policy.</p>
95d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     *
96d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * @return true if this view has a nested scrolling parent, false otherwise
97d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     */
98d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    public boolean hasNestedScrollingParent() {
99d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson        return hasNestedScrollingParent(TYPE_TOUCH);
100d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    }
101d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson
1023890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    /**
1033890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * Check if this view has a nested scrolling parent view currently receiving events for
1043890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * a nested scroll in progress with the given type.
1053890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
1063890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
1073890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
1083890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * signature to implement the standard policy.</p>
1093890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
1103890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * @return true if this view has a nested scrolling parent, false otherwise
1113890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     */
1123890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    public boolean hasNestedScrollingParent(@NestedScrollType int type) {
1133890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        return getNestedScrollingParentForType(type) != null;
1143890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    }
1153890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson
1163890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    /**
1173890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * Start a new nested scroll for this view.
1183890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
1193890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
1203890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
1213890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * signature to implement the standard policy.</p>
1223890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
1233890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * @param axes Supported nested scroll axes.
1243890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *             See {@link androidx.core.view.NestedScrollingChild#startNestedScroll(int)}.
1253890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * @return true if a cooperating parent view was found and nested scrolling started successfully
1263890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     */
1273890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    public boolean startNestedScroll(@ScrollAxis int axes) {
1283890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        return startNestedScroll(axes, TYPE_TOUCH);
1293890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    }
1303890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson
1313890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    /**
1323890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * Start a new nested scroll for this view.
1333890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
1343890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
135d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild2} interface method with the same
136d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * signature to implement the standard policy.</p>
137d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     *
138d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * @param axes Supported nested scroll axes.
139d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     *             See {@link androidx.core.view.NestedScrollingChild2#startNestedScroll(int,
140d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     *             int)}.
141d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * @return true if a cooperating parent view was found and nested scrolling started successfully
142d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     */
1433890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    public boolean startNestedScroll(@ScrollAxis int axes, @NestedScrollType int type) {
1443890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        if (hasNestedScrollingParent(type)) {
1453890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            // Already in progress
146d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson            return true;
1473890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        }
1483890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        if (isNestedScrollingEnabled()) {
1493890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            ViewParent p = mView.getParent();
1503890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            View child = mView;
1513890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            while (p != null) {
1523890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes, type)) {
1533890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                    setNestedScrollingParentForType(type, p);
1543890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                    ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes, type);
1553890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                    return true;
1563890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                }
1573890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                if (p instanceof View) {
1583890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                    child = (View) p;
1593890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                }
1603890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                p = p.getParent();
1613890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            }
1623890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        }
1633890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        return false;
1643890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    }
1653890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson
1663890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    /**
1673890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * Stop a nested scroll in progress.
168d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     *
1693890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
1703890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
1713890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * signature to implement the standard policy.</p>
1723890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     */
1733890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    public void stopNestedScroll() {
1743890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        stopNestedScroll(TYPE_TOUCH);
175d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    }
176d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson
177d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    /**
178d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * Stop a nested scroll in progress.
179d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     *
180d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
181d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild2} interface method with the same
1823890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * signature to implement the standard policy.</p>
1833890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     */
184d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    public void stopNestedScroll(@NestedScrollType int type) {
1853890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        ViewParent parent = getNestedScrollingParentForType(type);
186d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson        if (parent != null) {
187d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson            ViewParentCompat.onStopNestedScroll(parent, mView, type);
188d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson            setNestedScrollingParentForType(type, null);
189d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson        }
190d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson    }
191d6927fb1143398370c0885844bfb58923ef740b7Brian Anderson
1923890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    /**
1933890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * Dispatch one step of a nested scrolling operation to the current nested scrolling parent.
1943890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
1953890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
1963890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
1973890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * signature to implement the standard policy.</p>
1983890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
1993890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * @return true if the parent consumed any of the nested scroll
2003890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     */
2013890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
2023890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) {
2033890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        return dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
2043890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                offsetInWindow, TYPE_TOUCH);
2053890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    }
2063890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson
2073890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    /**
2083890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * Dispatch one step of a nested scrolling operation to the current nested scrolling parent.
2093890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
2103890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
2113890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild2} interface method with the same
2123890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * signature to implement the standard policy.</p>
2133890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
2143890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * @return true if the parent consumed any of the nested scroll
2153890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     */
2163890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
2173890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow,
2183890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            @NestedScrollType int type) {
2193890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        if (isNestedScrollingEnabled()) {
2203890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            final ViewParent parent = getNestedScrollingParentForType(type);
2213890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            if (parent == null) {
2223890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                return false;
2233890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            }
2243890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson
2253890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) {
2263890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                int startX = 0;
2273890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                int startY = 0;
2283890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                if (offsetInWindow != null) {
2293890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                    mView.getLocationInWindow(offsetInWindow);
2303890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                    startX = offsetInWindow[0];
2313890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                    startY = offsetInWindow[1];
2323890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                }
2333890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson
2343890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                ViewParentCompat.onNestedScroll(parent, mView, dxConsumed,
2353890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                        dyConsumed, dxUnconsumed, dyUnconsumed, type);
2367c3ba8aa288755fad78ddbabcee0ad5a0610ac1cBrian Anderson
2377c3ba8aa288755fad78ddbabcee0ad5a0610ac1cBrian Anderson                if (offsetInWindow != null) {
2387c3ba8aa288755fad78ddbabcee0ad5a0610ac1cBrian Anderson                    mView.getLocationInWindow(offsetInWindow);
2393890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                    offsetInWindow[0] -= startX;
2407c3ba8aa288755fad78ddbabcee0ad5a0610ac1cBrian Anderson                    offsetInWindow[1] -= startY;
2417c3ba8aa288755fad78ddbabcee0ad5a0610ac1cBrian Anderson                }
2423890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                return true;
2433890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            } else if (offsetInWindow != null) {
2443890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                // No motion, no dispatch. Keep offsetInWindow up to date.
2453890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                offsetInWindow[0] = 0;
2463890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson                offsetInWindow[1] = 0;
2473890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            }
2483890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        }
2493890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        return false;
2503890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    }
2513890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson
2523890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    /**
2533890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * Dispatch one step of a nested pre-scrolling operation to the current nested scrolling parent.
2543890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
2553890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
2563890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
2573890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * signature to implement the standard policy.</p>
2583890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
2593890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * @return true if the parent consumed any of the nested scroll
2603890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     */
2613890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
2623890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson            @Nullable int[] offsetInWindow) {
2633890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson        return dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, TYPE_TOUCH);
2643890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    }
2653890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson
2663890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson    /**
2673890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * Dispatch one step of a nested pre-scrolling operation to the current nested scrolling parent.
2683890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     *
2693890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
2703890c3995c4a52439844faeb80b5503d42b977d8Brian Anderson     * method/{@link androidx.core.view.NestedScrollingChild2} interface method with the same
271ce796e78a57018f186b062199c75d94545318acaPablo Ceballos     * signature to implement the standard policy.</p>
272ce796e78a57018f186b062199c75d94545318acaPablo Ceballos     *
273     * @return true if the parent consumed any of the nested scroll
274     */
275    public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
276            @Nullable int[] offsetInWindow, @NestedScrollType int type) {
277        if (isNestedScrollingEnabled()) {
278            final ViewParent parent = getNestedScrollingParentForType(type);
279            if (parent == null) {
280                return false;
281            }
282
283            if (dx != 0 || dy != 0) {
284                int startX = 0;
285                int startY = 0;
286                if (offsetInWindow != null) {
287                    mView.getLocationInWindow(offsetInWindow);
288                    startX = offsetInWindow[0];
289                    startY = offsetInWindow[1];
290                }
291
292                if (consumed == null) {
293                    if (mTempNestedScrollConsumed == null) {
294                        mTempNestedScrollConsumed = new int[2];
295                    }
296                    consumed = mTempNestedScrollConsumed;
297                }
298                consumed[0] = 0;
299                consumed[1] = 0;
300                ViewParentCompat.onNestedPreScroll(parent, mView, dx, dy, consumed, type);
301
302                if (offsetInWindow != null) {
303                    mView.getLocationInWindow(offsetInWindow);
304                    offsetInWindow[0] -= startX;
305                    offsetInWindow[1] -= startY;
306                }
307                return consumed[0] != 0 || consumed[1] != 0;
308            } else if (offsetInWindow != null) {
309                offsetInWindow[0] = 0;
310                offsetInWindow[1] = 0;
311            }
312        }
313        return false;
314    }
315
316    /**
317     * Dispatch a nested fling operation to the current nested scrolling parent.
318     *
319     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
320     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
321     * signature to implement the standard policy.</p>
322     *
323     * @return true if the parent consumed the nested fling
324     */
325    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
326        if (isNestedScrollingEnabled()) {
327            ViewParent parent = getNestedScrollingParentForType(TYPE_TOUCH);
328            if (parent != null) {
329                return ViewParentCompat.onNestedFling(parent, mView, velocityX,
330                        velocityY, consumed);
331            }
332        }
333        return false;
334    }
335
336    /**
337     * Dispatch a nested pre-fling operation to the current nested scrolling parent.
338     *
339     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
340     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
341     * signature to implement the standard policy.</p>
342     *
343     * @return true if the parent consumed the nested fling
344     */
345    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
346        if (isNestedScrollingEnabled()) {
347            ViewParent parent = getNestedScrollingParentForType(TYPE_TOUCH);
348            if (parent != null) {
349                return ViewParentCompat.onNestedPreFling(parent, mView, velocityX,
350                        velocityY);
351            }
352        }
353        return false;
354    }
355
356    /**
357     * View subclasses should always call this method on their
358     * <code>NestedScrollingChildHelper</code> when detached from a window.
359     *
360     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
361     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
362     * signature to implement the standard policy.</p>
363     */
364    public void onDetachedFromWindow() {
365        ViewCompat.stopNestedScroll(mView);
366    }
367
368    /**
369     * Called when a nested scrolling child stops its current nested scroll operation.
370     *
371     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
372     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
373     * signature to implement the standard policy.</p>
374     *
375     * @param child Child view stopping its nested scroll. This may not be a direct child view.
376     */
377    public void onStopNestedScroll(@NonNull View child) {
378        ViewCompat.stopNestedScroll(mView);
379    }
380
381    private ViewParent getNestedScrollingParentForType(@NestedScrollType int type) {
382        switch (type) {
383            case TYPE_TOUCH:
384                return mNestedScrollingParentTouch;
385            case TYPE_NON_TOUCH:
386                return mNestedScrollingParentNonTouch;
387        }
388        return null;
389    }
390
391    private void setNestedScrollingParentForType(@NestedScrollType int type, ViewParent p) {
392        switch (type) {
393            case TYPE_TOUCH:
394                mNestedScrollingParentTouch = p;
395                break;
396            case TYPE_NON_TOUCH:
397                mNestedScrollingParentNonTouch = p;
398                break;
399        }
400    }
401}
402