AppBarLayout.java revision 81520564f3dd783136e025174021ba4eabd6ff3c
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;
2150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banesimport android.support.annotation.IntDef;
22a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.support.design.R;
23a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.support.v4.view.ViewCompat;
24a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.util.AttributeSet;
25a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.View;
26a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.ViewGroup;
27a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.animation.Interpolator;
28a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.widget.LinearLayout;
29a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
3050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banesimport java.lang.annotation.Retention;
3150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banesimport java.lang.annotation.RetentionPolicy;
32a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport java.util.List;
33a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
34a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes/**
35a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * AppBarLayout is a vertical {@link LinearLayout} which implements many of the features of
36a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Material Design's App bar concept, namely scrolling gestures.
37a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <p>
38a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Children should provide their desired scrolling behavior through
39a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * {@link LayoutParams#setScrollFlags(int)} and the associated layout xml attribute:
40a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * {@code app:layout_scrollFlags}.
41a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
42a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <p>
43a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * This view depends heavily on being used as a direct child within a {@link CoordinatorLayout}.
44a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * If you use AppBarLayout within a different {@link ViewGroup}, most of it's functionality will
45a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * not work.
46a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <p>
47a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * AppBarLayout also requires a separate scrolling sibling in order to. The binding is done through
48a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * the {@link ScrollingViewBehavior} beahior class, meaning that you should set your scrolling
49a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * view's behavior to be an instance of {@link ScrollingViewBehavior}. A string resource containing
50a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * the full class name is available.
51a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
52a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * <pre>
53a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * &lt;android.support.design.widget.CoordinatorLayout
54a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         xmlns:android=&quot;http://schemas.android.com/apk/res/android";
55a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         xmlns:app=&quot;http://schemas.android.com/apk/res-auto";
56a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         android:layout_width=&quot;match_parent&quot;
57a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         android:layout_height=&quot;match_parent&quot;&gt;
58a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
59a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;android.support.v4.widget.NestedScrollView
60a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_width=&quot;match_parent&quot;
61a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_height=&quot;match_parent&quot;
62a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             app:layout_behavior=&quot;@string/appbar_scrolling_view_behavior&quot;&gt;
63a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
64a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         &lt;!-- Your scrolling content --&gt;
65a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
66a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;/android.support.v4.widget.NestedScrollView&gt;
67a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
68a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;android.support.design.widget.AppBarLayout
69a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_height=&quot;wrap_content&quot;
70a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *             android:layout_width=&quot;match_parent&quot;&gt;
71a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
72a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         &lt;android.support.v7.widget.Toolbar
73a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 ...
74a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 app:layout_scrollFlags=&quot;scroll|enterAlways&quot;/&gt;
75a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
76a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *         &lt;android.support.design.widget.TabLayout
77a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 ...
78a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *                 app:layout_scrollFlags=&quot;scroll|enterAlways&quot;/&gt;
79a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
80a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     &lt;/android.support.design.widget.AppBarLayout&gt;
81a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
82a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * &lt;/android.support.design.widget.CoordinatorLayout&gt;
83a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * </pre>
84a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
85a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * @see <a href="http://www.google.com/design/spec/layout/structure.html#structure-app-bar">
86a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *     http://www.google.com/design/spec/layout/structure.html#structure-app-bar</a>
87a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes */
88a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
89a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banespublic class AppBarLayout extends LinearLayout {
90a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
91a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
92a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Interface which allows an implementing child {@link View} of this {@link AppBarLayout} to
93a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * receive offset updates, and provide extra information.
94a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
95a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public interface AppBarLayoutChild {
9650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
9750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        /** @hide */
9850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @IntDef({
9950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                STATE_ELEVATED_ABOVE,
10050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                STATE_ELEVATED_INLINE
10150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        })
10250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @Retention(RetentionPolicy.SOURCE)
10350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @interface ElevatedState {}
10450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
10550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        /**
10650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * The {@link AppBarLayout} should be elevated above any scrolling content, and this cast
10750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * a shadow.
10850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         *
10950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * @see #onOffsetUpdate(int)
11050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         */
11150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        int STATE_ELEVATED_ABOVE = 1;
11250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
11350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        /**
11450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * The {@link AppBarLayout} should not be elevated above any scrolling content.
11550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         *
11650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * @see #onOffsetUpdate(int)
11750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         */
11850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        int STATE_ELEVATED_INLINE = 0;
11950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
120a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
121a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Called when the {@link AppBarLayout}'s layout offset has been changed. This allows
122a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * child views to implement custom behavior based on the offset (for instance pinning a
123a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * view at a certain y value).
124a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
12550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * <p>You can influence the elevation of the {@link AppBarLayout} by returning one of
12650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * {@link #STATE_ELEVATED_INLINE} or {@link #STATE_ELEVATED_ABOVE}.
12750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         *
12850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * @param verticalOffset the vertical offset for the parent {@link AppBarLayout}, in px
12950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         *
13050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes         * @return one of {@link #STATE_ELEVATED_INLINE} or {@link #STATE_ELEVATED_ABOVE}.
131a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
13250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @ElevatedState
13350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        int onOffsetUpdate(int verticalOffset);
134a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
135a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
136a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private static final int INVALID_SCROLL_RANGE = -1;
137a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
138a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private int mTotalScrollRange = INVALID_SCROLL_RANGE;
139a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private int mDownPreScrollRange = INVALID_SCROLL_RANGE;
140a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    private int mDownScrollRange = INVALID_SCROLL_RANGE;
141a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
142a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    boolean mHaveChildWithInterpolator;
143a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
14450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    private float mTargetElevation;
14550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
146a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public AppBarLayout(Context context) {
147a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        this(context, null);
148a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
149a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
150a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public AppBarLayout(Context context, AttributeSet attrs) {
151a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        super(context, attrs);
152a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        setOrientation(VERTICAL);
15350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
15450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppBarLayout,
15550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                0, R.style.Widget_Design_AppBarLayout);
15650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        mTargetElevation = a.getDimensionPixelSize(R.styleable.AppBarLayout_elevation, 0);
15781520564f3dd783136e025174021ba4eabd6ff3cChris Banes        setBackgroundDrawable(a.getDrawable(R.styleable.AppBarLayout_android_background));
15850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        a.recycle();
15950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
16050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        // Use the bounds view outline provider so that we cast a shadow, even without a background
16150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        ViewUtils.setBoundsViewOutlineProvider(this);
162a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
163a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
164a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
165a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected void onLayout(boolean changed, int l, int t, int r, int b) {
166a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        super.onLayout(changed, l, t, r, b);
167a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
168a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        // Invalidate the scroll ranges
169a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mTotalScrollRange = INVALID_SCROLL_RANGE;
170a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mDownPreScrollRange = INVALID_SCROLL_RANGE;
171a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mDownPreScrollRange = INVALID_SCROLL_RANGE;
172a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
173a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        mHaveChildWithInterpolator = false;
174a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        for (int i = 0, z = getChildCount(); i < z; i++) {
175a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
176a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams childLp = (LayoutParams) child.getLayoutParams();
177a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final Interpolator interpolator = childLp.getScrollInterpolator();
178a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
179a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (interpolator != null) {
180a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                mHaveChildWithInterpolator = true;
181a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
182a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
183a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
184a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
185a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
186a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
187a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public void setOrientation(int orientation) {
188a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (orientation != VERTICAL) {
189a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            throw new IllegalArgumentException("AppBarLayout is always vertical and does"
190a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    + " not support horizontal orientation");
191a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
192a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        super.setOrientation(orientation);
193a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
194a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
195a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
196a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
197a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return p instanceof LayoutParams;
198a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
199a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
200a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
201a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected LayoutParams generateDefaultLayoutParams() {
202a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
203a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
204a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
205a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
206a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public LayoutParams generateLayoutParams(AttributeSet attrs) {
207a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return new LayoutParams(getContext(), attrs);
208a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
209a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
210a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    @Override
211a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
212a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (p instanceof LinearLayout.LayoutParams) {
213a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return new LayoutParams((LinearLayout.LayoutParams) p);
214a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        } else if (p instanceof MarginLayoutParams) {
215a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return new LayoutParams((MarginLayoutParams) p);
216a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
217a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return new LayoutParams(p);
218a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
219a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
220a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final boolean hasChildWithInterpolator() {
221a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return mHaveChildWithInterpolator;
222a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
223a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
224a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
225a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Return the scroll range of any children
226a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     *
227a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * @return the scroll range in px
228a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
229a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final int getTotalScrollRange() {
230a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (mTotalScrollRange != INVALID_SCROLL_RANGE) {
231a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mTotalScrollRange;
232a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
233a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
234a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int range = 0;
235a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        for (int i = 0, z = getChildCount(); i < z; i++) {
236a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
237a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
238a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int childHeight = ViewCompat.isLaidOut(child)
239a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ? child.getHeight()
240a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    : child.getMeasuredHeight();
241a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int flags = lp.mScrollFlags;
242a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
243a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
244a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // We're set to scroll so add the child's height
245a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                range += childHeight;
246a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
247a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
248a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // For a collapsing scroll, we to take the collapsed height into account.
249a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // We also return the range straight away since later views can't scroll beneath
250a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // us
251a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return range - ViewCompat.getMinimumHeight(child);
252a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
253a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            } else {
254a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // As soon as a view doesn't have the scroll flag, we end the range calculation.
255a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // This is because views below can not scroll under a fixed view.
256a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
257a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
258a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
259a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return mTotalScrollRange = range;
260a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
261a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
262a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final boolean hasScrollableChildren() {
263a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return getTotalScrollRange() != 0;
264a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
265a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
266a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
267a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Return the scroll range when scrolling up from a nested pre-scroll.
268a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
269a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final int getUpNestedPreScrollRange() {
27050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        return getTotalScrollRange();
271a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
272a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
273a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
274a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Return the scroll range when scrolling down from a nested pre-scroll.
275a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
276a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final int getDownNestedPreScrollRange() {
277a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (mDownPreScrollRange != INVALID_SCROLL_RANGE) {
278a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            // If we already have a valid value, return it
279a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mDownPreScrollRange;
280a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
281a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
282a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int range = 0;
283a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        for (int i = getChildCount() - 1; i >= 0; i--) {
284a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
285a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
286a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int childHeight = ViewCompat.isLaidOut(child)
287a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ? child.getHeight()
288a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    : child.getMeasuredHeight();
289a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int flags = lp.mScrollFlags;
290a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
291a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if ((flags & LayoutParams.FLAG_QUICK_RETURN) == LayoutParams.FLAG_QUICK_RETURN) {
292a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // The view has the quick return flag combination...
293a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if ((flags & LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED) != 0) {
294a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // If they're set to enter collapsed, use the minimum height
295a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    range += ViewCompat.getMinimumHeight(child);
296a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                } else {
297a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Else use the full height
298a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    range += childHeight;
299a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
300a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            } else if (range > 0) {
301a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // If we've hit an non-quick return scrollable view, and we've already hit a
302a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // quick return view, return now
303a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
304a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
305a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
306a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return mDownPreScrollRange = range;
307a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
308a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
309a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
310a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Return the scroll range when scrolling down from a nested scroll.
311a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
312a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    final int getDownNestedScrollRange() {
313a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        if (mDownScrollRange != INVALID_SCROLL_RANGE) {
314a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            // If we already have a valid value, return it
315a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mDownScrollRange;
316a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
317a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
318a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int range = 0;
319a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        for (int i = getChildCount() - 1; i >= 0; i--) {
320a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final View child = getChildAt(i);
321a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
322a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int childHeight = ViewCompat.isLaidOut(child)
323a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ? child.getHeight()
324a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    : child.getMeasuredHeight();
325a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
326a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int flags = lp.mScrollFlags;
327a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
328a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
329a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // We're set to scroll so add the child's height
330a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                range += childHeight;
331a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
332a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
333a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // For a collapsing exit scroll, we to take the collapsed height into account.
334a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // We also return the range straight away since later views can't scroll
335a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // beneath us
336a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return range - ViewCompat.getMinimumHeight(child);
337a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
338a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            } else {
339a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // As soon as a view doesn't have the scroll flag, we end the range calculation.
340a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // This is because views below can not scroll under a fixed view.
341a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                break;
342a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
343a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
344a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        return mDownScrollRange = range;
345a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
346a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
34750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    final int getMinimumHeightForVisibleOverlappingContent() {
34850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        final int minHeight = ViewCompat.getMinimumHeight(this);
34950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        if (minHeight != 0) {
35050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            // If this layout has a min height, use it (doubled)
35150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            return minHeight * 2;
35250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        }
35350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
35450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        // Otherwise, we'll use twice the min height of our last child
35550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        final int childCount = getChildCount();
35650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        return childCount >= 1
35750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                ? ViewCompat.getMinimumHeight(getChildAt(childCount - 1)) * 2
35850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                : 0;
35950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    }
36050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
36150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    /**
36250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes     * The elevation value to use when {@link AppBarLayout} is elevated above content.
36350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes     */
36450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    final float getTargetElevation() {
36550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        return mTargetElevation;
36650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes    }
36750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
368a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public static class LayoutParams extends LinearLayout.LayoutParams {
36950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
37050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        /** @hide */
37150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @IntDef(flag=true, value={
37250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_SCROLL,
37350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_EXIT_UNTIL_COLLAPSED,
37450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_ENTER_ALWAYS,
37550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED
37650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        })
37750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @Retention(RetentionPolicy.SOURCE)
37850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        public @interface ScrollFlags {}
37950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
380a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
381a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * The view will be scroll in direct relation to scroll events. This flag needs to be
382a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * set for any of the other flags to take effect. If any sibling views
383a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * before this one do not have this flag, then this value has no effect.
384a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
385a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_SCROLL = 0x1;
386a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
387a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
388a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * When exiting (scrolling off screen) the view will be scrolled until it is
389a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * 'collapsed'. The collapsed height is defined by the view's minimum height.
390a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
391a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see ViewCompat#getMinimumHeight(View)
392a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see View#setMinimumHeight(int)
393a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
394a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 0x2;
395a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
396a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
397a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * When entering (scrolling on screen) the view will scroll on any downwards
398a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * scroll event, regardless of whether the scrolling view is also scrolling. This
399a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * is commonly referred to as the 'quick return' pattern.
400a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
401a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_ENTER_ALWAYS = 0x4;
402a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
403a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
404a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * An additional flag for 'enterAlways' which modifies the returning view to
405a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * only initially scroll back to it's collapsed height. Once the scrolling view has
406a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * reached the end of it's scroll range, the remainder of this view will be scrolled
407a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * into view. The collapsed height is defined by the view's minimum height.
408a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
409a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see ViewCompat#getMinimumHeight(View)
410a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see View#setMinimumHeight(int)
411a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
412a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 0x8;
413a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
414a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
415a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Internal flag which allows quick checking of 'quick return'
416a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
417a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        static final int FLAG_QUICK_RETURN = SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS;
418a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
419a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        int mScrollFlags = SCROLL_FLAG_SCROLL;
420a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        Interpolator mScrollInterpolator;
421a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
422a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(Context c, AttributeSet attrs) {
423a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(c, attrs);
424a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.AppBarLayout_LayoutParams);
425a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollFlags = a.getInt(R.styleable.AppBarLayout_LayoutParams_layout_scrollFlags, 0);
426a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (a.hasValue(R.styleable.AppBarLayout_LayoutParams_layout_scrollInterpolator)) {
427a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int resId = a.getResourceId(
428a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        R.styleable.AppBarLayout_LayoutParams_layout_scrollInterpolator, 0);
429a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                mScrollInterpolator = android.view.animation.AnimationUtils.loadInterpolator(
430a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        c, resId);
431a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
432a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            a.recycle();
433a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
434a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
435a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(int width, int height) {
436a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(width, height);
437a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
438a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
439a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(int width, int height, float weight) {
440a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(width, height, weight);
441a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
442a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
443a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(ViewGroup.LayoutParams p) {
444a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(p);
445a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
446a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
447a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(MarginLayoutParams source) {
448a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(source);
449a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
450a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
451a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(LinearLayout.LayoutParams source) {
452a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(source);
453a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
454a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
455a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public LayoutParams(LayoutParams source) {
456a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(source);
457a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollFlags = source.mScrollFlags;
458a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollInterpolator = source.mScrollInterpolator;
459a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
460a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
461a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
462a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Set the scrolling flags.
463a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
464a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @param flags bitwise int of {@link #SCROLL_FLAG_SCROLL},
465a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *             {@link #SCROLL_FLAG_EXIT_UNTIL_COLLAPSED}, {@link #SCROLL_FLAG_ENTER_ALWAYS}
466a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *             and {@link #SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED}.
467a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
468a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #getScrollFlags()
469a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
470a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @attr ref android.support.design.R.styleable.AppBarLayout_LayoutParams_layout_scrollFlags
471a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
47250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        public void setScrollFlags(@ScrollFlags int flags) {
473a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollFlags = flags;
474a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
475a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
476a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
477a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Returns the scrolling flags.
478a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
479a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #setScrollFlags(int)
480a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
481a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @attr ref android.support.design.R.styleable.AppBarLayout_LayoutParams_layout_scrollFlags
482a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
48350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @ScrollFlags
484a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public int getScrollFlags() {
485a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mScrollFlags;
486a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
487a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
488a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
489a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Set the interpolator to when scrolling the view associated with this
490a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * {@link LayoutParams}.
491a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
492a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @param interpolator the interpolator to use, or null to use normal 1-to-1 scrolling.
493a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
494a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @attr ref android.support.design.R.styleable.AppBarLayout_LayoutParams_layout_scrollInterpolator
495a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #getScrollInterpolator()
496a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
497a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void setScrollInterpolator(Interpolator interpolator) {
498a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mScrollInterpolator = interpolator;
499a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
500a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
501a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
502a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Returns the {@link Interpolator} being used for scrolling the view associated with this
503a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * {@link LayoutParams}. Null indicates 'normal' 1-to-1 scrolling.
504a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
505a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @attr ref android.support.design.R.styleable.AppBarLayout_LayoutParams_layout_scrollInterpolator
506a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @see #setScrollInterpolator(Interpolator)
507a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
508a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public Interpolator getScrollInterpolator() {
509a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mScrollInterpolator;
510a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
511a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
512a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
513a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
514a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * The default {@link Behavior} for {@link AppBarLayout}. Implements the necessary nested
515a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * scroll handling with offsetting.
516a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
517a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public static class Behavior extends ViewOffsetBehavior<AppBarLayout> {
518a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int mSiblingOffsetTop;
519a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
52050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        private boolean mSkipNestedPreScroll;
52150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
522a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public Behavior() {}
523a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
524a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public Behavior(Context context, AttributeSet attrs) {
525a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(context, attrs);
526a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
527a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
528a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
529a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
530a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View directTargetChild, View target, int nestedScrollAxes) {
531a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            // Return true if we're nested scrolling vertically and we have scrollable children
532a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0
533a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    && child.hasScrollableChildren();
534a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
535a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
536a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
537a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
538a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View target, int dx, int dy, int[] consumed) {
53950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            if (dy != 0 && !mSkipNestedPreScroll) {
54050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                int min, max;
54150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                if (dy < 0) {
54250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // We're scrolling down
54350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    min = -child.getTotalScrollRange();
54450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    max = min + child.getDownNestedPreScrollRange();
54550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                } else {
54650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // We're scrolling up
54750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    min = -child.getUpNestedPreScrollRange();
54850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    max = 0;
54950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                }
55050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                consumed[1] = scroll(coordinatorLayout, child, dy, min, max);
551a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
552a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
553a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
554a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
555a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
556a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View target, int dxConsumed, int dyConsumed,
557a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int dxUnconsumed, int dyUnconsumed) {
55850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            if (dyUnconsumed < 0) {
55950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // If the scrolling view is scrolling down but not consuming, it's probably be at
56050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // the top of it's content
56150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                scroll(coordinatorLayout, child, dyUnconsumed,
56250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        -child.getDownNestedScrollRange(), 0);
56350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // Set the expanding flag so that onNestedPreScroll doesn't handle any events
56450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                mSkipNestedPreScroll = true;
56550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            } else {
56650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // As we're no longer handling nested scrolls, reset the skip flag
56750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                mSkipNestedPreScroll = false;
568a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
56950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        }
570a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
57150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @Override
57250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
57350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                View target) {
57450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            // Reset the skip flag
57550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            mSkipNestedPreScroll = false;
57650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        }
57750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
57850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        @Override
57950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout child,
58050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                int layoutDirection) {
58150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            boolean handled = super.onLayoutChild(parent, child, layoutDirection);
58250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
58350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            // Make sure we update the elevation
58450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            final int elevationState = dispatchOffsetUpdates(child);
58550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            checkElevation(child, getTopAndBottomOffset(), elevationState);
58650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
58750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            return handled;
588a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
589a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
590a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int scroll(CoordinatorLayout coordinatorLayout, AppBarLayout appBarLayout,
59150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                int dy, int minOffset, int maxOffset) {
592a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return setAppBarTopBottomOffset(coordinatorLayout, appBarLayout,
59350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    mSiblingOffsetTop - dy, minOffset, maxOffset);
594a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
595a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
596a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int setAppBarTopBottomOffset(CoordinatorLayout coordinatorLayout,
59750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                AppBarLayout appBarLayout, int newOffset, int minOffset, int maxOffset) {
598a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int curOffset = mSiblingOffsetTop;
599a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            int consumed = 0;
600a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
60150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            if (minOffset != 0) {
60250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                newOffset = MathUtils.constrain(newOffset, minOffset, maxOffset);
603a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
604a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (curOffset != newOffset) {
605a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    boolean offsetChanged = setTopAndBottomOffset(
606a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            appBarLayout.hasChildWithInterpolator()
607a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                                    ? interpolateOffset(appBarLayout, newOffset)
608a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                                    : newOffset);
609a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Update how much dy we have consumed
610a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    consumed = curOffset - newOffset;
611a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Update the stored sibling offset
612a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    mSiblingOffsetTop = newOffset;
613a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
614a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    if (!offsetChanged && appBarLayout.hasChildWithInterpolator()) {
615a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // If the offset hasn't changed and we're using an interpolated scroll
616a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // then we need to keep any dependent views updated. CoL will do this for
617a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // us when we move, but we need to do it manually when we don't (as an
618a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // interpolated scroll may finish early).
619a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        coordinatorLayout.dispatchDependentViewsChanged(appBarLayout);
620a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    }
621a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
62250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // Dispatch the updates to any AppBarLayoutChild children
62350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    final int childState = dispatchOffsetUpdates(appBarLayout);
62450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    checkElevation(appBarLayout, newOffset, childState);
625a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
626a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
627a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
628a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return consumed;
629a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
630a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
63150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        private void checkElevation(AppBarLayout appBarLayout, int offset, int childState) {
63250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            if (appBarLayout.getHeight() + offset == 0) {
63350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                // If we're not visible, clear out the elevation
63450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                ViewCompat.setElevation(appBarLayout, 0f);
63550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            } else {
63650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                if (childState == AppBarLayoutChild.STATE_ELEVATED_ABOVE) {
63750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    ViewCompat.setElevation(appBarLayout, appBarLayout.getTargetElevation());
63850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                } else {
63950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    ViewCompat.setElevation(appBarLayout, 0f);
64050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                }
64150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            }
64250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        }
64350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
64450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes        private int dispatchOffsetUpdates(AppBarLayout layout) {
645a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            for (int i = 0, z = layout.getChildCount(); i < z; i++) {
646a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View child = layout.getChildAt(i);
647a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (child instanceof AppBarLayoutChild) {
64850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    final int childState = ((AppBarLayoutChild) child)
64950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            .onOffsetUpdate(getTopAndBottomOffset());
65050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
65150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    if (childState == AppBarLayoutChild.STATE_ELEVATED_INLINE) {
65250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        return childState;
65350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    }
654a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
655a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
65650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
65750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes            return AppBarLayoutChild.STATE_ELEVATED_ABOVE;
658a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
659a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
660a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int interpolateOffset(AppBarLayout layout, final int offset) {
661a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final int absOffset = Math.abs(offset);
662a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
663a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            for (int i = 0, z = layout.getChildCount(); i < z; i++) {
664a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final View child = layout.getChildAt(i);
665a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final AppBarLayout.LayoutParams childLp = (LayoutParams) child.getLayoutParams();
66650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                final Interpolator interpolator = childLp.getScrollInterpolator();
667a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
66850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                if (absOffset >= child.getTop() && absOffset <= child.getBottom()) {
669a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    if (interpolator != null) {
67050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        int childScrollableHeight = 0;
67150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        final int flags = childLp.getScrollFlags();
67250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
67350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            // We're set to scroll so add the child's height
67450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            childScrollableHeight += child.getHeight();
67550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
67650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                                // For a collapsing scroll, we to take the collapsed height into account.
67750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                                childScrollableHeight -= ViewCompat.getMinimumHeight(child);
67850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            }
67950dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        }
68050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
68150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        if (childScrollableHeight > 0) {
68250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            final int offsetForView = absOffset - child.getTop();
68350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            final int interpolatedDiff = Math.round(childScrollableHeight *
68450dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                                    interpolator.getInterpolation(
68550dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                                            offsetForView / (float) childScrollableHeight));
68650dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
68750dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                            return Integer.signum(offset) * (child.getTop() + interpolatedDiff);
68850dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                        }
689a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    }
69050dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes
69150dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // If we get to here then the view on the offset isn't suitable for interpolated
69250dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    // scrolling. So break out of the loop
69350dfc33a565c4aefe6d5e844c93aa24a74cb80b3Chris Banes                    break;
694a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
695a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
696a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
697a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return offset;
698a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
699a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
700a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        final int getTopBottomOffsetForScrollingSibling() {
701a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mSiblingOffsetTop;
702a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
703a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
704a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
705a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
706a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Behavior which should be used by {@link View}s which can scroll vertically and support
707a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * nested scrolling to automatically scroll any {@link AppBarLayout} siblings.
708a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
709a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    public static class ScrollingViewBehavior extends ViewOffsetBehavior<View> {
710a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private int mOverlayTop;
711a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
712a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public ScrollingViewBehavior() {}
713a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
714a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public ScrollingViewBehavior(Context context, AttributeSet attrs) {
715a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            super(context, attrs);
716a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
717a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            TypedArray a = context.obtainStyledAttributes(attrs,
718a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    R.styleable.ScrollingViewBehavior_Params);
719a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mOverlayTop = a.getDimensionPixelSize(
720a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    R.styleable.ScrollingViewBehavior_Params_behavior_overlapTop, 0);
721a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            a.recycle();
722a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
723a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
724a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
725a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
726a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            // We depend on any AppBarLayouts
727a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return dependency instanceof AppBarLayout;
728a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
729a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
730a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
731a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean onMeasureChild(CoordinatorLayout parent, View child,
732a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int parentWidthMeasureSpec, int widthUsed,
733a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                int parentHeightMeasureSpec, int heightUsed) {
734a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (child.getLayoutParams().height == LayoutParams.MATCH_PARENT) {
735a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // If the child's height is set to match_parent then it with it's maximum visible
736a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // visible height
737a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
738a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final List<View> dependencies = parent.getDependencies(child);
739a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (dependencies.isEmpty()) {
740a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // If we don't have any dependencies, return false
741a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return false;
742a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
743a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
744a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final AppBarLayout appBar = findFirstAppBarLayout(dependencies);
745a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (appBar != null) {
746a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    if (appBar.getMeasuredWidth() == 0 || appBar.getMeasuredHeight() == 0) {
747a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        // If the AppBar hasn't been measured yet, we need to do it now
748a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        parent.onMeasureChild(appBar, parentWidthMeasureSpec,
749a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                                widthUsed, parentHeightMeasureSpec, heightUsed);
750a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    }
751a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
752a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    final int scrollRange = appBar.getTotalScrollRange();
753a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    final int height = MeasureSpec.getSize(parentHeightMeasureSpec)
754a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            - appBar.getMeasuredHeight() + scrollRange;
755a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
756a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            MeasureSpec.AT_MOST);
757a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
758a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // Now measure the scrolling child with the correct height
759a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    parent.onMeasureChild(child, parentWidthMeasureSpec,
760a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            widthUsed, heightMeasureSpec, heightUsed);
761a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
762a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return true;
763a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
764a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
765a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return false;
766a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
767a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
768a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        @Override
769a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
770a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View dependency) {
771a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            final CoordinatorLayout.Behavior behavior =
772a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    ((CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior();
773a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            if (behavior instanceof Behavior) {
774a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                // Offset the child so that it is below the app-bar (with any overlap)
775a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
776a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final int appBarOffset = ((Behavior) behavior)
777a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                        .getTopBottomOffsetForScrollingSibling();
778a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final int expandedMax = dependency.getHeight() - mOverlayTop;
779a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                final int collapsedMin = parent.getHeight() - child.getHeight();
780a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
781a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (mOverlayTop != 0 && dependency instanceof AppBarLayout) {
782a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // If we have an overlap top, and the dependency is an AppBarLayout, we control
783a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // the offset ourselves based on the appbar's scroll progress. This is so that
784a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    // the scroll happens sequentially rather than linearly
785a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    final int scrollRange = ((AppBarLayout) dependency).getTotalScrollRange();
786a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    setTopAndBottomOffset(AnimationUtils.lerp(expandedMax, collapsedMin,
787a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            Math.abs(appBarOffset) / (float) scrollRange));
788a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                } else {
789a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    setTopAndBottomOffset(MathUtils.constrain(
790a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            dependency.getHeight() - mOverlayTop + appBarOffset,
791a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                            collapsedMin, expandedMax));
792a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
793a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
794a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return false;
795a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
796a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
797a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
798a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Set the distance that this view should overlap any {@link AppBarLayout}.
799a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
800a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @param overlayTop the distance in px
801a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
802a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @attr ref android.support.design.R.styleable.ScrollingViewBehavior_LayoutParams_layout_overlapTop
803a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
804a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public void setOverlayTop(int overlayTop) {
805a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            mOverlayTop = overlayTop;
806a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
807a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
808a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        /**
809a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * Returns the distance that this view should overlap any {@link AppBarLayout}.
810a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         *
811a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         * @attr ref android.support.design.R.styleable.ScrollingViewBehavior_LayoutParams_layout_overlapTop
812a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes         */
813a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        public int getOverlayTop() {
814a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return mOverlayTop;
815a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
816a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
817a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        private static AppBarLayout findFirstAppBarLayout(List<View> views) {
818a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            for (int i = 0, z = views.size(); i < z; i++) {
819a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                View view = views.get(i);
820a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                if (view instanceof AppBarLayout) {
821a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                    return (AppBarLayout) view;
822a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes                }
823a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            }
824a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes            return null;
825a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        }
826a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
827a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes}
828