BottomSheetBehavior.java revision 91177092bb7b2a0586f194de4d207349cdfabf30
1452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki/* 2452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Copyright (C) 2015 The Android Open Source Project 3452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 4452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Licensed under the Apache License, Version 2.0 (the "License"); 5452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * you may not use this file except in compliance with the License. 6452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * You may obtain a copy of the License at 7452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 8452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * http://www.apache.org/licenses/LICENSE-2.0 9452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 10452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Unless required by applicable law or agreed to in writing, software 11452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * distributed under the License is distributed on an "AS IS" BASIS, 12452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * See the License for the specific language governing permissions and 14452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * limitations under the License. 15452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 16452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 17452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakipackage android.support.design.widget; 18452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 19452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.content.Context; 20452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.content.res.TypedArray; 21452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.os.Parcel; 22452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.os.Parcelable; 23452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.annotation.IntDef; 24dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Arakiimport android.support.annotation.NonNull; 25452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.design.R; 2605f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banesimport android.support.v4.os.ParcelableCompat; 2705f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banesimport android.support.v4.os.ParcelableCompatCreatorCallbacks; 2805f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banesimport android.support.v4.view.AbsSavedState; 29452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.MotionEventCompat; 309aec720809a123c6193304730acf8b55d6ce5a7aYuichi Arakiimport android.support.v4.view.NestedScrollingChild; 31e3e7063749d095bba8743cad0aeb7164a567890dYuichi Arakiimport android.support.v4.view.VelocityTrackerCompat; 32452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.ViewCompat; 33452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.widget.ViewDragHelper; 34452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.util.AttributeSet; 35452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.MotionEvent; 36e3e7063749d095bba8743cad0aeb7164a567890dYuichi Arakiimport android.view.VelocityTracker; 37452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.View; 38e3e7063749d095bba8743cad0aeb7164a567890dYuichi Arakiimport android.view.ViewConfiguration; 39452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.ViewGroup; 40452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 41452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.Retention; 42452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.RetentionPolicy; 43452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.ref.WeakReference; 44452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 45452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 46452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki/** 47452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as 48452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * a bottom sheet. 49452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 50452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakipublic class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> { 51452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 52452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 534df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * Callback for monitoring events about bottom sheets. 54f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 554df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki public abstract static class BottomSheetCallback { 56f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 57f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 58f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Called when the bottom sheet changes its state. 59f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 60dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki * @param bottomSheet The bottom sheet view. 61dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki * @param newState The new state. This will be one of {@link #STATE_DRAGGING}, 62dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki * {@link #STATE_SETTLING}, {@link #STATE_EXPANDED}, 63dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki * {@link #STATE_COLLAPSED}, or {@link #STATE_HIDDEN}. 64f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 65dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki public abstract void onStateChanged(@NonNull View bottomSheet, @State int newState); 66f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 67f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 68f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Called when the bottom sheet is being dragged. 69f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 70dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki * @param bottomSheet The bottom sheet view. 7191177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas * @param slideOffset The new offset of this bottom sheet within [-1,1] range. Offset 7291177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas * increases as this bottom sheet is moving upward. From 0 to 1 the sheet 7391177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas * is between collapsed and expanded states and from -1 to 0 it is 7491177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas * between hidden and collapsed states. 75f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 76dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki public abstract void onSlide(@NonNull View bottomSheet, float slideOffset); 77f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 78f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 79f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 80452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is dragging. 81452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 82452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_DRAGGING = 1; 83452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 84452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 85452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is settling. 86452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 87452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_SETTLING = 2; 88452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 89452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 90452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is expanded. 91452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 92452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_EXPANDED = 3; 93452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 94452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 95452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is collapsed. 96452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 97452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_COLLAPSED = 4; 98452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 99f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 100f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * The bottom sheet is hidden. 101f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 102f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public static final int STATE_HIDDEN = 5; 103f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 104452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** @hide */ 105f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN}) 106452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Retention(RetentionPolicy.SOURCE) 107452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public @interface State {} 108452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 109f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private static final float HIDE_THRESHOLD = 0.5f; 110f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 111f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private static final float HIDE_FRICTION = 0.1f; 112f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 113e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private float mMaximumVelocity; 114f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 115452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mPeekHeight; 116452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 117452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mMinOffset; 118452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 119452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mMaxOffset; 120452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 121f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private boolean mHideable; 122f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 123362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki private boolean mSkipCollapsed; 124362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki 125452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 126452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mState = STATE_COLLAPSED; 127452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 128452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private ViewDragHelper mViewDragHelper; 129452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 130452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private boolean mIgnoreEvents; 131452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 132e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private int mLastNestedScrollDy; 133e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 13449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki private boolean mNestedScrolled; 13549a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki 136452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mParentHeight; 137452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 138452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private WeakReference<V> mViewRef; 139452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 1409aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki private WeakReference<View> mNestedScrollingChildRef; 141f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 1429aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki private BottomSheetCallback mCallback; 143f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 144e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private VelocityTracker mVelocityTracker; 145e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 146e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private int mActivePointerId; 147f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 1484eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki private int mInitialY; 1494eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki 150b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki private boolean mTouchingScrollingChild; 151b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki 152452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 153452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Default constructor for instantiating BottomSheetBehaviors. 154452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 155452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public BottomSheetBehavior() { 156452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 157452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 158452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 159452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Default constructor for inflating BottomSheetBehaviors from layout. 160452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 161452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param context The {@link Context}. 162452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param attrs The {@link AttributeSet}. 163452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 164452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public BottomSheetBehavior(Context context, AttributeSet attrs) { 165452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super(context, attrs); 166452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki TypedArray a = context.obtainStyledAttributes(attrs, 167c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes R.styleable.BottomSheetBehavior_Layout); 168452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setPeekHeight(a.getDimensionPixelSize( 169c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight, 0)); 170c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_hideable, false)); 171362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki setSkipCollapsed(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_skipCollapsed, 172362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki false)); 173452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki a.recycle(); 174e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewConfiguration configuration = ViewConfiguration.get(context); 175e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 176452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 177452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 178452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 179452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) { 180452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return new SavedState(super.onSaveInstanceState(parent, child), mState); 181452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 182452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 183452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 184452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) { 185452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki SavedState ss = (SavedState) state; 186452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super.onRestoreInstanceState(parent, child, ss.getSuperState()); 187452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Intermediate states are restored as collapsed state 188f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) { 189452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mState = STATE_COLLAPSED; 190f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 191f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mState = ss.state; 192452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 193452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 194452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 195452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 196452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) { 1976bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) { 1986bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki ViewCompat.setFitsSystemWindows(child, true); 199f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 2006bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki int savedTop = child.getTop(); 2016bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki // First let the parent lay it out 2026bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki parent.onLayoutChild(child, layoutDirection); 203452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Offset the bottom sheet 204452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mParentHeight = parent.getHeight(); 205452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mMinOffset = Math.max(0, mParentHeight - child.getHeight()); 2063bd9d18c5855600254e907d6668f2ec4d7fd1c51Yuichi Araki mMaxOffset = Math.max(mParentHeight - mPeekHeight, mMinOffset); 207452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mState == STATE_EXPANDED) { 208452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.offsetTopAndBottom(child, mMinOffset); 209f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && mState == STATE_HIDDEN) { 210f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ViewCompat.offsetTopAndBottom(child, mParentHeight); 211f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mState == STATE_COLLAPSED) { 212452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.offsetTopAndBottom(child, mMaxOffset); 2136bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki } else if (mState == STATE_DRAGGING || mState == STATE_SETTLING) { 2146bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop()); 215452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 216452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper == null) { 217452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewDragHelper = ViewDragHelper.create(parent, mDragCallback); 218452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 219452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewRef = new WeakReference<>(child); 2209aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child)); 221452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return true; 222452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 223452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 224452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 225452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) { 22617fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki if (!child.isShown()) { 22717fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki return false; 22817fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki } 229452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int action = MotionEventCompat.getActionMasked(event); 230e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki // Record the velocity 231e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (action == MotionEvent.ACTION_DOWN) { 232e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki reset(); 233e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 234e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mVelocityTracker == null) { 235e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker = VelocityTracker.obtain(); 236e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 237e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker.addMovement(event); 238452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki switch (action) { 239452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_UP: 240452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_CANCEL: 241b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki mTouchingScrollingChild = false; 242e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mActivePointerId = MotionEvent.INVALID_POINTER_ID; 243452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Reset the ignore flag 244452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mIgnoreEvents) { 245452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mIgnoreEvents = false; 246452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return false; 247452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 248452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki break; 249452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_DOWN: 2504eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki int initialX = (int) event.getX(); 2514eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki mInitialY = (int) event.getY(); 2529aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki View scroll = mNestedScrollingChildRef.get(); 2534eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki if (scroll != null && parent.isPointInChildBounds(scroll, initialX, mInitialY)) { 254e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mActivePointerId = event.getPointerId(event.getActionIndex()); 255b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki mTouchingScrollingChild = true; 2569aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 257e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mIgnoreEvents = mActivePointerId == MotionEvent.INVALID_POINTER_ID && 2584eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki !parent.isPointInChildBounds(child, initialX, mInitialY); 259452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki break; 260452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 2614eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki if (!mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event)) { 2624eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki return true; 2634eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki } 2644eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki // We have to handle cases that the ViewDragHelper does not capture the bottom sheet because 2654eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki // it is not the top most view of its parent. This is not necessary when the touch event is 2664eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki // happening over the scrolling content as nested scrolling logic handles that case. 2674eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki View scroll = mNestedScrollingChildRef.get(); 2684eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki return action == MotionEvent.ACTION_MOVE && scroll != null && 2694eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki !mIgnoreEvents && mState != STATE_DRAGGING && 2704eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki !parent.isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY()) && 2714eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop(); 272452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 273452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 274452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 275452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) { 27617fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki if (!child.isShown()) { 27717fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki return false; 27817fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki } 279e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int action = MotionEventCompat.getActionMasked(event); 280e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mState == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) { 281e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return true; 282e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 283452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewDragHelper.processTouchEvent(event); 284e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki // Record the velocity 285e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (action == MotionEvent.ACTION_DOWN) { 286e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki reset(); 287e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 288e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mVelocityTracker == null) { 289e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker = VelocityTracker.obtain(); 290e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 291e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker.addMovement(event); 2924eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki // The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it 2934eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki // to capture the bottom sheet in case it is not captured and the touch slop is passed. 294912d40d353f5b6d0a4fa18740ca40aa4b25b0f9cYuichi Araki if (action == MotionEvent.ACTION_MOVE && !mIgnoreEvents) { 2954eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki if (Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop()) { 2964eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki mViewDragHelper.captureChildView(child, event.getPointerId(event.getActionIndex())); 2974eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki } 2984eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki } 2991dbdc6baec537b45e9bd8e5afabcb5c35f1a8004Yuichi Araki return !mIgnoreEvents; 300452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 301452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 302e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki @Override 303e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, 304e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki View directTargetChild, View target, int nestedScrollAxes) { 305e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mLastNestedScrollDy = 0; 30649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki mNestedScrolled = false; 307e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0; 308e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 309e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 310e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki @Override 311e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, 312e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int dy, int[] consumed) { 313e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki View scrollingChild = mNestedScrollingChildRef.get(); 314e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (target != scrollingChild) { 315e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return; 316e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 317e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int currentTop = child.getTop(); 318e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int newTop = currentTop - dy; 319e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (dy > 0) { // Upward 320e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (newTop < mMinOffset) { 321e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki consumed[1] = currentTop - mMinOffset; 322e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewCompat.offsetTopAndBottom(child, -consumed[1]); 323e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(STATE_EXPANDED); 324e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else { 325e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki consumed[1] = dy; 326e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewCompat.offsetTopAndBottom(child, -dy); 327e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(STATE_DRAGGING); 328e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 329e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else if (dy < 0) { // Downward 330e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (!ViewCompat.canScrollVertically(target, -1)) { 331e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (newTop <= mMaxOffset || mHideable) { 332e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki consumed[1] = dy; 333e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewCompat.offsetTopAndBottom(child, -dy); 334e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(STATE_DRAGGING); 335e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else { 336e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki consumed[1] = currentTop - mMaxOffset; 337e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewCompat.offsetTopAndBottom(child, -consumed[1]); 338e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(STATE_COLLAPSED); 339e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 340e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 341e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 342e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki dispatchOnSlide(child.getTop()); 343e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mLastNestedScrollDy = dy; 34449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki mNestedScrolled = true; 345e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 346e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 347e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki @Override 348e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) { 349b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki if (child.getTop() == mMinOffset) { 350b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki setStateInternal(STATE_EXPANDED); 351b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki return; 352b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki } 353b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki if (target != mNestedScrollingChildRef.get() || !mNestedScrolled) { 354e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return; 355e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 356e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int top; 357e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int targetState; 358e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mLastNestedScrollDy > 0) { 359e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki top = mMinOffset; 360e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki targetState = STATE_EXPANDED; 361e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else if (mHideable && shouldHide(child, getYVelocity())) { 362e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki top = mParentHeight; 363e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki targetState = STATE_HIDDEN; 36449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } else if (mLastNestedScrollDy == 0) { 36549a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki int currentTop = child.getTop(); 36649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) { 36749a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki top = mMinOffset; 36849a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki targetState = STATE_EXPANDED; 36949a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } else { 37049a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki top = mMaxOffset; 37149a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki targetState = STATE_COLLAPSED; 37249a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } 373e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else { 374e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki top = mMaxOffset; 375e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki targetState = STATE_COLLAPSED; 376e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 377e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { 378e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(STATE_SETTLING); 379e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState)); 380e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else { 381e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(targetState); 382e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 38349a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki mNestedScrolled = false; 384e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 385e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 386e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki @Override 387e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, 388e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki float velocityX, float velocityY) { 389e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return target == mNestedScrollingChildRef.get() && 390e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki (mState != STATE_EXPANDED || 391e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki super.onNestedPreFling(coordinatorLayout, child, target, 392e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki velocityX, velocityY)); 393e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 394e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 395452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 396452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Sets the height of the bottom sheet when it is collapsed. 397452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 398452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param peekHeight The height of the collapsed bottom sheet in pixels. 39973e7a06fb66110495fa4e98a91831a47feab2526Chris Banes * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight 400452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 401452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final void setPeekHeight(int peekHeight) { 402452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mPeekHeight = Math.max(0, peekHeight); 403452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mMaxOffset = mParentHeight - peekHeight; 404452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 405452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 406452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 407452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Gets the height of the bottom sheet when it is collapsed. 408452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 409452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return The height of the collapsed bottom sheet. 41073e7a06fb66110495fa4e98a91831a47feab2526Chris Banes * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight 411452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 412452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final int getPeekHeight() { 413452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return mPeekHeight; 414452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 415452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 416452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 417f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Sets whether this bottom sheet can hide when it is swiped down. 418f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 419f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param hideable {@code true} to make this bottom sheet hideable. 42073e7a06fb66110495fa4e98a91831a47feab2526Chris Banes * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable 421f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 422f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public void setHideable(boolean hideable) { 423f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mHideable = hideable; 424f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 425f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 426f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 427f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Gets whether this bottom sheet can hide when it is swiped down. 428f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 429f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @return {@code true} if this bottom sheet can hide. 43073e7a06fb66110495fa4e98a91831a47feab2526Chris Banes * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable 431f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 432f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public boolean isHideable() { 433f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return mHideable; 434f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 435f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 436f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 437362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki * Sets whether this bottom sheet should skip the collapsed state when it is being hidden 438362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki * after it is expanded once. Setting this to true has no effect unless the sheet is hideable. 439362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki * 440362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki * @param skipCollapsed True if the bottom sheet should skip the collapsed state. 441362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed 442362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki */ 443362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki public void setSkipCollapsed(boolean skipCollapsed) { 444362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki mSkipCollapsed = skipCollapsed; 445362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki } 446362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki 447362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki /** 448362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki * Sets whether this bottom sheet should skip the collapsed state when it is being hidden 449362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki * after it is expanded once. 450362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki * 451362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki * @return Whether the bottom sheet should skip the collapsed state. 452362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed 453362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki */ 454362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki public boolean getSkipCollapsed() { 455362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki return mSkipCollapsed; 456362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki } 457362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki 458362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki /** 4594df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * Sets a callback to be notified of bottom sheet events. 460f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 4614df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * @param callback The callback to notify when bottom sheet events occur. 462f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 4634df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki public void setBottomSheetCallback(BottomSheetCallback callback) { 4644df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki mCallback = callback; 465f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 466f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 467f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 468452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Sets the state of the bottom sheet. The bottom sheet will transition to that state with 469452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * animation. 470452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 471f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, or 472f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * {@link #STATE_HIDDEN}. 473452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 474452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final void setState(@State int state) { 475e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki if (state == mState) { 476e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki return; 477e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki } 47898475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim if (mViewRef == null) { 4796deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki // The view is not laid out yet; modify mState and let onLayoutChild handle it later 4806deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki if (state == STATE_COLLAPSED || state == STATE_EXPANDED || 4816deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki (mHideable && state == STATE_HIDDEN)) { 4826deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki mState = state; 4836deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki } 48498475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim return; 48598475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim } 486452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki V child = mViewRef.get(); 487452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (child == null) { 488452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return; 489452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 490452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int top; 491452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (state == STATE_COLLAPSED) { 492452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMaxOffset; 493452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else if (state == STATE_EXPANDED) { 494452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMinOffset; 495f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && state == STATE_HIDDEN) { 496f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki top = mParentHeight; 497452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 498452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException("Illegal state argument: " + state); 499452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 500452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_SETTLING); 501452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { 502452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(child, new SettleRunnable(child, state)); 503452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 504452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 505452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 506452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 507452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Gets the current state of the bottom sheet. 508452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 509452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING}, 510452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * and {@link #STATE_SETTLING}. 511452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 512452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 513452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final int getState() { 514452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return mState; 515452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 516452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 517452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private void setStateInternal(@State int state) { 518452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mState == state) { 519452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return; 520452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 521452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mState = state; 522dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki View bottomSheet = mViewRef.get(); 523dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki if (bottomSheet != null && mCallback != null) { 524dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki mCallback.onStateChanged(bottomSheet, state); 525f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 526f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 527f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 528e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private void reset() { 529e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mActivePointerId = ViewDragHelper.INVALID_POINTER; 530e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mVelocityTracker != null) { 531e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker.recycle(); 532e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker = null; 533e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 534e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 535e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 536f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private boolean shouldHide(View child, float yvel) { 537362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki if (mSkipCollapsed) { 538362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki return true; 539362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki } 540f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (child.getTop() < mMaxOffset) { 541f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki // It should not hide, but collapse. 542f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return false; 543f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 544f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki final float newTop = child.getTop() + yvel * HIDE_FRICTION; 545f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return Math.abs(newTop - mMaxOffset) / (float) mPeekHeight > HIDE_THRESHOLD; 546f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 547f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 5489aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki private View findScrollingChild(View view) { 5499aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (view instanceof NestedScrollingChild) { 5509aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return view; 5519aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 5529aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (view instanceof ViewGroup) { 5539aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki ViewGroup group = (ViewGroup) view; 5549aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki for (int i = 0, count = group.getChildCount(); i < count; i++) { 5559aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki View scrollingChild = findScrollingChild(group.getChildAt(i)); 5569aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (scrollingChild != null) { 5579aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return scrollingChild; 5589aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 5599aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 5609aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 5619aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return null; 562452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 563452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 564e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private float getYVelocity() { 565e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 566e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId); 567e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 568e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 569452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() { 570452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 571452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 572452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean tryCaptureView(View child, int pointerId) { 573e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mState == STATE_DRAGGING) { 574e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return false; 575e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 576b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki if (mTouchingScrollingChild) { 577b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki return false; 578b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki } 579e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mState == STATE_EXPANDED && mActivePointerId == pointerId) { 5809aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki View scroll = mNestedScrollingChildRef.get(); 5819aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (scroll != null && ViewCompat.canScrollVertically(scroll, -1)) { 5829aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki // Let the content scroll up 5839aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return false; 5849aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 5859aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 586f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return mViewRef != null && mViewRef.get() == child; 587f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 588f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 589f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki @Override 590f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { 591f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki dispatchOnSlide(top); 592452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 593452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 594452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 595452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onViewDragStateChanged(int state) { 596452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (state == ViewDragHelper.STATE_DRAGGING) { 597452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_DRAGGING); 598452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 599452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 600452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 601452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 602452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onViewReleased(View releasedChild, float xvel, float yvel) { 603452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int top; 604452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State int targetState; 605f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (yvel < 0) { // Moving up 606452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMinOffset; 607452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki targetState = STATE_EXPANDED; 608f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && shouldHide(releasedChild, yvel)) { 609f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki top = mParentHeight; 610f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki targetState = STATE_HIDDEN; 61149a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } else if (yvel == 0.f) { 61249a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki int currentTop = releasedChild.getTop(); 61349a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) { 61449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki top = mMinOffset; 61549a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki targetState = STATE_EXPANDED; 61649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } else { 61749a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki top = mMaxOffset; 61849a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki targetState = STATE_COLLAPSED; 61949a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } 620452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 621452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMaxOffset; 622452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki targetState = STATE_COLLAPSED; 623452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 624452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) { 625f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(STATE_SETTLING); 626452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(releasedChild, 627452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki new SettleRunnable(releasedChild, targetState)); 628f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 629f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(targetState); 630452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 631452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 632452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 633452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 634452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public int clampViewPositionVertical(View child, int top, int dy) { 635f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return MathUtils.constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset); 636452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 637452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 638452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 639452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public int clampViewPositionHorizontal(View child, int left, int dx) { 640452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return child.getLeft(); 641452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 642f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 6439aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki @Override 6449aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki public int getViewVerticalDragRange(View child) { 6459aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (mHideable) { 6469aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return mParentHeight - mMinOffset; 6479aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } else { 6489aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return mMaxOffset - mMinOffset; 6499aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 6509aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 651452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki }; 652452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 653f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private void dispatchOnSlide(int top) { 654dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki View bottomSheet = mViewRef.get(); 655dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki if (bottomSheet != null && mCallback != null) { 656f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (top > mMaxOffset) { 657dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki mCallback.onSlide(bottomSheet, (float) (mMaxOffset - top) / mPeekHeight); 658f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 659dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki mCallback.onSlide(bottomSheet, 660dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki (float) (mMaxOffset - top) / ((mMaxOffset - mMinOffset))); 661f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 662f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 663f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 664f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 665452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private class SettleRunnable implements Runnable { 666452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 667452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final View mView; 668452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 669452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 670452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final int mTargetState; 671452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 672452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki SettleRunnable(View view, @State int targetState) { 673452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mView = view; 674452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mTargetState = targetState; 675452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 676452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 677452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 678452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void run() { 679452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) { 680452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(mView, this); 681452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 682452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(mTargetState); 683452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 684452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 685452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 686452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 68705f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes protected static class SavedState extends AbsSavedState { 688452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 689452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki final int state; 690452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 691452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState(Parcel source) { 69205f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes this(source, null); 69305f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes } 69405f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes 69505f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes public SavedState(Parcel source, ClassLoader loader) { 69605f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes super(source, loader); 697452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki //noinspection ResourceType 698452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki state = source.readInt(); 699452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 700452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 701452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState(Parcelable superState, @State int state) { 702452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super(superState); 703452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki this.state = state; 704452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 705452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 706452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 707452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void writeToParcel(Parcel out, int flags) { 708452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super.writeToParcel(out, flags); 709452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki out.writeInt(state); 710452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 711452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 71205f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator( 71305f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes new ParcelableCompatCreatorCallbacks<SavedState>() { 714452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 71505f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes public SavedState createFromParcel(Parcel in, ClassLoader loader) { 71605f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes return new SavedState(in, loader); 717452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 718452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 719452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 720452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState[] newArray(int size) { 721452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return new SavedState[size]; 722452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 72305f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes }); 724452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 725452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 726f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 727452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}. 728452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 729452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param view The {@link View} with {@link BottomSheetBehavior}. 730452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return The {@link BottomSheetBehavior} associated with the {@code view}. 731452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 732452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @SuppressWarnings("unchecked") 733452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static <V extends View> BottomSheetBehavior<V> from(V view) { 734452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewGroup.LayoutParams params = view.getLayoutParams(); 735452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (!(params instanceof CoordinatorLayout.LayoutParams)) { 736452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException("The view is not a child of CoordinatorLayout"); 737452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 738452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params) 739452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki .getBehavior(); 740452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (!(behavior instanceof BottomSheetBehavior)) { 741452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException( 742452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki "The view is not associated with BottomSheetBehavior"); 743452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 744452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return (BottomSheetBehavior<V>) behavior; 745452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 746452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 747452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki} 748