BottomSheetBehavior.java revision 73e7a06fb66110495fa4e98a91831a47feab2526
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. 71f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param slideOffset The new offset of this bottom sheet within its range, from 0 to 1 72f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * when it is moving upward, and from 0 to -1 when it moving downward. 73f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 74dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki public abstract void onSlide(@NonNull View bottomSheet, float slideOffset); 75f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 76f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 77f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 78452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is dragging. 79452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 80452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_DRAGGING = 1; 81452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 82452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 83452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is settling. 84452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 85452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_SETTLING = 2; 86452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 87452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 88452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is expanded. 89452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 90452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_EXPANDED = 3; 91452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 92452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 93452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is collapsed. 94452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 95452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_COLLAPSED = 4; 96452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 97f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 98f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * The bottom sheet is hidden. 99f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 100f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public static final int STATE_HIDDEN = 5; 101f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 102452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** @hide */ 103f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN}) 104452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Retention(RetentionPolicy.SOURCE) 105452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public @interface State {} 106452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 107f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private static final float HIDE_THRESHOLD = 0.5f; 108f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 109f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private static final float HIDE_FRICTION = 0.1f; 110f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 111e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private float mMaximumVelocity; 112f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 113452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mPeekHeight; 114452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 115452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mMinOffset; 116452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 117452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mMaxOffset; 118452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 119f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private boolean mHideable; 120f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 121452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 122452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mState = STATE_COLLAPSED; 123452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 124452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private ViewDragHelper mViewDragHelper; 125452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 126452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private boolean mIgnoreEvents; 127452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 128e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private int mLastNestedScrollDy; 129e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 13049a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki private boolean mNestedScrolled; 13149a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki 132452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mParentHeight; 133452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 134452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private WeakReference<V> mViewRef; 135452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 1369aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki private WeakReference<View> mNestedScrollingChildRef; 137f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 1389aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki private BottomSheetCallback mCallback; 139f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 140e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private VelocityTracker mVelocityTracker; 141e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 142e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private int mActivePointerId; 143f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 1444eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki private int mInitialY; 1454eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki 146b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki private boolean mTouchingScrollingChild; 147b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki 148452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 149452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Default constructor for instantiating BottomSheetBehaviors. 150452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 151452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public BottomSheetBehavior() { 152452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 153452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 154452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 155452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Default constructor for inflating BottomSheetBehaviors from layout. 156452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 157452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param context The {@link Context}. 158452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param attrs The {@link AttributeSet}. 159452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 160452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public BottomSheetBehavior(Context context, AttributeSet attrs) { 161452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super(context, attrs); 162452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki TypedArray a = context.obtainStyledAttributes(attrs, 163c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes R.styleable.BottomSheetBehavior_Layout); 164452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setPeekHeight(a.getDimensionPixelSize( 165c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight, 0)); 166c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_hideable, false)); 167452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki a.recycle(); 168e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewConfiguration configuration = ViewConfiguration.get(context); 169e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 170452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 171452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 172452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 173452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) { 174452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return new SavedState(super.onSaveInstanceState(parent, child), mState); 175452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 176452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 177452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 178452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) { 179452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki SavedState ss = (SavedState) state; 180452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super.onRestoreInstanceState(parent, child, ss.getSuperState()); 181452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Intermediate states are restored as collapsed state 182f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) { 183452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mState = STATE_COLLAPSED; 184f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 185f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mState = ss.state; 186452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 187452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 188452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 189452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 190452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) { 1916bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) { 1926bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki ViewCompat.setFitsSystemWindows(child, true); 193f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 1946bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki int savedTop = child.getTop(); 1956bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki // First let the parent lay it out 1966bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki parent.onLayoutChild(child, layoutDirection); 197452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Offset the bottom sheet 198452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mParentHeight = parent.getHeight(); 199452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mMinOffset = Math.max(0, mParentHeight - child.getHeight()); 2003bd9d18c5855600254e907d6668f2ec4d7fd1c51Yuichi Araki mMaxOffset = Math.max(mParentHeight - mPeekHeight, mMinOffset); 201452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mState == STATE_EXPANDED) { 202452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.offsetTopAndBottom(child, mMinOffset); 203f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && mState == STATE_HIDDEN) { 204f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ViewCompat.offsetTopAndBottom(child, mParentHeight); 205f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mState == STATE_COLLAPSED) { 206452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.offsetTopAndBottom(child, mMaxOffset); 2076bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki } else if (mState == STATE_DRAGGING || mState == STATE_SETTLING) { 2086bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop()); 209452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 210452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper == null) { 211452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewDragHelper = ViewDragHelper.create(parent, mDragCallback); 212452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 213452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewRef = new WeakReference<>(child); 2149aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child)); 215452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return true; 216452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 217452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 218452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 219452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) { 22017fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki if (!child.isShown()) { 22117fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki return false; 22217fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki } 223452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int action = MotionEventCompat.getActionMasked(event); 224e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki // Record the velocity 225e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (action == MotionEvent.ACTION_DOWN) { 226e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki reset(); 227e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 228e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mVelocityTracker == null) { 229e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker = VelocityTracker.obtain(); 230e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 231e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker.addMovement(event); 232452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki switch (action) { 233452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_UP: 234452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_CANCEL: 235b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki mTouchingScrollingChild = false; 236e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mActivePointerId = MotionEvent.INVALID_POINTER_ID; 237452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Reset the ignore flag 238452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mIgnoreEvents) { 239452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mIgnoreEvents = false; 240452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return false; 241452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 242452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki break; 243452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_DOWN: 2444eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki int initialX = (int) event.getX(); 2454eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki mInitialY = (int) event.getY(); 2469aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki View scroll = mNestedScrollingChildRef.get(); 2474eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki if (scroll != null && parent.isPointInChildBounds(scroll, initialX, mInitialY)) { 248e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mActivePointerId = event.getPointerId(event.getActionIndex()); 249b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki mTouchingScrollingChild = true; 2509aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 251e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mIgnoreEvents = mActivePointerId == MotionEvent.INVALID_POINTER_ID && 2524eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki !parent.isPointInChildBounds(child, initialX, mInitialY); 253452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki break; 254452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 2554eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki if (!mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event)) { 2564eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki return true; 2574eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki } 2584eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki // We have to handle cases that the ViewDragHelper does not capture the bottom sheet because 2594eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki // it is not the top most view of its parent. This is not necessary when the touch event is 2604eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki // happening over the scrolling content as nested scrolling logic handles that case. 2614eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki View scroll = mNestedScrollingChildRef.get(); 2624eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki return action == MotionEvent.ACTION_MOVE && scroll != null && 2634eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki !mIgnoreEvents && mState != STATE_DRAGGING && 2644eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki !parent.isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY()) && 2654eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop(); 266452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 267452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 268452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 269452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) { 27017fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki if (!child.isShown()) { 27117fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki return false; 27217fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki } 273e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int action = MotionEventCompat.getActionMasked(event); 274e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mState == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) { 275e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return true; 276e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 277452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewDragHelper.processTouchEvent(event); 278e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki // Record the velocity 279e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (action == MotionEvent.ACTION_DOWN) { 280e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki reset(); 281e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 282e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mVelocityTracker == null) { 283e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker = VelocityTracker.obtain(); 284e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 285e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker.addMovement(event); 2864eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki // The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it 2874eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki // to capture the bottom sheet in case it is not captured and the touch slop is passed. 288912d40d353f5b6d0a4fa18740ca40aa4b25b0f9cYuichi Araki if (action == MotionEvent.ACTION_MOVE && !mIgnoreEvents) { 2894eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki if (Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop()) { 2904eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki mViewDragHelper.captureChildView(child, event.getPointerId(event.getActionIndex())); 2914eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki } 2924eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki } 2931dbdc6baec537b45e9bd8e5afabcb5c35f1a8004Yuichi Araki return !mIgnoreEvents; 294452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 295452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 296e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki @Override 297e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, 298e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki View directTargetChild, View target, int nestedScrollAxes) { 299e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mLastNestedScrollDy = 0; 30049a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki mNestedScrolled = false; 301e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0; 302e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 303e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 304e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki @Override 305e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, 306e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int dy, int[] consumed) { 307e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki View scrollingChild = mNestedScrollingChildRef.get(); 308e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (target != scrollingChild) { 309e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return; 310e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 311e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int currentTop = child.getTop(); 312e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int newTop = currentTop - dy; 313e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (dy > 0) { // Upward 314e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (newTop < mMinOffset) { 315e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki consumed[1] = currentTop - mMinOffset; 316e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewCompat.offsetTopAndBottom(child, -consumed[1]); 317e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(STATE_EXPANDED); 318e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else { 319e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki consumed[1] = dy; 320e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewCompat.offsetTopAndBottom(child, -dy); 321e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(STATE_DRAGGING); 322e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 323e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else if (dy < 0) { // Downward 324e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (!ViewCompat.canScrollVertically(target, -1)) { 325e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (newTop <= mMaxOffset || mHideable) { 326e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki consumed[1] = dy; 327e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewCompat.offsetTopAndBottom(child, -dy); 328e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(STATE_DRAGGING); 329e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else { 330e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki consumed[1] = currentTop - mMaxOffset; 331e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewCompat.offsetTopAndBottom(child, -consumed[1]); 332e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(STATE_COLLAPSED); 333e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 334e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 335e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 336e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki dispatchOnSlide(child.getTop()); 337e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mLastNestedScrollDy = dy; 33849a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki mNestedScrolled = true; 339e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 340e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 341e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki @Override 342e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) { 343b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki if (child.getTop() == mMinOffset) { 344b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki setStateInternal(STATE_EXPANDED); 345b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki return; 346b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki } 347b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki if (target != mNestedScrollingChildRef.get() || !mNestedScrolled) { 348e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return; 349e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 350e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int top; 351e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki int targetState; 352e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mLastNestedScrollDy > 0) { 353e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki top = mMinOffset; 354e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki targetState = STATE_EXPANDED; 355e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else if (mHideable && shouldHide(child, getYVelocity())) { 356e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki top = mParentHeight; 357e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki targetState = STATE_HIDDEN; 35849a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } else if (mLastNestedScrollDy == 0) { 35949a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki int currentTop = child.getTop(); 36049a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) { 36149a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki top = mMinOffset; 36249a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki targetState = STATE_EXPANDED; 36349a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } else { 36449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki top = mMaxOffset; 36549a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki targetState = STATE_COLLAPSED; 36649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } 367e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else { 368e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki top = mMaxOffset; 369e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki targetState = STATE_COLLAPSED; 370e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 371e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { 372e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(STATE_SETTLING); 373e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState)); 374e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } else { 375e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki setStateInternal(targetState); 376e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 37749a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki mNestedScrolled = false; 378e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 379e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 380e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki @Override 381e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, 382e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki float velocityX, float velocityY) { 383e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return target == mNestedScrollingChildRef.get() && 384e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki (mState != STATE_EXPANDED || 385e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki super.onNestedPreFling(coordinatorLayout, child, target, 386e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki velocityX, velocityY)); 387e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 388e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 389452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 390452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Sets the height of the bottom sheet when it is collapsed. 391452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 392452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param peekHeight The height of the collapsed bottom sheet in pixels. 39373e7a06fb66110495fa4e98a91831a47feab2526Chris Banes * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight 394452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 395452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final void setPeekHeight(int peekHeight) { 396452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mPeekHeight = Math.max(0, peekHeight); 397452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mMaxOffset = mParentHeight - peekHeight; 398452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 399452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 400452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 401452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Gets the height of the bottom sheet when it is collapsed. 402452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 403452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return The height of the collapsed bottom sheet. 40473e7a06fb66110495fa4e98a91831a47feab2526Chris Banes * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight 405452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 406452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final int getPeekHeight() { 407452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return mPeekHeight; 408452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 409452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 410452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 411f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Sets whether this bottom sheet can hide when it is swiped down. 412f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 413f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param hideable {@code true} to make this bottom sheet hideable. 41473e7a06fb66110495fa4e98a91831a47feab2526Chris Banes * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable 415f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 416f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public void setHideable(boolean hideable) { 417f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mHideable = hideable; 418f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 419f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 420f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 421f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Gets whether this bottom sheet can hide when it is swiped down. 422f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 423f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @return {@code true} if this bottom sheet can hide. 42473e7a06fb66110495fa4e98a91831a47feab2526Chris Banes * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable 425f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 426f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public boolean isHideable() { 427f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return mHideable; 428f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 429f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 430f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 4314df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * Sets a callback to be notified of bottom sheet events. 432f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 4334df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * @param callback The callback to notify when bottom sheet events occur. 434f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 4354df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki public void setBottomSheetCallback(BottomSheetCallback callback) { 4364df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki mCallback = callback; 437f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 438f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 439f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 440452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Sets the state of the bottom sheet. The bottom sheet will transition to that state with 441452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * animation. 442452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 443f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, or 444f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * {@link #STATE_HIDDEN}. 445452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 446452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final void setState(@State int state) { 447e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki if (state == mState) { 448e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki return; 449e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki } 45098475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim if (mViewRef == null) { 4516deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki // The view is not laid out yet; modify mState and let onLayoutChild handle it later 4526deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki if (state == STATE_COLLAPSED || state == STATE_EXPANDED || 4536deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki (mHideable && state == STATE_HIDDEN)) { 4546deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki mState = state; 4556deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki } 45698475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim return; 45798475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim } 458452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki V child = mViewRef.get(); 459452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (child == null) { 460452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return; 461452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 462452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int top; 463452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (state == STATE_COLLAPSED) { 464452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMaxOffset; 465452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else if (state == STATE_EXPANDED) { 466452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMinOffset; 467f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && state == STATE_HIDDEN) { 468f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki top = mParentHeight; 469452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 470452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException("Illegal state argument: " + state); 471452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 472452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_SETTLING); 473452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { 474452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(child, new SettleRunnable(child, state)); 475452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 476452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 477452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 478452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 479452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Gets the current state of the bottom sheet. 480452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 481452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING}, 482452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * and {@link #STATE_SETTLING}. 483452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 484452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 485452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final int getState() { 486452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return mState; 487452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 488452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 489452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private void setStateInternal(@State int state) { 490452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mState == state) { 491452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return; 492452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 493452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mState = state; 494dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki View bottomSheet = mViewRef.get(); 495dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki if (bottomSheet != null && mCallback != null) { 496dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki mCallback.onStateChanged(bottomSheet, state); 497f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 498f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 499f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 500e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private void reset() { 501e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mActivePointerId = ViewDragHelper.INVALID_POINTER; 502e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mVelocityTracker != null) { 503e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker.recycle(); 504e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker = null; 505e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 506e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 507e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 508f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private boolean shouldHide(View child, float yvel) { 509f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (child.getTop() < mMaxOffset) { 510f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki // It should not hide, but collapse. 511f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return false; 512f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 513f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki final float newTop = child.getTop() + yvel * HIDE_FRICTION; 514f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return Math.abs(newTop - mMaxOffset) / (float) mPeekHeight > HIDE_THRESHOLD; 515f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 516f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 5179aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki private View findScrollingChild(View view) { 5189aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (view instanceof NestedScrollingChild) { 5199aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return view; 5209aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 5219aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (view instanceof ViewGroup) { 5229aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki ViewGroup group = (ViewGroup) view; 5239aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki for (int i = 0, count = group.getChildCount(); i < count; i++) { 5249aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki View scrollingChild = findScrollingChild(group.getChildAt(i)); 5259aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (scrollingChild != null) { 5269aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return scrollingChild; 5279aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 5289aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 5299aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 5309aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return null; 531452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 532452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 533e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki private float getYVelocity() { 534e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 535e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId); 536e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 537e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki 538452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() { 539452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 540452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 541452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean tryCaptureView(View child, int pointerId) { 542e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mState == STATE_DRAGGING) { 543e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki return false; 544e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki } 545b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki if (mTouchingScrollingChild) { 546b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki return false; 547b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki } 548e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki if (mState == STATE_EXPANDED && mActivePointerId == pointerId) { 5499aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki View scroll = mNestedScrollingChildRef.get(); 5509aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (scroll != null && ViewCompat.canScrollVertically(scroll, -1)) { 5519aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki // Let the content scroll up 5529aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return false; 5539aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 5549aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 555f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return mViewRef != null && mViewRef.get() == child; 556f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 557f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 558f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki @Override 559f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { 560f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki dispatchOnSlide(top); 561452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 562452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 563452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 564452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onViewDragStateChanged(int state) { 565452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (state == ViewDragHelper.STATE_DRAGGING) { 566452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_DRAGGING); 567452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 568452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 569452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 570452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 571452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onViewReleased(View releasedChild, float xvel, float yvel) { 572452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int top; 573452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State int targetState; 574f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (yvel < 0) { // Moving up 575452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMinOffset; 576452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki targetState = STATE_EXPANDED; 577f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && shouldHide(releasedChild, yvel)) { 578f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki top = mParentHeight; 579f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki targetState = STATE_HIDDEN; 58049a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } else if (yvel == 0.f) { 58149a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki int currentTop = releasedChild.getTop(); 58249a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) { 58349a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki top = mMinOffset; 58449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki targetState = STATE_EXPANDED; 58549a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } else { 58649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki top = mMaxOffset; 58749a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki targetState = STATE_COLLAPSED; 58849a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki } 589452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 590452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMaxOffset; 591452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki targetState = STATE_COLLAPSED; 592452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 593452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) { 594f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(STATE_SETTLING); 595452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(releasedChild, 596452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki new SettleRunnable(releasedChild, targetState)); 597f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 598f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(targetState); 599452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 600452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 601452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 602452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 603452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public int clampViewPositionVertical(View child, int top, int dy) { 604f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return MathUtils.constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset); 605452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 606452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 607452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 608452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public int clampViewPositionHorizontal(View child, int left, int dx) { 609452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return child.getLeft(); 610452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 611f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 6129aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki @Override 6139aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki public int getViewVerticalDragRange(View child) { 6149aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (mHideable) { 6159aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return mParentHeight - mMinOffset; 6169aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } else { 6179aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return mMaxOffset - mMinOffset; 6189aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 6199aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 620452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki }; 621452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 622f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private void dispatchOnSlide(int top) { 623dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki View bottomSheet = mViewRef.get(); 624dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki if (bottomSheet != null && mCallback != null) { 625f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (top > mMaxOffset) { 626dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki mCallback.onSlide(bottomSheet, (float) (mMaxOffset - top) / mPeekHeight); 627f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 628dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki mCallback.onSlide(bottomSheet, 629dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki (float) (mMaxOffset - top) / ((mMaxOffset - mMinOffset))); 630f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 631f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 632f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 633f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 634452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private class SettleRunnable implements Runnable { 635452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 636452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final View mView; 637452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 638452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 639452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final int mTargetState; 640452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 641452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki SettleRunnable(View view, @State int targetState) { 642452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mView = view; 643452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mTargetState = targetState; 644452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 645452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 646452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 647452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void run() { 648452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) { 649452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(mView, this); 650452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 651452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(mTargetState); 652452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 653452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 654452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 655452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 65605f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes protected static class SavedState extends AbsSavedState { 657452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 658452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki final int state; 659452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 660452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState(Parcel source) { 66105f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes this(source, null); 66205f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes } 66305f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes 66405f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes public SavedState(Parcel source, ClassLoader loader) { 66505f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes super(source, loader); 666452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki //noinspection ResourceType 667452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki state = source.readInt(); 668452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 669452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 670452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState(Parcelable superState, @State int state) { 671452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super(superState); 672452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki this.state = state; 673452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 674452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 675452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 676452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void writeToParcel(Parcel out, int flags) { 677452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super.writeToParcel(out, flags); 678452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki out.writeInt(state); 679452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 680452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 68105f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator( 68205f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes new ParcelableCompatCreatorCallbacks<SavedState>() { 683452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 68405f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes public SavedState createFromParcel(Parcel in, ClassLoader loader) { 68505f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes return new SavedState(in, loader); 686452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 687452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 688452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 689452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState[] newArray(int size) { 690452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return new SavedState[size]; 691452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 69205f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes }); 693452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 694452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 695f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 696452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}. 697452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 698452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param view The {@link View} with {@link BottomSheetBehavior}. 699452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return The {@link BottomSheetBehavior} associated with the {@code view}. 700452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 701452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @SuppressWarnings("unchecked") 702452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static <V extends View> BottomSheetBehavior<V> from(V view) { 703452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewGroup.LayoutParams params = view.getLayoutParams(); 704452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (!(params instanceof CoordinatorLayout.LayoutParams)) { 705452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException("The view is not a child of CoordinatorLayout"); 706452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 707452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params) 708452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki .getBehavior(); 709452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (!(behavior instanceof BottomSheetBehavior)) { 710452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException( 711452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki "The view is not associated with BottomSheetBehavior"); 712452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 713452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return (BottomSheetBehavior<V>) behavior; 714452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 715452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 716452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki} 717