AppBarLayout.java revision b263b91ba75dc1a7855186e8b0e9cf75d46a6b8d
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;
25a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.support.v4.view.ViewCompat;
266ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banesimport android.support.v4.view.WindowInsetsCompat;
27631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport android.support.v4.widget.ScrollerCompat;
28a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.util.AttributeSet;
29a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.View;
30a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.ViewGroup;
31a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.animation.Interpolator;
32a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.widget.LinearLayout;
33a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
3450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banesimport java.lang.annotation.Retention;
3550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banesimport java.lang.annotation.RetentionPolicy;
36631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport java.lang.ref.WeakReference;
37631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport java.util.ArrayList;
38631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport java.util.Iterator;
39a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport java.util.List;
40a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
41a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes/**
42a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * AppBarLayout is a vertical {@link LinearLayout} which implements many of the features of
439fb154338a62edc2c57dc036895199d6f1769400Chris Banes * material designs app bar concept, namely scrolling gestures.
44a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <p>
45a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Children should provide their desired scrolling behavior through
46a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * {@link LayoutParams#setScrollFlags(int)} and the associated layout xml attribute:
47a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * {@code app:layout_scrollFlags}.
48a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
49a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <p>
50a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * This view depends heavily on being used as a direct child within a {@link CoordinatorLayout}.
51a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * If you use AppBarLayout within a different {@link ViewGroup}, most of it's functionality will
52a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * not work.
53a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <p>
549fb154338a62edc2c57dc036895199d6f1769400Chris Banes * AppBarLayout also requires a separate scrolling sibling in order to know when to scroll.
559fb154338a62edc2c57dc036895199d6f1769400Chris Banes * The binding is done through the {@link ScrollingViewBehavior} behavior class, meaning that you
569fb154338a62edc2c57dc036895199d6f1769400Chris Banes * should set your scrolling view's behavior to be an instance of {@link ScrollingViewBehavior}.
579fb154338a62edc2c57dc036895199d6f1769400Chris Banes * A string resource containing the full class name is available.
58a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
59a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <pre>
60a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * &lt;android.support.design.widget.CoordinatorLayout
61a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         xmlns:android=&quot;http://schemas.android.com/apk/res/android";
62a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         xmlns:app=&quot;http://schemas.android.com/apk/res-auto";
63a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         android:layout_width=&quot;match_parent&quot;
64a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         android:layout_height=&quot;match_parent&quot;&gt;
65a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
66a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;android.support.v4.widget.NestedScrollView
67a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_width=&quot;match_parent&quot;
68a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_height=&quot;match_parent&quot;
69a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             app:layout_behavior=&quot;@string/appbar_scrolling_view_behavior&quot;&gt;
70a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
71a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         &lt;!-- Your scrolling content --&gt;
72a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
73a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;/android.support.v4.widget.NestedScrollView&gt;
74a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
75a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;android.support.design.widget.AppBarLayout
76a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_height=&quot;wrap_content&quot;
77a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_width=&quot;match_parent&quot;&gt;
78a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
79a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         &lt;android.support.v7.widget.Toolbar
80a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 ...
81a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 app:layout_scrollFlags=&quot;scroll|enterAlways&quot;/&gt;
82a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
83a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         &lt;android.support.design.widget.TabLayout
84a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 ...
85a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 app:layout_scrollFlags=&quot;scroll|enterAlways&quot;/&gt;
86a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
87a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;/android.support.design.widget.AppBarLayout&gt;
88a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
89a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * &lt;/android.support.design.widget.CoordinatorLayout&gt;
90a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * </pre>
91a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
92a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * @see <a href="http://www.google.com/design/spec/layout/structure.html#structure-app-bar">
93a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     http://www.google.com/design/spec/layout/structure.html#structure-app-bar</a>
94a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes */
95a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
96a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banespublic class AppBarLayout extends LinearLayout {
97a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
98a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
99631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * Interface definition for a callback to be invoked when an {@link AppBarLayout}'s vertical
100631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * offset changes.
101a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
102631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public interface OnOffsetChangedListener {
103a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
104a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Called when the {@link AppBarLayout}'s layout offset has been changed. This allows
105a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * child views to implement custom behavior based on the offset (for instance pinning a
106a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * view at a certain y value).
107a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
108631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes         * @param appBarLayout the {@link AppBarLayout} which offset has changed
10950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * @param verticalOffset the vertical offset for the parent {@link AppBarLayout}, in px
110a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
111631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset);
112a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
113a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
114a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private static final int INVALID_SCROLL_RANGE = -1;
115a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
116a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private int mTotalScrollRange = INVALID_SCROLL_RANGE;
117a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private int mDownPreScrollRange = INVALID_SCROLL_RANGE;
118a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private int mDownScrollRange = INVALID_SCROLL_RANGE;
119a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
120a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    boolean mHaveChildWithInterpolator;
121a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
12250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    private float mTargetElevation;
12350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
1246ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes    private WindowInsetsCompat mLastInsets;
1256ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes
126631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private final List<WeakReference<OnOffsetChangedListener>> mListeners;
127631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
128a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public AppBarLayout(Context context) {
129a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        this(context, null);
130a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
131a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
132a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public AppBarLayout(Context context, AttributeSet attrs) {
133a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        super(context, attrs);
134a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        setOrientation(VERTICAL);
13550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
13650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppBarLayout,
13750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                0, R.style.Widget_Design_AppBarLayout);
13850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        mTargetElevation = a.getDimensionPixelSize(R.styleable.AppBarLayout_elevation, 0);
13981520564f3dd783136e025174021ba4eabd6ff3cChris Banes        setBackgroundDrawable(a.getDrawable(R.styleable.AppBarLayout_android_background));
14050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        a.recycle();
14150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
14250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        // Use the bounds view outline provider so that we cast a shadow, even without a background
14350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        ViewUtils.setBoundsViewOutlineProvider(this);
144631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
145631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mListeners = new ArrayList<>();
146631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
147631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        ViewCompat.setElevation(this, mTargetElevation);
1486ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes
1496ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        ViewCompat.setOnApplyWindowInsetsListener(this,
1506ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                new android.support.v4.view.OnApplyWindowInsetsListener() {
1516ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    @Override
1526ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    public WindowInsetsCompat onApplyWindowInsets(View v,
1536ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                            WindowInsetsCompat insets) {
1546ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                        setWindowInsets(insets);
1556ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                        return insets.consumeSystemWindowInsets();
1566ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    }
1576ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                });
158631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
159631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
160631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    /**
161631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * Add a listener that will be called when the offset of this {@link AppBarLayout} changes.
162631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     *
163631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * @param listener The listener that will be called when the offset changes.]
164631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     *
165631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * @see #removeOnOffsetChangedListener(OnOffsetChangedListener)
166631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     */
167631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void addOnOffsetChangedListener(OnOffsetChangedListener listener) {
168631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        for (int i = 0, z = mListeners.size(); i < z; i++) {
169631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            final WeakReference<OnOffsetChangedListener> ref = mListeners.get(i);
170631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (ref != null && ref.get() == listener) {
171631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // Listener already added
172631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                return;
173631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
174631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
175631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mListeners.add(new WeakReference<>(listener));
176631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
177631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
178631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    /**
179631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * Remove the previously added {@link OnOffsetChangedListener}.
180631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     *
181631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * @param listener the listener to remove.
182631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     */
183631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void removeOnOffsetChangedListener(OnOffsetChangedListener listener) {
184631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        final Iterator<WeakReference<OnOffsetChangedListener>> i = mListeners.iterator();
185631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        while (i.hasNext()) {
186631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            final WeakReference<OnOffsetChangedListener> ref = i.next();
187631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            final OnOffsetChangedListener item = ref.get();
188631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (item == listener || item == null) {
189631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // If the item is null, or is our given listener, remove
190631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                i.remove();
191631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
192631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
193a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
194a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
195a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
196a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected void onLayout(boolean changed, int l, int t, int r, int b) {
197a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        super.onLayout(changed, l, t, r, b);
198a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
199a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        // Invalidate the scroll ranges
200a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mTotalScrollRange = INVALID_SCROLL_RANGE;
201a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mDownPreScrollRange = INVALID_SCROLL_RANGE;
202a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mDownPreScrollRange = INVALID_SCROLL_RANGE;
203a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
204a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mHaveChildWithInterpolator = false;
205a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        for (int i = 0, z = getChildCount(); i < z; i++) {
206a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
207a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams childLp = (LayoutParams) child.getLayoutParams();
208a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final Interpolator interpolator = childLp.getScrollInterpolator();
209a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
210a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (interpolator != null) {
211a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                mHaveChildWithInterpolator = true;
212a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
213a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
214a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
215a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
216a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
217a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
218a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public void setOrientation(int orientation) {
219a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (orientation != VERTICAL) {
220a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            throw new IllegalArgumentException("AppBarLayout is always vertical and does"
221a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    + " not support horizontal orientation");
222a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
223a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        super.setOrientation(orientation);
224a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
225a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
226a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
227a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
228a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return p instanceof LayoutParams;
229a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
230a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
231a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
232a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected LayoutParams generateDefaultLayoutParams() {
233a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
234a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
235a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
236a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
237a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public LayoutParams generateLayoutParams(AttributeSet attrs) {
238a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return new LayoutParams(getContext(), attrs);
239a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
240a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
241a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
242a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
243a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (p instanceof LinearLayout.LayoutParams) {
244a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return new LayoutParams((LinearLayout.LayoutParams) p);
245a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        } else if (p instanceof MarginLayoutParams) {
246a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return new LayoutParams((MarginLayoutParams) p);
247a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
248a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return new LayoutParams(p);
249a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
250a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
251a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final boolean hasChildWithInterpolator() {
252a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return mHaveChildWithInterpolator;
253a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
254a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
255a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
2566ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes     * Returns the scroll range of all children.
257a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     *
258a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * @return the scroll range in px
259a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
2606ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes    public final int getTotalScrollRange() {
261a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (mTotalScrollRange != INVALID_SCROLL_RANGE) {
262a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mTotalScrollRange;
263a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
264a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
265a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int range = 0;
266a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        for (int i = 0, z = getChildCount(); i < z; i++) {
267a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
268a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
269a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int childHeight = ViewCompat.isLaidOut(child)
270a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ? child.getHeight()
271a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    : child.getMeasuredHeight();
272a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int flags = lp.mScrollFlags;
273a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
274a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
275a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // We're set to scroll so add the child's height
276b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                range += childHeight + lp.topMargin + lp.bottomMargin;
277a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
278a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
279a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // For a collapsing scroll, we to take the collapsed height into account.
2806ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    // We also break straight away since later views can't scroll beneath
281a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // us
2826ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    range -= ViewCompat.getMinimumHeight(child);
2836ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    break;
284a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
285a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            } else {
286a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // As soon as a view doesn't have the scroll flag, we end the range calculation.
287a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // This is because views below can not scroll under a fixed view.
288a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
289a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
290a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
2916ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        final int top = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
2926ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        return mTotalScrollRange = (range - top);
293a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
294a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
295a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final boolean hasScrollableChildren() {
296a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return getTotalScrollRange() != 0;
297a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
298a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
299a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
300a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Return the scroll range when scrolling up from a nested pre-scroll.
301a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
302a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final int getUpNestedPreScrollRange() {
30350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        return getTotalScrollRange();
304a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
305a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
306a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
307a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Return the scroll range when scrolling down from a nested pre-scroll.
308a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
309a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final int getDownNestedPreScrollRange() {
310a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (mDownPreScrollRange != INVALID_SCROLL_RANGE) {
311a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            // If we already have a valid value, return it
312a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mDownPreScrollRange;
313a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
314a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
315a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int range = 0;
316a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        for (int i = getChildCount() - 1; i >= 0; i--) {
317a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
318a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
319a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int childHeight = ViewCompat.isLaidOut(child)
320a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ? child.getHeight()
321a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    : child.getMeasuredHeight();
322a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int flags = lp.mScrollFlags;
323a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
324a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if ((flags & LayoutParams.FLAG_QUICK_RETURN) == LayoutParams.FLAG_QUICK_RETURN) {
325b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                // First take the margin into account
326b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                range += lp.topMargin + lp.bottomMargin;
327a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // The view has the quick return flag combination...
328a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if ((flags & LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED) != 0) {
329a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // If they're set to enter collapsed, use the minimum height
330a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    range += ViewCompat.getMinimumHeight(child);
331a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                } else {
332a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Else use the full height
333a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    range += childHeight;
334a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
335a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            } else if (range > 0) {
336a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // If we've hit an non-quick return scrollable view, and we've already hit a
337a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // quick return view, return now
338a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
339a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
340a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
341a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return mDownPreScrollRange = range;
342a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
343a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
344a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
345a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Return the scroll range when scrolling down from a nested scroll.
346a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
347a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final int getDownNestedScrollRange() {
348a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (mDownScrollRange != INVALID_SCROLL_RANGE) {
349a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            // If we already have a valid value, return it
350a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mDownScrollRange;
351a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
352a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
353a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int range = 0;
354c1ce4f6cf4d99d6856c4259bf1bb1cb56f604737Chris Banes        for (int i = 0, z = getChildCount(); i < z; i++) {
355a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
356a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
357b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes            int childHeight = ViewCompat.isLaidOut(child)
358a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ? child.getHeight()
359a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    : child.getMeasuredHeight();
360b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes            childHeight += lp.topMargin + lp.bottomMargin;
361a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
362a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int flags = lp.mScrollFlags;
363a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
364a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
365a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // We're set to scroll so add the child's height
366a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                range += childHeight;
367a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
368a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
369a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // For a collapsing exit scroll, we to take the collapsed height into account.
370a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // We also return the range straight away since later views can't scroll
371a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // beneath us
372a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return range - ViewCompat.getMinimumHeight(child);
373a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
374a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            } else {
375a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // As soon as a view doesn't have the scroll flag, we end the range calculation.
376a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // This is because views below can not scroll under a fixed view.
377a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
378a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
379a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
380a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return mDownScrollRange = range;
381a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
382a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
38350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    final int getMinimumHeightForVisibleOverlappingContent() {
3846ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        final int topInset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
38550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        final int minHeight = ViewCompat.getMinimumHeight(this);
38650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        if (minHeight != 0) {
38750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            // If this layout has a min height, use it (doubled)
3886ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes            return (minHeight * 2) + topInset;
38950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        }
39050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
39150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        // Otherwise, we'll use twice the min height of our last child
39250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        final int childCount = getChildCount();
39350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        return childCount >= 1
3946ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                ? (ViewCompat.getMinimumHeight(getChildAt(childCount - 1)) * 2) + topInset
39550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                : 0;
39650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    }
39750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
39850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    /**
399631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * Set the elevation value to use when this {@link AppBarLayout} should be elevated
400631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * above content.
401631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * <p>
402631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * This method does not do anything itself. A typical use for this method is called from within
403631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * an {@link OnOffsetChangedListener} when the offset has changed in such a way to require an
404631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * elevation change.
405631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     *
406631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * @param elevation the elevation value to use.
407631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     *
408631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * @see ViewCompat#setElevation(View, float)
40950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes     */
410631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setTargetElevation(float elevation) {
411631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mTargetElevation = elevation;
412631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
413631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
414631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    /**
415631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * Returns the elevation value to use when this {@link AppBarLayout} should be elevated
416631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     * above content.
417631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes     */
418631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public float getTargetElevation() {
41950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        return mTargetElevation;
42050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    }
42150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
4226ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes    private void setWindowInsets(WindowInsetsCompat insets) {
4236ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        // Invalidate the total scroll range...
4246ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        mTotalScrollRange = INVALID_SCROLL_RANGE;
4256ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        mLastInsets = insets;
4266ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes
4276ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        // Now dispatch them to our children
4286ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        for (int i = 0, z = getChildCount(); i < z; i++) {
4296ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes            final View child = getChildAt(i);
4306ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes            insets = ViewCompat.dispatchApplyWindowInsets(child, insets);
4316ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes            if (insets.isConsumed()) {
4326ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                break;
4336ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes            }
4346ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes        }
4356ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes    }
4366ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes
437a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public static class LayoutParams extends LinearLayout.LayoutParams {
43850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
43950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        /** @hide */
44050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @IntDef(flag=true, value={
44150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_SCROLL,
44250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_EXIT_UNTIL_COLLAPSED,
44350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_ENTER_ALWAYS,
44450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED
44550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        })
44650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @Retention(RetentionPolicy.SOURCE)
44750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        public @interface ScrollFlags {}
44850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
449a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
450a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * The view will be scroll in direct relation to scroll events. This flag needs to be
451a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * set for any of the other flags to take effect. If any sibling views
452a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * before this one do not have this flag, then this value has no effect.
453a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
454a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_SCROLL = 0x1;
455a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
456a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
457a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * When exiting (scrolling off screen) the view will be scrolled until it is
458a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * 'collapsed'. The collapsed height is defined by the view's minimum height.
459a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
460a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see ViewCompat#getMinimumHeight(View)
461a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see View#setMinimumHeight(int)
462a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
463a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 0x2;
464a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
465a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
466a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * When entering (scrolling on screen) the view will scroll on any downwards
467a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * scroll event, regardless of whether the scrolling view is also scrolling. This
468a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * is commonly referred to as the 'quick return' pattern.
469a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
470a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_ENTER_ALWAYS = 0x4;
471a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
472a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
473a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * An additional flag for 'enterAlways' which modifies the returning view to
474a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * only initially scroll back to it's collapsed height. Once the scrolling view has
475a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * reached the end of it's scroll range, the remainder of this view will be scrolled
476a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * into view. The collapsed height is defined by the view's minimum height.
477a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
478a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see ViewCompat#getMinimumHeight(View)
479a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see View#setMinimumHeight(int)
480a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
481a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 0x8;
482a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
483a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
484a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Internal flag which allows quick checking of 'quick return'
485a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
486a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        static final int FLAG_QUICK_RETURN = SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS;
487a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
488a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int mScrollFlags = SCROLL_FLAG_SCROLL;
489a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        Interpolator mScrollInterpolator;
490a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
491a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(Context c, AttributeSet attrs) {
492a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(c, attrs);
493a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.AppBarLayout_LayoutParams);
494a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollFlags = a.getInt(R.styleable.AppBarLayout_LayoutParams_layout_scrollFlags, 0);
495a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (a.hasValue(R.styleable.AppBarLayout_LayoutParams_layout_scrollInterpolator)) {
496a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int resId = a.getResourceId(
497a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        R.styleable.AppBarLayout_LayoutParams_layout_scrollInterpolator, 0);
498a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                mScrollInterpolator = android.view.animation.AnimationUtils.loadInterpolator(
499a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        c, resId);
500a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
501a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            a.recycle();
502a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
503a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
504a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(int width, int height) {
505a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(width, height);
506a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
507a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
508a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(int width, int height, float weight) {
509a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(width, height, weight);
510a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
511a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
512a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(ViewGroup.LayoutParams p) {
513a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(p);
514a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
515a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
516a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(MarginLayoutParams source) {
517a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(source);
518a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
519a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
520a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(LinearLayout.LayoutParams source) {
521a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(source);
522a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
523a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
524a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(LayoutParams source) {
525a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(source);
526a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollFlags = source.mScrollFlags;
527a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollInterpolator = source.mScrollInterpolator;
528a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
529a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
530a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
531a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Set the scrolling flags.
532a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
533a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @param flags bitwise int of {@link #SCROLL_FLAG_SCROLL},
534a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *             {@link #SCROLL_FLAG_EXIT_UNTIL_COLLAPSED}, {@link #SCROLL_FLAG_ENTER_ALWAYS}
535a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *             and {@link #SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED}.
536a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
537a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #getScrollFlags()
538a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
539149689d3a0b4165577470d7152112674d1d7f87cChris Banes         * @attr ref android.support.design.R.styleable#AppBarLayout_LayoutParams_layout_scrollFlags
540a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
54150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        public void setScrollFlags(@ScrollFlags int flags) {
542a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollFlags = flags;
543a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
544a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
545a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
546a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Returns the scrolling flags.
547a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
548a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #setScrollFlags(int)
549a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
550149689d3a0b4165577470d7152112674d1d7f87cChris Banes         * @attr ref android.support.design.R.styleable#AppBarLayout_LayoutParams_layout_scrollFlags
551a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
55250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @ScrollFlags
553a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public int getScrollFlags() {
554a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mScrollFlags;
555a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
556a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
557a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
558a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Set the interpolator to when scrolling the view associated with this
559a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * {@link LayoutParams}.
560a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
561a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @param interpolator the interpolator to use, or null to use normal 1-to-1 scrolling.
562a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
563149689d3a0b4165577470d7152112674d1d7f87cChris Banes         * @attr ref android.support.design.R.styleable#AppBarLayout_LayoutParams_layout_scrollInterpolator
564a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #getScrollInterpolator()
565a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
566a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void setScrollInterpolator(Interpolator interpolator) {
567a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollInterpolator = interpolator;
568a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
569a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
570a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
571a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Returns the {@link Interpolator} being used for scrolling the view associated with this
572a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * {@link LayoutParams}. Null indicates 'normal' 1-to-1 scrolling.
573a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
574149689d3a0b4165577470d7152112674d1d7f87cChris Banes         * @attr ref android.support.design.R.styleable#AppBarLayout_LayoutParams_layout_scrollInterpolator
575a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #setScrollInterpolator(Interpolator)
576a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
577a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public Interpolator getScrollInterpolator() {
578a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mScrollInterpolator;
579a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
580a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
581a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
582a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
583a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * The default {@link Behavior} for {@link AppBarLayout}. Implements the necessary nested
584a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * scroll handling with offsetting.
585a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
586a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public static class Behavior extends ViewOffsetBehavior<AppBarLayout> {
587e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        private static final int INVALID_POSITION = -1;
588e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
589e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        private int mOffsetDelta;
590a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
59150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        private boolean mSkipNestedPreScroll;
592631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private Runnable mFlingRunnable;
593631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private ScrollerCompat mScroller;
594631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
595631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private ValueAnimatorCompat mAnimator;
59650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
597e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        private int mOffsetToChildIndexOnLayout = INVALID_POSITION;
598e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        private boolean mOffsetToChildIndexOnLayoutIsMinHeight;
599e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        private float mOffsetToChildIndexOnLayoutPerc;
600e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
601a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public Behavior() {}
602a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
603a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public Behavior(Context context, AttributeSet attrs) {
604a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(context, attrs);
605a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
606a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
607a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
608a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
609a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View directTargetChild, View target, int nestedScrollAxes) {
610f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes            // Return true if we're nested scrolling vertically, and we have scrollable children
611f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes            // and the scrolling view is big enough to scroll
612631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            final boolean started = (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0
613f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes                    && child.hasScrollableChildren()
614f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes                    && coordinatorLayout.getHeight() - target.getHeight() <= child.getHeight();
615631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
616631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (started && mAnimator != null) {
617631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // Cancel any offset animation
618631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mAnimator.cancel();
619631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
620631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
621631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            return started;
622a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
623a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
624a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
625a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
626a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View target, int dx, int dy, int[] consumed) {
62750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            if (dy != 0 && !mSkipNestedPreScroll) {
62850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                int min, max;
62950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                if (dy < 0) {
63050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // We're scrolling down
63150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    min = -child.getTotalScrollRange();
63250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    max = min + child.getDownNestedPreScrollRange();
63350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                } else {
63450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // We're scrolling up
63550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    min = -child.getUpNestedPreScrollRange();
63650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    max = 0;
63750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                }
63850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                consumed[1] = scroll(coordinatorLayout, child, dy, min, max);
639a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
640a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
641a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
642a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
643a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
644a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View target, int dxConsumed, int dyConsumed,
645a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int dxUnconsumed, int dyUnconsumed) {
64650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            if (dyUnconsumed < 0) {
64750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // If the scrolling view is scrolling down but not consuming, it's probably be at
64850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // the top of it's content
64950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                scroll(coordinatorLayout, child, dyUnconsumed,
65050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        -child.getDownNestedScrollRange(), 0);
65150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // Set the expanding flag so that onNestedPreScroll doesn't handle any events
65250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                mSkipNestedPreScroll = true;
65350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            } else {
65450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // As we're no longer handling nested scrolls, reset the skip flag
65550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                mSkipNestedPreScroll = false;
656a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
65750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        }
658a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
65950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @Override
66050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
66150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                View target) {
66250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            // Reset the skip flag
66350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            mSkipNestedPreScroll = false;
66450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        }
66550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
66650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @Override
667631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        public boolean onNestedFling(final CoordinatorLayout coordinatorLayout,
668631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                final AppBarLayout child, View target, float velocityX, float velocityY,
669631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                boolean consumed) {
670631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (!consumed) {
671631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // It has been consumed so let's fling ourselves
672631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                return fling(coordinatorLayout, child, -child.getTotalScrollRange(), 0, -velocityY);
673631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            } else {
674631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // If we're scrolling up and the child also consumed the fling. We'll fake scroll
675631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // upto our 'collapsed' offset
676631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                int targetScroll;
677631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                if (velocityY < 0) {
678631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    // We're scrolling down
679631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    targetScroll = -child.getTotalScrollRange()
680631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                            + child.getDownNestedPreScrollRange();
681631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
682631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    if (getTopBottomOffsetForScrollingSibling() > targetScroll) {
683631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        // If we're currently expanded more than the target scroll, we'll return false
684631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        // now. This is so that we don't 'scroll' the wrong way.
685631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        return false;
686631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    }
687631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                } else {
688631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    // We're scrolling up
689631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    targetScroll = -child.getUpNestedPreScrollRange();
690631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
691631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    if (getTopBottomOffsetForScrollingSibling() < targetScroll) {
692631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        // If we're currently expanded less than the target scroll, we'll return
693631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        // false now. This is so that we don't 'scroll' the wrong way.
694631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        return false;
695631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    }
696631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                }
697631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
698e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                if (getTopBottomOffsetForScrollingSibling() != targetScroll) {
699631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    animateOffsetTo(coordinatorLayout, child, targetScroll);
700631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    return true;
701631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                }
702631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
703631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
704631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            return false;
705631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
706631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
707631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private void animateOffsetTo(final CoordinatorLayout coordinatorLayout,
708631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                final AppBarLayout child, int offset) {
709631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mAnimator == null) {
710631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mAnimator = ViewUtils.createAnimator();
711631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mAnimator.setInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
712631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mAnimator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
713631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    @Override
714631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    public void onAnimationUpdate(ValueAnimatorCompat animator) {
715631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                        setAppBarTopBottomOffset(coordinatorLayout, child,
716631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                                animator.getAnimatedIntValue());
717631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    }
718631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                });
719631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            } else {
720631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mAnimator.cancel();
721631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
722631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
723631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mAnimator.setIntValues(getTopBottomOffsetForScrollingSibling(), offset);
724631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mAnimator.start();
725631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
726631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
727631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private boolean fling(CoordinatorLayout coordinatorLayout, AppBarLayout layout, int minOffset,
728631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                int maxOffset, float velocityY) {
729631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mFlingRunnable != null) {
730631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                layout.removeCallbacks(mFlingRunnable);
731631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
732631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
733631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mScroller == null) {
734631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mScroller = ScrollerCompat.create(layout.getContext());
735631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
736631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
737631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mScroller.fling(
738e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    0, getTopBottomOffsetForScrollingSibling(), // curr
739631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    0, Math.round(velocityY), // velocity.
740631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    0, 0, // x
741631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    minOffset, maxOffset); // y
742631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
743631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mScroller.computeScrollOffset()) {
744631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mFlingRunnable = new FlingRunnable(coordinatorLayout, layout);
745631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                ViewCompat.postOnAnimation(layout, mFlingRunnable);
746631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                return true;
747631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            } else {
748631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mFlingRunnable = null;
749631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                return false;
750631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
751631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
752631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
753631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private class FlingRunnable implements Runnable {
754631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            private final CoordinatorLayout mParent;
755631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            private final AppBarLayout mLayout;
756631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
757631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            FlingRunnable(CoordinatorLayout parent, AppBarLayout layout) {
758631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mParent = parent;
759631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mLayout = layout;
760631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
761631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
762631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            @Override
763631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            public void run() {
764631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                if (mLayout != null && mScroller != null && mScroller.computeScrollOffset()) {
765631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    setAppBarTopBottomOffset(mParent, mLayout, mScroller.getCurrY());
766631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
767631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    // Post ourselves so that we run on the next animation
768631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    ViewCompat.postOnAnimation(mLayout, this);
769631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                }
770631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
771631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
772631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
773631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        @Override
774e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout appBarLayout,
77550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                int layoutDirection) {
776e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            boolean handled = super.onLayoutChild(parent, appBarLayout, layoutDirection);
777e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
778e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            if (mOffsetToChildIndexOnLayout >= 0) {
779e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                View child = appBarLayout.getChildAt(mOffsetToChildIndexOnLayout);
780e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                int offset = -child.getBottom();
781e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                if (mOffsetToChildIndexOnLayoutIsMinHeight) {
782e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    offset += ViewCompat.getMinimumHeight(child);
783e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                } else {
784e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    offset += Math.round(child.getHeight() * mOffsetToChildIndexOnLayoutPerc);
785e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                }
786e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                setTopAndBottomOffset(offset);
787e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                mOffsetToChildIndexOnLayout = INVALID_POSITION;
788e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
78950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
79050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            // Make sure we update the elevation
791e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            dispatchOffsetUpdates(appBarLayout);
79250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
79350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            return handled;
794a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
795a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
796a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int scroll(CoordinatorLayout coordinatorLayout, AppBarLayout appBarLayout,
79750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                int dy, int minOffset, int maxOffset) {
798a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return setAppBarTopBottomOffset(coordinatorLayout, appBarLayout,
799e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    getTopBottomOffsetForScrollingSibling() - dy, minOffset, maxOffset);
800a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
801a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
802631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        final int setAppBarTopBottomOffset(CoordinatorLayout coordinatorLayout,
803631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                AppBarLayout appBarLayout, int newOffset) {
804631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            return setAppBarTopBottomOffset(coordinatorLayout, appBarLayout, newOffset,
805631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    Integer.MIN_VALUE, Integer.MAX_VALUE);
806631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
807631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
808631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        final int setAppBarTopBottomOffset(CoordinatorLayout coordinatorLayout,
80950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                AppBarLayout appBarLayout, int newOffset, int minOffset, int maxOffset) {
810e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            final int curOffset = getTopBottomOffsetForScrollingSibling();
811a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            int consumed = 0;
812a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
813631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (minOffset != 0 && curOffset >= minOffset && curOffset <= maxOffset) {
814631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // If we have some scrolling range, and we're currently within the min and max
815631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                // offsets, calculate a new offset
81650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                newOffset = MathUtils.constrain(newOffset, minOffset, maxOffset);
817a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
818a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (curOffset != newOffset) {
819e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    final int interpolatedOffset = appBarLayout.hasChildWithInterpolator()
820e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                            ? interpolateOffset(appBarLayout, newOffset)
821e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                            : newOffset;
822e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
823e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    boolean offsetChanged = setTopAndBottomOffset(interpolatedOffset);
824631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
825a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Update how much dy we have consumed
826a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    consumed = curOffset - newOffset;
827a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Update the stored sibling offset
828e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    mOffsetDelta = newOffset - interpolatedOffset;
829a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
830a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    if (!offsetChanged && appBarLayout.hasChildWithInterpolator()) {
831a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // If the offset hasn't changed and we're using an interpolated scroll
832a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // then we need to keep any dependent views updated. CoL will do this for
833a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // us when we move, but we need to do it manually when we don't (as an
834a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // interpolated scroll may finish early).
835a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        coordinatorLayout.dispatchDependentViewsChanged(appBarLayout);
836a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    }
837a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
838631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    // Dispatch the updates to any listeners
839631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    dispatchOffsetUpdates(appBarLayout);
840a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
841a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
842a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
843a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return consumed;
844a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
845a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
846631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        private void dispatchOffsetUpdates(AppBarLayout layout) {
847631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            final List<WeakReference<OnOffsetChangedListener>> listeners = layout.mListeners;
84850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
849631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // Iterate backwards through the list so that most recently added listeners
850631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // get the first chance to decide
851631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            for (int i = 0, z = listeners.size(); i < z; i++) {
852631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                final WeakReference<OnOffsetChangedListener> ref = listeners.get(i);
853631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                final OnOffsetChangedListener listener = ref != null ? ref.get() : null;
85450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
855631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                if (listener != null) {
856631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    listener.onOffsetChanged(layout, getTopAndBottomOffset());
857a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
858a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
859a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
860a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
861a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int interpolateOffset(AppBarLayout layout, final int offset) {
862a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int absOffset = Math.abs(offset);
863a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
864a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            for (int i = 0, z = layout.getChildCount(); i < z; i++) {
865a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final View child = layout.getChildAt(i);
866a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final AppBarLayout.LayoutParams childLp = (LayoutParams) child.getLayoutParams();
86750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                final Interpolator interpolator = childLp.getScrollInterpolator();
868a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
86950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                if (absOffset >= child.getTop() && absOffset <= child.getBottom()) {
870a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    if (interpolator != null) {
87150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        int childScrollableHeight = 0;
87250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        final int flags = childLp.getScrollFlags();
87350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
874b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                            // We're set to scroll so add the child's height plus margin
875b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                            childScrollableHeight += child.getHeight() + childLp.topMargin
876b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                                    + childLp.bottomMargin;
877b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes
87850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
879b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                                // For a collapsing scroll, we to take the collapsed height
880b263b91ba75dc1a7855186e8b0e9cf75d46a6b8dChris Banes                                // into account.
88150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                                childScrollableHeight -= ViewCompat.getMinimumHeight(child);
88250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            }
88350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        }
88450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
88550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        if (childScrollableHeight > 0) {
88650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            final int offsetForView = absOffset - child.getTop();
88750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            final int interpolatedDiff = Math.round(childScrollableHeight *
88850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                                    interpolator.getInterpolation(
88950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                                            offsetForView / (float) childScrollableHeight));
89050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
89150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            return Integer.signum(offset) * (child.getTop() + interpolatedDiff);
89250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        }
893a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    }
89450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
89550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // If we get to here then the view on the offset isn't suitable for interpolated
89650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // scrolling. So break out of the loop
89750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    break;
898a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
899a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
900a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
901a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return offset;
902a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
903a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
904a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        final int getTopBottomOffsetForScrollingSibling() {
905e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            return getTopAndBottomOffset() + mOffsetDelta;
906e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        }
907e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
908e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        @Override
909e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        public Parcelable onSaveInstanceState(CoordinatorLayout parent, AppBarLayout appBarLayout) {
910e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            final Parcelable superState = super.onSaveInstanceState(parent, appBarLayout);
911e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            final int offset = getTopAndBottomOffset();
912e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
913e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            // Try and find the first visible child...
914e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            for (int i = 0, count = appBarLayout.getChildCount(); i < count; i++) {
915e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                View child = appBarLayout.getChildAt(i);
916e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                final int visBottom = child.getBottom() + offset;
917e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
918e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                if (child.getTop() + offset <= 0 && visBottom >= 0) {
919e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    final SavedState ss = new SavedState(superState);
920e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    ss.firstVisibleChildIndex = i;
921e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    ss.firstVisibileChildAtMinimumHeight =
922e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                            visBottom == ViewCompat.getMinimumHeight(child);
923e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    ss.firstVisibileChildPercentageShown = visBottom / (float) child.getHeight();
924e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    return ss;
925e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                }
926e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
927e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
928e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            // Else we'll just return the super state
929e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            return superState;
930e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        }
931e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
932e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        @Override
933e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        public void onRestoreInstanceState(CoordinatorLayout parent, AppBarLayout appBarLayout,
934e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                Parcelable state) {
935e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            if (state instanceof SavedState) {
936e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                final SavedState ss = (SavedState) state;
937e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                super.onRestoreInstanceState(parent, appBarLayout, ss.getSuperState());
938e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                mOffsetToChildIndexOnLayout = ss.firstVisibleChildIndex;
939e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                mOffsetToChildIndexOnLayoutPerc = ss.firstVisibileChildPercentageShown;
940e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                mOffsetToChildIndexOnLayoutIsMinHeight = ss.firstVisibileChildAtMinimumHeight;
941e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            } else {
942e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                super.onRestoreInstanceState(parent, appBarLayout, state);
943e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                mOffsetToChildIndexOnLayout = INVALID_POSITION;
944e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
945e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        }
946e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
947e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes        protected static class SavedState extends View.BaseSavedState {
948e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            int firstVisibleChildIndex;
949e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            float firstVisibileChildPercentageShown;
950e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            boolean firstVisibileChildAtMinimumHeight;
951e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
952e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            public SavedState(Parcel source) {
953e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                super(source);
954e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                firstVisibleChildIndex = source.readInt();
955e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                firstVisibileChildPercentageShown = source.readFloat();
956e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                firstVisibileChildAtMinimumHeight = source.readByte() != 0;
957e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
958e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
959e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            public SavedState(Parcelable superState) {
960e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                super(superState);
961e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
962e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
963e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            @Override
964e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            public void writeToParcel(Parcel dest, int flags) {
965e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                super.writeToParcel(dest, flags);
966e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                dest.writeInt(firstVisibleChildIndex);
967e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                dest.writeFloat(firstVisibileChildPercentageShown);
968e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                dest.writeByte((byte) (firstVisibileChildAtMinimumHeight ? 1 : 0));
969e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            }
970e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
971e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes            public static final Parcelable.Creator<SavedState> CREATOR =
972e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    new Parcelable.Creator<SavedState>() {
973e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        @Override
974e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        public SavedState createFromParcel(Parcel source) {
975e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                            return new SavedState(source);
976e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        }
977e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes
978e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        @Override
979e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        public SavedState[] newArray(int size) {
980e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                            return new SavedState[size];
981e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                        }
982e52e16988e2500e20052ddd70920f950f4eb4f79Chris Banes                    };
983a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
984a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
985a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
986a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
987a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Behavior which should be used by {@link View}s which can scroll vertically and support
988a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * nested scrolling to automatically scroll any {@link AppBarLayout} siblings.
989a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
990a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public static class ScrollingViewBehavior extends ViewOffsetBehavior<View> {
991a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int mOverlayTop;
992a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
993a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public ScrollingViewBehavior() {}
994a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
995a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public ScrollingViewBehavior(Context context, AttributeSet attrs) {
996a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(context, attrs);
997a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
998a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            TypedArray a = context.obtainStyledAttributes(attrs,
999a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    R.styleable.ScrollingViewBehavior_Params);
1000a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mOverlayTop = a.getDimensionPixelSize(
1001a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    R.styleable.ScrollingViewBehavior_Params_behavior_overlapTop, 0);
1002a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            a.recycle();
1003a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1004a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1005a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
1006a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
1007a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            // We depend on any AppBarLayouts
1008a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return dependency instanceof AppBarLayout;
1009a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1010a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1011a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
1012a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean onMeasureChild(CoordinatorLayout parent, View child,
1013a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int parentWidthMeasureSpec, int widthUsed,
1014a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int parentHeightMeasureSpec, int heightUsed) {
1015a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (child.getLayoutParams().height == LayoutParams.MATCH_PARENT) {
1016f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes                // If the child's height is set to match_parent then measure it with it's
1017f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes                // maximum visible visible height
1018a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1019a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final List<View> dependencies = parent.getDependencies(child);
1020a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (dependencies.isEmpty()) {
1021a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // If we don't have any dependencies, return false
1022a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return false;
1023a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1024a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1025a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final AppBarLayout appBar = findFirstAppBarLayout(dependencies);
10266ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                if (appBar != null && ViewCompat.isLaidOut(appBar)) {
10276ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                    if (ViewCompat.getFitsSystemWindows(appBar)) {
10286ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                        // If the AppBarLayout is fitting system windows then we need to also,
10296ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                        // otherwise we'll get CoL's compatible layout functionality
10306ba61c5c79fe025036593c9daf79cb65299bb0b6Chris Banes                        ViewCompat.setFitsSystemWindows(child, true);
1031a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    }
1032a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
103355f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                    int availableHeight = MeasureSpec.getSize(parentHeightMeasureSpec);
103455f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                    if (availableHeight == 0) {
103555f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                        // If the measure spec doesn't specify a size, use the current height
103655f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                        availableHeight = parent.getHeight();
103755f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                    }
103855f3d29c12610da3574c4f488fbc3a1c7ca790f1Chris Banes                    final int height = availableHeight - appBar.getMeasuredHeight()
1039f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes                            + appBar.getTotalScrollRange();
1040a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1041a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            MeasureSpec.AT_MOST);
1042a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1043a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Now measure the scrolling child with the correct height
1044a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    parent.onMeasureChild(child, parentWidthMeasureSpec,
1045a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            widthUsed, heightMeasureSpec, heightUsed);
1046a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1047a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return true;
1048a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1049a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
1050a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return false;
1051a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1052a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1053a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
1054a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
1055a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View dependency) {
1056a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final CoordinatorLayout.Behavior behavior =
1057a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ((CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior();
1058a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (behavior instanceof Behavior) {
1059a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // Offset the child so that it is below the app-bar (with any overlap)
1060a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1061a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final int appBarOffset = ((Behavior) behavior)
1062a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        .getTopBottomOffsetForScrollingSibling();
1063a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final int expandedMax = dependency.getHeight() - mOverlayTop;
1064a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final int collapsedMin = parent.getHeight() - child.getHeight();
1065a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1066a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (mOverlayTop != 0 && dependency instanceof AppBarLayout) {
1067a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // If we have an overlap top, and the dependency is an AppBarLayout, we control
1068a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // the offset ourselves based on the appbar's scroll progress. This is so that
1069a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // the scroll happens sequentially rather than linearly
1070a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    final int scrollRange = ((AppBarLayout) dependency).getTotalScrollRange();
1071a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    setTopAndBottomOffset(AnimationUtils.lerp(expandedMax, collapsedMin,
1072a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            Math.abs(appBarOffset) / (float) scrollRange));
1073a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                } else {
1074f57cd2fd5059c43d77bdfec57edfd5a217533103Chris Banes                    setTopAndBottomOffset(dependency.getHeight() - mOverlayTop + appBarOffset);
1075a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1076a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
1077a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return false;
1078a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1079a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1080a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
1081a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Set the distance that this view should overlap any {@link AppBarLayout}.
1082a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
1083a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @param overlayTop the distance in px
1084a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
1085a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void setOverlayTop(int overlayTop) {
1086a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mOverlayTop = overlayTop;
1087a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1088a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1089a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
1090a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Returns the distance that this view should overlap any {@link AppBarLayout}.
1091a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
1092a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public int getOverlayTop() {
1093a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mOverlayTop;
1094a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1095a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
1096a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private static AppBarLayout findFirstAppBarLayout(List<View> views) {
1097a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            for (int i = 0, z = views.size(); i < z; i++) {
1098a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View view = views.get(i);
1099a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (view instanceof AppBarLayout) {
1100a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return (AppBarLayout) view;
1101a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
1102a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
1103a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return null;
1104a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
1105a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
1106a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes}
1107