AppBarLayout.java revision ab809dd75ef2f73b312038f2c10473cfa5885a58
1a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes/*
2a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Copyright (C) 2015 The Android Open Source Project
3a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
4a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Licensed under the Apache License, Version 2.0 (the "License");
5a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * you may not use this file except in compliance with the License.
6a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * You may obtain a copy of the License at
7a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
8a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *      http://www.apache.org/licenses/LICENSE-2.0
9a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
10a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Unless required by applicable law or agreed to in writing, software
11a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * distributed under the License is distributed on an "AS IS" BASIS,
12a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * See the License for the specific language governing permissions and
14a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * limitations under the License.
15a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes */
16a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
17a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banespackage android.support.design.widget;
18a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
19a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.content.Context;
20a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.content.res.TypedArray;
21e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banesimport android.os.Parcel;
22e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banesimport android.os.Parcelable;
2350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banesimport android.support.annotation.IntDef;
24a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.support.design.R;
25d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banesimport android.support.v4.view.MotionEventCompat;
26a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.support.v4.view.ViewCompat;
276ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banesimport android.support.v4.view.WindowInsetsCompat;
28631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport android.support.v4.widget.ScrollerCompat;
29a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.util.AttributeSet;
30d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banesimport android.view.MotionEvent;
31a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.View;
32d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banesimport android.view.ViewConfiguration;
33a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.ViewGroup;
34a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.animation.Interpolator;
35a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.widget.LinearLayout;
36a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
3750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banesimport java.lang.annotation.Retention;
3850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banesimport java.lang.annotation.RetentionPolicy;
39d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banesimport java.lang.ref.WeakReference;
40631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport java.util.ArrayList;
41a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport java.util.List;
42a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
43a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes/**
44a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * AppBarLayout is a vertical {@link LinearLayout} which implements many of the features of
459fb154338a62edc2c57dc036895199d6f1769400Chris Banes * material designs app bar concept, namely scrolling gestures.
46a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <p>
47a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Children should provide their desired scrolling behavior through
48a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * {@link LayoutParams#setScrollFlags(int)} and the associated layout xml attribute:
49a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * {@code app:layout_scrollFlags}.
50a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
51a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <p>
52a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * This view depends heavily on being used as a direct child within a {@link CoordinatorLayout}.
53a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * If you use AppBarLayout within a different {@link ViewGroup}, most of it's functionality will
54a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * not work.
55a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <p>
569fb154338a62edc2c57dc036895199d6f1769400Chris Banes * AppBarLayout also requires a separate scrolling sibling in order to know when to scroll.
579fb154338a62edc2c57dc036895199d6f1769400Chris Banes * The binding is done through the {@link ScrollingViewBehavior} behavior class, meaning that you
589fb154338a62edc2c57dc036895199d6f1769400Chris Banes * should set your scrolling view's behavior to be an instance of {@link ScrollingViewBehavior}.
599fb154338a62edc2c57dc036895199d6f1769400Chris Banes * A string resource containing the full class name is available.
60a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
61a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <pre>
62a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * &lt;android.support.design.widget.CoordinatorLayout
63a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         xmlns:android=&quot;http://schemas.android.com/apk/res/android";
64a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         xmlns:app=&quot;http://schemas.android.com/apk/res-auto";
65a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         android:layout_width=&quot;match_parent&quot;
66a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         android:layout_height=&quot;match_parent&quot;&gt;
67a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
68a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;android.support.v4.widget.NestedScrollView
69a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_width=&quot;match_parent&quot;
70a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_height=&quot;match_parent&quot;
71a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             app:layout_behavior=&quot;@string/appbar_scrolling_view_behavior&quot;&gt;
72a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
73a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         &lt;!-- Your scrolling content --&gt;
74a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
75a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;/android.support.v4.widget.NestedScrollView&gt;
76a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
77a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;android.support.design.widget.AppBarLayout
78a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_height=&quot;wrap_content&quot;
79a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_width=&quot;match_parent&quot;&gt;
80a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
81a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         &lt;android.support.v7.widget.Toolbar
82a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 ...
83a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 app:layout_scrollFlags=&quot;scroll|enterAlways&quot;/&gt;
84a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
85a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         &lt;android.support.design.widget.TabLayout
86a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 ...
87a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 app:layout_scrollFlags=&quot;scroll|enterAlways&quot;/&gt;
88a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
89a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;/android.support.design.widget.AppBarLayout&gt;
90a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
91a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * &lt;/android.support.design.widget.CoordinatorLayout&gt;
92a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * </pre>
93a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
94a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * @see <a href="http://www.google.com/design/spec/layout/structure.html#structure-app-bar">
95a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     http://www.google.com/design/spec/layout/structure.html#structure-app-bar</a>
96a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes */
97a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
98a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banespublic class AppBarLayout extends LinearLayout {
99a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1009995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    private static final int PENDING_ACTION_NONE = 0x0;
1019995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    private static final int PENDING_ACTION_EXPANDED = 0x1;
1029995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    private static final int PENDING_ACTION_COLLAPSED = 0x2;
1039995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    private static final int PENDING_ACTION_ANIMATE_ENABLED = 0x4;
1049995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes
105a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
106631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * Interface definition for a callback to be invoked when an {@link AppBarLayout}'s vertical
107631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * offset changes.
108a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
109631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public interface OnOffsetChangedListener {
110a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
111a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Called when the {@link AppBarLayout}'s layout offset has been changed. This allows
112a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * child views to implement custom behavior based on the offset (for instance pinning a
113a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * view at a certain y value).
114a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
115631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes         * @param appBarLayout the {@link AppBarLayout} which offset has changed
11650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * @param verticalOffset the vertical offset for the parent {@link AppBarLayout}, in px
117a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
118631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset);
119a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
120a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
121a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private static final int INVALID_SCROLL_RANGE = -1;
122a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
123a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private int mTotalScrollRange = INVALID_SCROLL_RANGE;
124a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private int mDownPreScrollRange = INVALID_SCROLL_RANGE;
125a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private int mDownScrollRange = INVALID_SCROLL_RANGE;
126a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
127a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    boolean mHaveChildWithInterpolator;
128a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
12950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    private float mTargetElevation;
13050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
1319995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    private int mPendingAction = PENDING_ACTION_NONE;
1329995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes
1336ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes    private WindowInsetsCompat mLastInsets;
1346ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes
1356f730c0acfb10a929172ea2981a1aded0e39f5c7Chris Banes    private final List<OnOffsetChangedListener> mListeners;
136631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
137a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public AppBarLayout(Context context) {
138a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        this(context, null);
139a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
140a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
141a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public AppBarLayout(Context context, AttributeSet attrs) {
142a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        super(context, attrs);
143a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        setOrientation(VERTICAL);
14450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
14550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppBarLayout,
14650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                0, R.style.Widget_Design_AppBarLayout);
14750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        mTargetElevation = a.getDimensionPixelSize(R.styleable.AppBarLayout_elevation, 0);
14881520564f3dd783136e025174021ba4eabd6ff3cChris Banes        setBackgroundDrawable(a.getDrawable(R.styleable.AppBarLayout_android_background));
1499995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes        if (a.hasValue(R.styleable.AppBarLayout_expanded)) {
1509995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes            setExpanded(a.getBoolean(R.styleable.AppBarLayout_expanded, false));
1519995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes        }
15250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        a.recycle();
15350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
15450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        // Use the bounds view outline provider so that we cast a shadow, even without a background
15550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        ViewUtils.setBoundsViewOutlineProvider(this);
156631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
157631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mListeners = new ArrayList<>();
158631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
159631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        ViewCompat.setElevation(this, mTargetElevation);
1606ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes
1616ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        ViewCompat.setOnApplyWindowInsetsListener(this,
1626ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                new android.support.v4.view.OnApplyWindowInsetsListener() {
1636ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    @Override
1646ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    public WindowInsetsCompat onApplyWindowInsets(View v,
1656ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                            WindowInsetsCompat insets) {
1666ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                        setWindowInsets(insets);
1676ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                        return insets.consumeSystemWindowInsets();
1686ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    }
1696ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                });
170631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
171631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
172631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    /**
173631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * Add a listener that will be called when the offset of this {@link AppBarLayout} changes.
174631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     *
175631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * @param listener The listener that will be called when the offset changes.]
176631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     *
177631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * @see #removeOnOffsetChangedListener(OnOffsetChangedListener)
178631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     */
179631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void addOnOffsetChangedListener(OnOffsetChangedListener listener) {
1806f730c0acfb10a929172ea2981a1aded0e39f5c7Chris Banes        if (listener != null && !mListeners.contains(listener)) {
1816f730c0acfb10a929172ea2981a1aded0e39f5c7Chris Banes            mListeners.add(listener);
182631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
183631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
184631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
185631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    /**
186631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * Remove the previously added {@link OnOffsetChangedListener}.
187631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     *
188631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * @param listener the listener to remove.
189631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     */
190631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void removeOnOffsetChangedListener(OnOffsetChangedListener listener) {
1916f730c0acfb10a929172ea2981a1aded0e39f5c7Chris Banes        if (listener != null) {
1926f730c0acfb10a929172ea2981a1aded0e39f5c7Chris Banes            mListeners.remove(listener);
193631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
194a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
195a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
196a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
197a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected void onLayout(boolean changed, int l, int t, int r, int b) {
198a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        super.onLayout(changed, l, t, r, b);
199a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
200a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        // Invalidate the scroll ranges
201a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mTotalScrollRange = INVALID_SCROLL_RANGE;
202a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mDownPreScrollRange = INVALID_SCROLL_RANGE;
203a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mDownPreScrollRange = INVALID_SCROLL_RANGE;
204a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
205a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mHaveChildWithInterpolator = false;
206a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        for (int i = 0, z = getChildCount(); i < z; i++) {
207a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
208a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams childLp = (LayoutParams) child.getLayoutParams();
209a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final Interpolator interpolator = childLp.getScrollInterpolator();
210a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
211a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (interpolator != null) {
212a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                mHaveChildWithInterpolator = true;
213a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
214a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
215a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
216a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
217a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
218a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
219a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public void setOrientation(int orientation) {
220a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (orientation != VERTICAL) {
221a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            throw new IllegalArgumentException("AppBarLayout is always vertical and does"
222a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    + " not support horizontal orientation");
223a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
224a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        super.setOrientation(orientation);
225a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
226a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
2279995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    /**
2289995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * Sets whether this {@link AppBarLayout} is expanded or not, animating if it has already
2299995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * been laid out.
2309995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     *
2319995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * <p>As with {@link AppBarLayout}'s scrolling, this method relies on this layout being a
2329995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * direct child of a {@link CoordinatorLayout}.</p>
2339995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     *
2349995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * @param expanded true if the layout should be fully expanded, false if it should
2359995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     *                 be fully collapsed
2369995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     *
2379995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * @attr ref android.support.design.R.styleable#AppBarLayout_expanded
2389995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     */
2399995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    public void setExpanded(boolean expanded) {
2409995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes        setExpanded(expanded, ViewCompat.isLaidOut(this));
2419995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    }
2429995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes
2439995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    /**
2449995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * Sets whether this {@link AppBarLayout} is expanded or not.
2459995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     *
2469995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * <p>As with {@link AppBarLayout}'s scrolling, this method relies on this layout being a
2479995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * direct child of a {@link CoordinatorLayout}.</p>
2489995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     *
2499995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * @param expanded true if the layout should be fully expanded, false if it should
2509995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     *                 be fully collapsed
2519995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * @param animate Whether to animate to the new state
2529995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     *
2539995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     * @attr ref android.support.design.R.styleable#AppBarLayout_expanded
2549995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes     */
2559995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    public void setExpanded(boolean expanded, boolean animate) {
2569995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes        mPendingAction = (expanded ? PENDING_ACTION_EXPANDED : PENDING_ACTION_COLLAPSED)
2579995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                | (animate ? PENDING_ACTION_ANIMATE_ENABLED : 0);
2589995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes        requestLayout();
2599995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    }
2609995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes
261a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
262a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
263a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return p instanceof LayoutParams;
264a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
265a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
266a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
267a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected LayoutParams generateDefaultLayoutParams() {
268a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
269a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
270a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
271a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
272a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public LayoutParams generateLayoutParams(AttributeSet attrs) {
273a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return new LayoutParams(getContext(), attrs);
274a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
275a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
276a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
277a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
278a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (p instanceof LinearLayout.LayoutParams) {
279a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return new LayoutParams((LinearLayout.LayoutParams) p);
280a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        } else if (p instanceof MarginLayoutParams) {
281a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return new LayoutParams((MarginLayoutParams) p);
282a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
283a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return new LayoutParams(p);
284a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
285a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
286a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final boolean hasChildWithInterpolator() {
287a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return mHaveChildWithInterpolator;
288a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
289a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
290a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
2916ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes     * Returns the scroll range of all children.
292a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     *
293a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * @return the scroll range in px
294a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
2956ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes    public final int getTotalScrollRange() {
296a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (mTotalScrollRange != INVALID_SCROLL_RANGE) {
297a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mTotalScrollRange;
298a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
299a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
300a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int range = 0;
301a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        for (int i = 0, z = getChildCount(); i < z; i++) {
302a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
303a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
304a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int childHeight = ViewCompat.isLaidOut(child)
305a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ? child.getHeight()
306a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    : child.getMeasuredHeight();
307a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int flags = lp.mScrollFlags;
308a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
309a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
310a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // We're set to scroll so add the child's height
311b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                range += childHeight + lp.topMargin + lp.bottomMargin;
312a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
313a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
314a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // For a collapsing scroll, we to take the collapsed height into account.
3156ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    // We also break straight away since later views can't scroll beneath
316a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // us
3176ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    range -= ViewCompat.getMinimumHeight(child);
3186ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    break;
319a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
320a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            } else {
321a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // As soon as a view doesn't have the scroll flag, we end the range calculation.
322a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // This is because views below can not scroll under a fixed view.
323a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
324a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
325a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
3266ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        final int top = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
3276ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        return mTotalScrollRange = (range - top);
328a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
329a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
330a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final boolean hasScrollableChildren() {
331a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return getTotalScrollRange() != 0;
332a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
333a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
334a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
335a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Return the scroll range when scrolling up from a nested pre-scroll.
336a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
337a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final int getUpNestedPreScrollRange() {
33850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        return getTotalScrollRange();
339a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
340a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
341a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
342a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Return the scroll range when scrolling down from a nested pre-scroll.
343a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
344a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final int getDownNestedPreScrollRange() {
345a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (mDownPreScrollRange != INVALID_SCROLL_RANGE) {
346a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            // If we already have a valid value, return it
347a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mDownPreScrollRange;
348a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
349a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
350a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int range = 0;
351a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        for (int i = getChildCount() - 1; i >= 0; i--) {
352a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
353a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
354a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int childHeight = ViewCompat.isLaidOut(child)
355a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ? child.getHeight()
356a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    : child.getMeasuredHeight();
357a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int flags = lp.mScrollFlags;
358a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
359a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if ((flags & LayoutParams.FLAG_QUICK_RETURN) == LayoutParams.FLAG_QUICK_RETURN) {
360b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                // First take the margin into account
361b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                range += lp.topMargin + lp.bottomMargin;
362a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // The view has the quick return flag combination...
363a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if ((flags & LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED) != 0) {
364a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // If they're set to enter collapsed, use the minimum height
365a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    range += ViewCompat.getMinimumHeight(child);
366a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                } else {
367a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Else use the full height
368a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    range += childHeight;
369a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
370a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            } else if (range > 0) {
371a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // If we've hit an non-quick return scrollable view, and we've already hit a
372a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // quick return view, return now
373a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
374a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
375a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
376a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return mDownPreScrollRange = range;
377a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
378a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
379a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
380a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Return the scroll range when scrolling down from a nested scroll.
381a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
382a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final int getDownNestedScrollRange() {
383a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (mDownScrollRange != INVALID_SCROLL_RANGE) {
384a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            // If we already have a valid value, return it
385a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mDownScrollRange;
386a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
387a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
388a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int range = 0;
389c1ce4f6cf4d99d6856c4259bf1bb1cb56f604737Chris Banes        for (int i = 0, z = getChildCount(); i < z; i++) {
390a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
391a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
392b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes            int childHeight = ViewCompat.isLaidOut(child)
393a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ? child.getHeight()
394a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    : child.getMeasuredHeight();
395b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes            childHeight += lp.topMargin + lp.bottomMargin;
396a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
397a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int flags = lp.mScrollFlags;
398a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
399a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
400a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // We're set to scroll so add the child's height
401a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                range += childHeight;
402a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
403a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
404a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // For a collapsing exit scroll, we to take the collapsed height into account.
405a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // We also return the range straight away since later views can't scroll
406a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // beneath us
407a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return range - ViewCompat.getMinimumHeight(child);
408a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
409a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            } else {
410a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // As soon as a view doesn't have the scroll flag, we end the range calculation.
411a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // This is because views below can not scroll under a fixed view.
412a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
413a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
414a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
415a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return mDownScrollRange = range;
416a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
417a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
41850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    final int getMinimumHeightForVisibleOverlappingContent() {
4196ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        final int topInset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
42050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        final int minHeight = ViewCompat.getMinimumHeight(this);
42150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        if (minHeight != 0) {
42250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            // If this layout has a min height, use it (doubled)
4236ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes            return (minHeight * 2) + topInset;
42450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        }
42550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
42650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        // Otherwise, we'll use twice the min height of our last child
42750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        final int childCount = getChildCount();
42850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        return childCount >= 1
4296ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                ? (ViewCompat.getMinimumHeight(getChildAt(childCount - 1)) * 2) + topInset
43050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                : 0;
43150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    }
43250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
43350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    /**
434631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * Set the elevation value to use when this {@link AppBarLayout} should be elevated
435631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * above content.
436631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * <p>
437631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * This method does not do anything itself. A typical use for this method is called from within
438631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * an {@link OnOffsetChangedListener} when the offset has changed in such a way to require an
439631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * elevation change.
440631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     *
441631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * @param elevation the elevation value to use.
442631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     *
443631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * @see ViewCompat#setElevation(View, float)
44450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes     */
445631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setTargetElevation(float elevation) {
446631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mTargetElevation = elevation;
447631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
448631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
449631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    /**
450631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * Returns the elevation value to use when this {@link AppBarLayout} should be elevated
451631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * above content.
452631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     */
453631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public float getTargetElevation() {
45450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        return mTargetElevation;
45550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    }
45650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
4579995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    int getPendingAction() {
4589995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes        return mPendingAction;
4599995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    }
4609995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes
4619995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    void resetPendingAction() {
4629995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes        mPendingAction = PENDING_ACTION_NONE;
4639995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes    }
4649995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes
4656ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes    private void setWindowInsets(WindowInsetsCompat insets) {
4666ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        // Invalidate the total scroll range...
4676ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        mTotalScrollRange = INVALID_SCROLL_RANGE;
4686ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        mLastInsets = insets;
4696ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes
4706ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        // Now dispatch them to our children
4716ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        for (int i = 0, z = getChildCount(); i < z; i++) {
4726ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes            final View child = getChildAt(i);
4736ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes            insets = ViewCompat.dispatchApplyWindowInsets(child, insets);
4746ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes            if (insets.isConsumed()) {
4756ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                break;
4766ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes            }
4776ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        }
4786ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes    }
4796ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes
480a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public static class LayoutParams extends LinearLayout.LayoutParams {
48150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
48250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        /** @hide */
48350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @IntDef(flag=true, value={
48450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_SCROLL,
48550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_EXIT_UNTIL_COLLAPSED,
48650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_ENTER_ALWAYS,
48750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED
48850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        })
48950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @Retention(RetentionPolicy.SOURCE)
49050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        public @interface ScrollFlags {}
49150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
492a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
493a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * The view will be scroll in direct relation to scroll events. This flag needs to be
494a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * set for any of the other flags to take effect. If any sibling views
495a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * before this one do not have this flag, then this value has no effect.
496a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
497a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_SCROLL = 0x1;
498a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
499a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
500a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * When exiting (scrolling off screen) the view will be scrolled until it is
501a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * 'collapsed'. The collapsed height is defined by the view's minimum height.
502a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
503a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see ViewCompat#getMinimumHeight(View)
504a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see View#setMinimumHeight(int)
505a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
506a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 0x2;
507a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
508a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
509a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * When entering (scrolling on screen) the view will scroll on any downwards
510a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * scroll event, regardless of whether the scrolling view is also scrolling. This
511a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * is commonly referred to as the 'quick return' pattern.
512a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
513a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_ENTER_ALWAYS = 0x4;
514a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
515a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
516a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * An additional flag for 'enterAlways' which modifies the returning view to
517a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * only initially scroll back to it's collapsed height. Once the scrolling view has
518a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * reached the end of it's scroll range, the remainder of this view will be scrolled
519a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * into view. The collapsed height is defined by the view's minimum height.
520a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
521a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see ViewCompat#getMinimumHeight(View)
522a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see View#setMinimumHeight(int)
523a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
524a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 0x8;
525a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
526a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
527a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Internal flag which allows quick checking of 'quick return'
528a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
529a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        static final int FLAG_QUICK_RETURN = SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS;
530a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
531a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int mScrollFlags = SCROLL_FLAG_SCROLL;
532a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        Interpolator mScrollInterpolator;
533a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
534a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(Context c, AttributeSet attrs) {
535a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(c, attrs);
536a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.AppBarLayout_LayoutParams);
537a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollFlags = a.getInt(R.styleable.AppBarLayout_LayoutParams_layout_scrollFlags, 0);
538a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (a.hasValue(R.styleable.AppBarLayout_LayoutParams_layout_scrollInterpolator)) {
539a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int resId = a.getResourceId(
540a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        R.styleable.AppBarLayout_LayoutParams_layout_scrollInterpolator, 0);
541a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                mScrollInterpolator = android.view.animation.AnimationUtils.loadInterpolator(
542a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        c, resId);
543a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
544a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            a.recycle();
545a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
546a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
547a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(int width, int height) {
548a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(width, height);
549a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
550a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
551a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(int width, int height, float weight) {
552a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(width, height, weight);
553a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
554a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
555a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(ViewGroup.LayoutParams p) {
556a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(p);
557a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
558a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
559a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(MarginLayoutParams source) {
560a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(source);
561a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
562a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
563a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(LinearLayout.LayoutParams source) {
564a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(source);
565a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
566a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
567a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(LayoutParams source) {
568a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(source);
569a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollFlags = source.mScrollFlags;
570a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollInterpolator = source.mScrollInterpolator;
571a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
572a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
573a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
574a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Set the scrolling flags.
575a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
576a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @param flags bitwise int of {@link #SCROLL_FLAG_SCROLL},
577a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *             {@link #SCROLL_FLAG_EXIT_UNTIL_COLLAPSED}, {@link #SCROLL_FLAG_ENTER_ALWAYS}
578a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *             and {@link #SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED}.
579a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
580a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #getScrollFlags()
581a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
582149689d3a0b4165577470d7152112674d1d7f87cChris Banes         * @attr ref android.support.design.R.styleable#AppBarLayout_LayoutParams_layout_scrollFlags
583a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
58450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        public void setScrollFlags(@ScrollFlags int flags) {
585a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollFlags = flags;
586a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
587a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
588a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
589a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Returns the scrolling flags.
590a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
591a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #setScrollFlags(int)
592a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
593149689d3a0b4165577470d7152112674d1d7f87cChris Banes         * @attr ref android.support.design.R.styleable#AppBarLayout_LayoutParams_layout_scrollFlags
594a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
59550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @ScrollFlags
596a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public int getScrollFlags() {
597a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mScrollFlags;
598a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
599a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
600a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
601a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Set the interpolator to when scrolling the view associated with this
602a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * {@link LayoutParams}.
603a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
604a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @param interpolator the interpolator to use, or null to use normal 1-to-1 scrolling.
605a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
606149689d3a0b4165577470d7152112674d1d7f87cChris Banes         * @attr ref android.support.design.R.styleable#AppBarLayout_LayoutParams_layout_scrollInterpolator
607a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #getScrollInterpolator()
608a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
609a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void setScrollInterpolator(Interpolator interpolator) {
610a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollInterpolator = interpolator;
611a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
612a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
613a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
614a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Returns the {@link Interpolator} being used for scrolling the view associated with this
615a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * {@link LayoutParams}. Null indicates 'normal' 1-to-1 scrolling.
616a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
617149689d3a0b4165577470d7152112674d1d7f87cChris Banes         * @attr ref android.support.design.R.styleable#AppBarLayout_LayoutParams_layout_scrollInterpolator
618a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #setScrollInterpolator(Interpolator)
619a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
620a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public Interpolator getScrollInterpolator() {
621a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mScrollInterpolator;
622a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
623a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
624a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
625a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
626a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * The default {@link Behavior} for {@link AppBarLayout}. Implements the necessary nested
627a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * scroll handling with offsetting.
628a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
629a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public static class Behavior extends ViewOffsetBehavior<AppBarLayout> {
630d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        private static final int INVALID_POINTER = -1;
631e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        private static final int INVALID_POSITION = -1;
632e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
633e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        private int mOffsetDelta;
634a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
63550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        private boolean mSkipNestedPreScroll;
636631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private Runnable mFlingRunnable;
637631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private ScrollerCompat mScroller;
638631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
639631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private ValueAnimatorCompat mAnimator;
64050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
641e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        private int mOffsetToChildIndexOnLayout = INVALID_POSITION;
642e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        private boolean mOffsetToChildIndexOnLayoutIsMinHeight;
643e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        private float mOffsetToChildIndexOnLayoutPerc;
644e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
645d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        private boolean mIsBeingDragged;
646d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        private int mActivePointerId = INVALID_POINTER;
647d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        private int mLastMotionY;
648d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        private int mTouchSlop = -1;
649d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
650d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        private WeakReference<View> mLastNestedScrollingChildRef;
651d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
652a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public Behavior() {}
653a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
654a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public Behavior(Context context, AttributeSet attrs) {
655a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(context, attrs);
656a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
657a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
658a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
659ab809dd75ef2f73b312038f2c10473cfa5885a58Chris Banes        public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child,
660a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View directTargetChild, View target, int nestedScrollAxes) {
661f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes            // Return true if we're nested scrolling vertically, and we have scrollable children
662f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes            // and the scrolling view is big enough to scroll
663631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            final boolean started = (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0
664f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes                    && child.hasScrollableChildren()
665ab809dd75ef2f73b312038f2c10473cfa5885a58Chris Banes                    && parent.getHeight() - directTargetChild.getHeight() <= child.getHeight();
666631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
667631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (started && mAnimator != null) {
668631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // Cancel any offset animation
669631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mAnimator.cancel();
670631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
671631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
672d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            // A new nested scroll has started so clear out the previous ref
673d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            mLastNestedScrollingChildRef = null;
674d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
675631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            return started;
676a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
677a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
678a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
679a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
680a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View target, int dx, int dy, int[] consumed) {
68150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            if (dy != 0 && !mSkipNestedPreScroll) {
68250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                int min, max;
68350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                if (dy < 0) {
68450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // We're scrolling down
68550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    min = -child.getTotalScrollRange();
68650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    max = min + child.getDownNestedPreScrollRange();
68750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                } else {
68850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // We're scrolling up
68950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    min = -child.getUpNestedPreScrollRange();
69050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    max = 0;
69150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                }
69250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                consumed[1] = scroll(coordinatorLayout, child, dy, min, max);
693a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
694a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
695a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
696a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
697a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
698a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View target, int dxConsumed, int dyConsumed,
699a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int dxUnconsumed, int dyUnconsumed) {
70050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            if (dyUnconsumed < 0) {
70150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // If the scrolling view is scrolling down but not consuming, it's probably be at
70250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // the top of it's content
70350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                scroll(coordinatorLayout, child, dyUnconsumed,
70450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        -child.getDownNestedScrollRange(), 0);
70550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // Set the expanding flag so that onNestedPreScroll doesn't handle any events
70650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                mSkipNestedPreScroll = true;
70750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            } else {
70850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // As we're no longer handling nested scrolls, reset the skip flag
70950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                mSkipNestedPreScroll = false;
710a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
71150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        }
712a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
71350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @Override
71450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
71550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                View target) {
71650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            // Reset the skip flag
71750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            mSkipNestedPreScroll = false;
718d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            // Keep a reference to the previous nested scrolling child
719d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            mLastNestedScrollingChildRef = new WeakReference<>(target);
720d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        }
721d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
722d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        @Override
723d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child,
724d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                MotionEvent ev) {
725d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            if (mTouchSlop < 0) {
726d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
727d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            }
728d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
729d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            final int action = ev.getAction();
730d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
731d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            // Shortcut since we're being dragged
732d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            if (action == MotionEvent.ACTION_MOVE && mIsBeingDragged) {
733d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                return true;
734d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            }
735d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
736d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            switch (MotionEventCompat.getActionMasked(ev)) {
737d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                case MotionEvent.ACTION_MOVE: {
738d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    final int activePointerId = mActivePointerId;
739d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    if (activePointerId == INVALID_POINTER) {
740d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        // If we don't have a valid id, the touch down wasn't on content.
741d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        break;
742d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    }
743d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
744d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    if (pointerIndex == -1) {
745d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        break;
746d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    }
747d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
748d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    final int y = (int) MotionEventCompat.getY(ev, pointerIndex);
749d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    final int yDiff = Math.abs(y - mLastMotionY);
750d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    if (yDiff > mTouchSlop) {
751d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        mIsBeingDragged = true;
752d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        mLastMotionY = y;
753d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    }
754d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    break;
755d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                }
756d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
757d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                case MotionEvent.ACTION_DOWN: {
758d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    mIsBeingDragged = false;
759d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    final int x = (int) ev.getX();
760d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    final int y = (int) ev.getY();
761d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    if (parent.isPointInChildBounds(child, x, y) && canDragAppBarLayout()) {
762d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        mLastMotionY = y;
763d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
764d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    }
765d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    break;
766d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                }
767d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
768d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                case MotionEvent.ACTION_CANCEL:
769d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                case MotionEvent.ACTION_UP:
770d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    mIsBeingDragged = false;
771d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    mActivePointerId = INVALID_POINTER;
772d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    break;
773d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            }
774d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
775d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            return mIsBeingDragged;
776d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        }
777d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
778d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        @Override
779d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        public boolean onTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
780d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            if (mTouchSlop < 0) {
781d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
782d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            }
783d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
784d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            int x = (int) ev.getX();
785d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            int y = (int) ev.getY();
786d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
787d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            switch (MotionEventCompat.getActionMasked(ev)) {
788d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                case MotionEvent.ACTION_DOWN:
789d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    if (parent.isPointInChildBounds(child, x, y) && canDragAppBarLayout()) {
790d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        mLastMotionY = y;
791d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
792d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    } else {
793d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        return false;
794d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    }
795d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    break;
796d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                case MotionEvent.ACTION_MOVE:
797d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    final int activePointerIndex = MotionEventCompat.findPointerIndex(ev,
798d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                            mActivePointerId);
799d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    if (activePointerIndex == -1) {
800d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        return false;
801d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    }
802d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
803d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    y = (int) MotionEventCompat.getY(ev, activePointerIndex);
804d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
805d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    int dy = mLastMotionY - y;
806d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    if (!mIsBeingDragged && Math.abs(dy) > mTouchSlop) {
807d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        mIsBeingDragged = true;
808d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        if (dy > 0) {
809d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                            dy -= mTouchSlop;
810d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        } else {
811d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                            dy += mTouchSlop;
812d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        }
813d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    }
814d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
815d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    if (mIsBeingDragged) {
816d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        mLastMotionY = y;
817d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        // We're being dragged so scroll the ABL
818d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                        scroll(parent, child, dy, -child.getDownNestedScrollRange(), 0);
819d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    }
820d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    break;
821d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                case MotionEvent.ACTION_UP:
822d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                case MotionEvent.ACTION_CANCEL:
823d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    mIsBeingDragged = false;
824d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    mActivePointerId = INVALID_POINTER;
825d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                    break;
826d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            }
827d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
828d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            return true;
82950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        }
83050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
83150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @Override
832631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        public boolean onNestedFling(final CoordinatorLayout coordinatorLayout,
833631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                final AppBarLayout child, View target, float velocityX, float velocityY,
834631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                boolean consumed) {
835631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (!consumed) {
836631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // It has been consumed so let's fling ourselves
837631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                return fling(coordinatorLayout, child, -child.getTotalScrollRange(), 0, -velocityY);
838631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            } else {
839631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // If we're scrolling up and the child also consumed the fling. We'll fake scroll
840631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // upto our 'collapsed' offset
841631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                int targetScroll;
842631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                if (velocityY < 0) {
843631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    // We're scrolling down
844631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    targetScroll = -child.getTotalScrollRange()
845631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                            + child.getDownNestedPreScrollRange();
846631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
847631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    if (getTopBottomOffsetForScrollingSibling() > targetScroll) {
848631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        // If we're currently expanded more than the target scroll, we'll return false
849631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        // now. This is so that we don't 'scroll' the wrong way.
850631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        return false;
851631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    }
852631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                } else {
853631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    // We're scrolling up
854631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    targetScroll = -child.getUpNestedPreScrollRange();
855631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
856631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    if (getTopBottomOffsetForScrollingSibling() < targetScroll) {
857631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        // If we're currently expanded less than the target scroll, we'll return
858631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        // false now. This is so that we don't 'scroll' the wrong way.
859631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        return false;
860631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    }
861631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                }
862631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
863e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                if (getTopBottomOffsetForScrollingSibling() != targetScroll) {
864631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    animateOffsetTo(coordinatorLayout, child, targetScroll);
865631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    return true;
866631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                }
867631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
868631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
869631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            return false;
870631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
871631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
872631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private void animateOffsetTo(final CoordinatorLayout coordinatorLayout,
873631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                final AppBarLayout child, int offset) {
874631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mAnimator == null) {
875631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mAnimator = ViewUtils.createAnimator();
876631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mAnimator.setInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
877631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mAnimator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
878631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    @Override
879631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    public void onAnimationUpdate(ValueAnimatorCompat animator) {
880631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        setAppBarTopBottomOffset(coordinatorLayout, child,
881631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                                animator.getAnimatedIntValue());
882631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    }
883631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                });
884631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            } else {
885631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mAnimator.cancel();
886631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
887631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
888631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mAnimator.setIntValues(getTopBottomOffsetForScrollingSibling(), offset);
889631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mAnimator.start();
890631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
891631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
892631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private boolean fling(CoordinatorLayout coordinatorLayout, AppBarLayout layout, int minOffset,
893631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                int maxOffset, float velocityY) {
894631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mFlingRunnable != null) {
895631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                layout.removeCallbacks(mFlingRunnable);
896631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
897631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
898631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mScroller == null) {
899631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mScroller = ScrollerCompat.create(layout.getContext());
900631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
901631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
902631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mScroller.fling(
903e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    0, getTopBottomOffsetForScrollingSibling(), // curr
904631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    0, Math.round(velocityY), // velocity.
905631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    0, 0, // x
906631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    minOffset, maxOffset); // y
907631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
908631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mScroller.computeScrollOffset()) {
909631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mFlingRunnable = new FlingRunnable(coordinatorLayout, layout);
910631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                ViewCompat.postOnAnimation(layout, mFlingRunnable);
911631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                return true;
912631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            } else {
913631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mFlingRunnable = null;
914631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                return false;
915631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
916631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
917631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
918631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private class FlingRunnable implements Runnable {
919631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            private final CoordinatorLayout mParent;
920631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            private final AppBarLayout mLayout;
921631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
922631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            FlingRunnable(CoordinatorLayout parent, AppBarLayout layout) {
923631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mParent = parent;
924631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mLayout = layout;
925631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
926631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
927631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            @Override
928631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            public void run() {
929631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                if (mLayout != null && mScroller != null && mScroller.computeScrollOffset()) {
930631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    setAppBarTopBottomOffset(mParent, mLayout, mScroller.getCurrY());
931631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
932631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    // Post ourselves so that we run on the next animation
933631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    ViewCompat.postOnAnimation(mLayout, this);
934631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                }
935631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
936631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
937631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
938631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        @Override
9399995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes        public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout abl,
94050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                int layoutDirection) {
9419995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes            boolean handled = super.onLayoutChild(parent, abl, layoutDirection);
9429995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes
9439995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes            final int pendingAction = abl.getPendingAction();
9449995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes            if (pendingAction != PENDING_ACTION_NONE) {
9459995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                final boolean animate = (pendingAction & PENDING_ACTION_ANIMATE_ENABLED) != 0;
9469995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                if ((pendingAction & PENDING_ACTION_COLLAPSED) != 0) {
9479995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                    final int offset = -abl.getUpNestedPreScrollRange();
9489995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                    if (animate) {
9499995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                        animateOffsetTo(parent, abl, offset);
9509995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                    } else {
9519995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                        setAppBarTopBottomOffset(parent, abl, offset);
9529995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                    }
9539995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                } else if ((pendingAction & PENDING_ACTION_EXPANDED) != 0) {
9549995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                    if (animate) {
9559995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                        animateOffsetTo(parent, abl, 0);
9569995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                    } else {
9579995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                        setAppBarTopBottomOffset(parent, abl, 0);
9589995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                    }
9599995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                }
9609995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                // Finally reset the pending state
9619995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                abl.resetPendingAction();
9629995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes            } else if (mOffsetToChildIndexOnLayout >= 0) {
9639995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes                View child = abl.getChildAt(mOffsetToChildIndexOnLayout);
964e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                int offset = -child.getBottom();
965e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                if (mOffsetToChildIndexOnLayoutIsMinHeight) {
966e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    offset += ViewCompat.getMinimumHeight(child);
967e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                } else {
968e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    offset += Math.round(child.getHeight() * mOffsetToChildIndexOnLayoutPerc);
969e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                }
970e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                setTopAndBottomOffset(offset);
971e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                mOffsetToChildIndexOnLayout = INVALID_POSITION;
972e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
97350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
97450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            // Make sure we update the elevation
9759995f7bdb02dbe16155661545fd64046ad3d56c2Chris Banes            dispatchOffsetUpdates(abl);
97650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
97750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            return handled;
978a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
979a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
980a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int scroll(CoordinatorLayout coordinatorLayout, AppBarLayout appBarLayout,
98150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                int dy, int minOffset, int maxOffset) {
982a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return setAppBarTopBottomOffset(coordinatorLayout, appBarLayout,
983e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    getTopBottomOffsetForScrollingSibling() - dy, minOffset, maxOffset);
984a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
985a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
986d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        private boolean canDragAppBarLayout() {
987d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            if (mLastNestedScrollingChildRef != null) {
988d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                final View view = mLastNestedScrollingChildRef.get();
989d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes                return view != null && view.isShown() && !ViewCompat.canScrollVertically(view, -1);
990d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            }
991d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes            return false;
992d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        }
993d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
994631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        final int setAppBarTopBottomOffset(CoordinatorLayout coordinatorLayout,
995631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                AppBarLayout appBarLayout, int newOffset) {
996631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            return setAppBarTopBottomOffset(coordinatorLayout, appBarLayout, newOffset,
997631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    Integer.MIN_VALUE, Integer.MAX_VALUE);
998631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
999631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
1000631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        final int setAppBarTopBottomOffset(CoordinatorLayout coordinatorLayout,
100150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                AppBarLayout appBarLayout, int newOffset, int minOffset, int maxOffset) {
1002e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            final int curOffset = getTopBottomOffsetForScrollingSibling();
1003a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            int consumed = 0;
1004a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1005631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (minOffset != 0 && curOffset >= minOffset && curOffset <= maxOffset) {
1006631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // If we have some scrolling range, and we're currently within the min and max
1007631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // offsets, calculate a new offset
100850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                newOffset = MathUtils.constrain(newOffset, minOffset, maxOffset);
1009a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1010a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (curOffset != newOffset) {
1011e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    final int interpolatedOffset = appBarLayout.hasChildWithInterpolator()
1012e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                            ? interpolateOffset(appBarLayout, newOffset)
1013e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                            : newOffset;
1014e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1015e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    boolean offsetChanged = setTopAndBottomOffset(interpolatedOffset);
1016631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
1017a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Update how much dy we have consumed
1018a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    consumed = curOffset - newOffset;
1019a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Update the stored sibling offset
1020e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    mOffsetDelta = newOffset - interpolatedOffset;
1021a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1022a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    if (!offsetChanged && appBarLayout.hasChildWithInterpolator()) {
1023a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // If the offset hasn't changed and we're using an interpolated scroll
1024a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // then we need to keep any dependent views updated. CoL will do this for
1025a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // us when we move, but we need to do it manually when we don't (as an
1026a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // interpolated scroll may finish early).
1027a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        coordinatorLayout.dispatchDependentViewsChanged(appBarLayout);
1028a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    }
1029a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1030631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    // Dispatch the updates to any listeners
1031631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    dispatchOffsetUpdates(appBarLayout);
1032a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1033a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
1034a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1035a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return consumed;
1036a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1037a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1038631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private void dispatchOffsetUpdates(AppBarLayout layout) {
10396f730c0acfb10a929172ea2981a1aded0e39f5c7Chris Banes            final List<OnOffsetChangedListener> listeners = layout.mListeners;
104050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
1041631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // Iterate backwards through the list so that most recently added listeners
1042631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // get the first chance to decide
1043631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            for (int i = 0, z = listeners.size(); i < z; i++) {
10446f730c0acfb10a929172ea2981a1aded0e39f5c7Chris Banes                final OnOffsetChangedListener listener = listeners.get(i);
1045631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                if (listener != null) {
1046631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    listener.onOffsetChanged(layout, getTopAndBottomOffset());
1047a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1048a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
1049a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1050a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1051a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int interpolateOffset(AppBarLayout layout, final int offset) {
1052a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int absOffset = Math.abs(offset);
1053a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1054a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            for (int i = 0, z = layout.getChildCount(); i < z; i++) {
1055a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final View child = layout.getChildAt(i);
1056a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final AppBarLayout.LayoutParams childLp = (LayoutParams) child.getLayoutParams();
105750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                final Interpolator interpolator = childLp.getScrollInterpolator();
1058a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
105950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                if (absOffset >= child.getTop() && absOffset <= child.getBottom()) {
1060a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    if (interpolator != null) {
106150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        int childScrollableHeight = 0;
106250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        final int flags = childLp.getScrollFlags();
106350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
1064b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                            // We're set to scroll so add the child's height plus margin
1065b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                            childScrollableHeight += child.getHeight() + childLp.topMargin
1066b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                                    + childLp.bottomMargin;
1067b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes
106850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
1069b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                                // For a collapsing scroll, we to take the collapsed height
1070b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                                // into account.
107150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                                childScrollableHeight -= ViewCompat.getMinimumHeight(child);
107250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            }
107350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        }
107450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
107550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        if (childScrollableHeight > 0) {
107650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            final int offsetForView = absOffset - child.getTop();
107750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            final int interpolatedDiff = Math.round(childScrollableHeight *
107850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                                    interpolator.getInterpolation(
107950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                                            offsetForView / (float) childScrollableHeight));
108050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
108150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            return Integer.signum(offset) * (child.getTop() + interpolatedDiff);
108250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        }
1083a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    }
108450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
108550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // If we get to here then the view on the offset isn't suitable for interpolated
108650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // scrolling. So break out of the loop
108750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    break;
1088a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1089a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
1090a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1091a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return offset;
1092a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1093a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1094a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        final int getTopBottomOffsetForScrollingSibling() {
1095e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            return getTopAndBottomOffset() + mOffsetDelta;
1096e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        }
1097e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1098e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        @Override
1099e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        public Parcelable onSaveInstanceState(CoordinatorLayout parent, AppBarLayout appBarLayout) {
1100e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            final Parcelable superState = super.onSaveInstanceState(parent, appBarLayout);
1101e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            final int offset = getTopAndBottomOffset();
1102e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1103e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            // Try and find the first visible child...
1104e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            for (int i = 0, count = appBarLayout.getChildCount(); i < count; i++) {
1105e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                View child = appBarLayout.getChildAt(i);
1106e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                final int visBottom = child.getBottom() + offset;
1107e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1108e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                if (child.getTop() + offset <= 0 && visBottom >= 0) {
1109e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    final SavedState ss = new SavedState(superState);
1110e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    ss.firstVisibleChildIndex = i;
1111e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    ss.firstVisibileChildAtMinimumHeight =
1112e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                            visBottom == ViewCompat.getMinimumHeight(child);
1113e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    ss.firstVisibileChildPercentageShown = visBottom / (float) child.getHeight();
1114e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    return ss;
1115e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                }
1116e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
1117e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1118e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            // Else we'll just return the super state
1119e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            return superState;
1120e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        }
1121e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1122e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        @Override
1123e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        public void onRestoreInstanceState(CoordinatorLayout parent, AppBarLayout appBarLayout,
1124e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                Parcelable state) {
1125e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            if (state instanceof SavedState) {
1126e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                final SavedState ss = (SavedState) state;
1127e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                super.onRestoreInstanceState(parent, appBarLayout, ss.getSuperState());
1128e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                mOffsetToChildIndexOnLayout = ss.firstVisibleChildIndex;
1129e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                mOffsetToChildIndexOnLayoutPerc = ss.firstVisibileChildPercentageShown;
1130e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                mOffsetToChildIndexOnLayoutIsMinHeight = ss.firstVisibileChildAtMinimumHeight;
1131e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            } else {
1132e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                super.onRestoreInstanceState(parent, appBarLayout, state);
1133e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                mOffsetToChildIndexOnLayout = INVALID_POSITION;
1134e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
1135e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        }
1136e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1137e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        protected static class SavedState extends View.BaseSavedState {
1138e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            int firstVisibleChildIndex;
1139e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            float firstVisibileChildPercentageShown;
1140e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            boolean firstVisibileChildAtMinimumHeight;
1141e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1142e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            public SavedState(Parcel source) {
1143e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                super(source);
1144e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                firstVisibleChildIndex = source.readInt();
1145e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                firstVisibileChildPercentageShown = source.readFloat();
1146e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                firstVisibileChildAtMinimumHeight = source.readByte() != 0;
1147e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
1148e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1149e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            public SavedState(Parcelable superState) {
1150e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                super(superState);
1151e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
1152e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1153e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            @Override
1154e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            public void writeToParcel(Parcel dest, int flags) {
1155e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                super.writeToParcel(dest, flags);
1156e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                dest.writeInt(firstVisibleChildIndex);
1157e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                dest.writeFloat(firstVisibileChildPercentageShown);
1158e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                dest.writeByte((byte) (firstVisibileChildAtMinimumHeight ? 1 : 0));
1159e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
1160e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1161e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            public static final Parcelable.Creator<SavedState> CREATOR =
1162e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    new Parcelable.Creator<SavedState>() {
1163e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        @Override
1164e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        public SavedState createFromParcel(Parcel source) {
1165e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                            return new SavedState(source);
1166e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        }
1167e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
1168e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        @Override
1169e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        public SavedState[] newArray(int size) {
1170e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                            return new SavedState[size];
1171e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        }
1172e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    };
1173a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1174a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
1175a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1176a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
1177a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Behavior which should be used by {@link View}s which can scroll vertically and support
1178a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * nested scrolling to automatically scroll any {@link AppBarLayout} siblings.
1179a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
1180a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public static class ScrollingViewBehavior extends ViewOffsetBehavior<View> {
1181a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int mOverlayTop;
1182a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1183a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public ScrollingViewBehavior() {}
1184a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1185a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public ScrollingViewBehavior(Context context, AttributeSet attrs) {
1186a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(context, attrs);
1187a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1188a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            TypedArray a = context.obtainStyledAttributes(attrs,
1189a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    R.styleable.ScrollingViewBehavior_Params);
1190a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mOverlayTop = a.getDimensionPixelSize(
1191a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    R.styleable.ScrollingViewBehavior_Params_behavior_overlapTop, 0);
1192a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            a.recycle();
1193a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1194a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1195a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
1196a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
1197a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            // We depend on any AppBarLayouts
1198a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return dependency instanceof AppBarLayout;
1199a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1200a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1201a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
1202a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean onMeasureChild(CoordinatorLayout parent, View child,
1203a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int parentWidthMeasureSpec, int widthUsed,
1204a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int parentHeightMeasureSpec, int heightUsed) {
1205d6c56d929f7975eb6d80116e915ff5515a294c41Chris Banes            final int childLpHeight = child.getLayoutParams().height;
1206d6c56d929f7975eb6d80116e915ff5515a294c41Chris Banes            if (childLpHeight == LayoutParams.MATCH_PARENT
1207d6c56d929f7975eb6d80116e915ff5515a294c41Chris Banes                    || childLpHeight == LayoutParams.WRAP_CONTENT) {
1208d6c56d929f7975eb6d80116e915ff5515a294c41Chris Banes                // If the child's height is set to match_parent/wrap_content then measure it
1209d6c56d929f7975eb6d80116e915ff5515a294c41Chris Banes                // with the maximum visible height
1210a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1211a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final List<View> dependencies = parent.getDependencies(child);
1212a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (dependencies.isEmpty()) {
1213a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // If we don't have any dependencies, return false
1214a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return false;
1215a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1216a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1217a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final AppBarLayout appBar = findFirstAppBarLayout(dependencies);
12186ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                if (appBar != null && ViewCompat.isLaidOut(appBar)) {
12196ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    if (ViewCompat.getFitsSystemWindows(appBar)) {
12206ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                        // If the AppBarLayout is fitting system windows then we need to also,
12216ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                        // otherwise we'll get CoL's compatible layout functionality
12226ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                        ViewCompat.setFitsSystemWindows(child, true);
1223a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    }
1224a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
122555f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                    int availableHeight = MeasureSpec.getSize(parentHeightMeasureSpec);
122655f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                    if (availableHeight == 0) {
122755f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                        // If the measure spec doesn't specify a size, use the current height
122855f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                        availableHeight = parent.getHeight();
122955f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                    }
123055f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                    final int height = availableHeight - appBar.getMeasuredHeight()
1231f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes                            + appBar.getTotalScrollRange();
1232a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1233d6c56d929f7975eb6d80116e915ff5515a294c41Chris Banes                            childLpHeight == LayoutParams.MATCH_PARENT
1234d6c56d929f7975eb6d80116e915ff5515a294c41Chris Banes                                    ? MeasureSpec.EXACTLY
1235d6c56d929f7975eb6d80116e915ff5515a294c41Chris Banes                                    : MeasureSpec.AT_MOST);
1236a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1237a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Now measure the scrolling child with the correct height
1238a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    parent.onMeasureChild(child, parentWidthMeasureSpec,
1239a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            widthUsed, heightMeasureSpec, heightUsed);
1240a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1241a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return true;
1242a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1243a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
1244a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return false;
1245a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1246a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1247a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
1248a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
1249a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View dependency) {
1250a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final CoordinatorLayout.Behavior behavior =
1251a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ((CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior();
1252a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (behavior instanceof Behavior) {
1253a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // Offset the child so that it is below the app-bar (with any overlap)
1254a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1255a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final int appBarOffset = ((Behavior) behavior)
1256a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        .getTopBottomOffsetForScrollingSibling();
1257a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final int expandedMax = dependency.getHeight() - mOverlayTop;
1258a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final int collapsedMin = parent.getHeight() - child.getHeight();
1259a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1260a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (mOverlayTop != 0 && dependency instanceof AppBarLayout) {
1261a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // If we have an overlap top, and the dependency is an AppBarLayout, we control
1262a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // the offset ourselves based on the appbar's scroll progress. This is so that
1263a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // the scroll happens sequentially rather than linearly
1264a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    final int scrollRange = ((AppBarLayout) dependency).getTotalScrollRange();
1265a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    setTopAndBottomOffset(AnimationUtils.lerp(expandedMax, collapsedMin,
1266a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            Math.abs(appBarOffset) / (float) scrollRange));
1267a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                } else {
1268f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes                    setTopAndBottomOffset(dependency.getHeight() - mOverlayTop + appBarOffset);
1269a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1270a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
1271a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return false;
1272a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1273a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1274a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
1275a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Set the distance that this view should overlap any {@link AppBarLayout}.
1276a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
1277a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @param overlayTop the distance in px
1278a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
1279a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void setOverlayTop(int overlayTop) {
1280a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mOverlayTop = overlayTop;
1281a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1282a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1283a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
1284a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Returns the distance that this view should overlap any {@link AppBarLayout}.
1285a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
1286a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public int getOverlayTop() {
1287a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mOverlayTop;
1288a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1289a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1290a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private static AppBarLayout findFirstAppBarLayout(List<View> views) {
1291a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            for (int i = 0, z = views.size(); i < z; i++) {
1292a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View view = views.get(i);
1293a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (view instanceof AppBarLayout) {
1294a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return (AppBarLayout) view;
1295a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1296a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
1297a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return null;
1298a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1299a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
1300a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes}
1301