BottomSheetBehavior.java revision 4df3c15e330c2f9730d3aa712f57befec8536dff
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; 21f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.os.Build; 22452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.os.Parcel; 23452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.os.Parcelable; 24452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.annotation.IntDef; 25452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.design.R; 26452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.MotionEventCompat; 27f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.support.v4.view.VelocityTrackerCompat; 28452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.ViewCompat; 29452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.widget.ViewDragHelper; 30452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.util.AttributeSet; 31452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.MotionEvent; 32f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.view.VelocityTracker; 33452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.View; 34f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.view.ViewConfiguration; 35452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.ViewGroup; 36f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.view.ViewParent; 37452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 38452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.Retention; 39452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.RetentionPolicy; 40452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.ref.WeakReference; 41452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 42452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 43452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki/** 44452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as 45452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * a bottom sheet. 46452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 47452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakipublic class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> { 48452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 49452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 504df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * Callback for monitoring events about bottom sheets. 51f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 524df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki public abstract static class BottomSheetCallback { 53f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 54f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 55f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Called when the bottom sheet changes its state. 56f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 57f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param newState The new state. This will be one of {@link #STATE_DRAGGING}, 58f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * {@link #STATE_SETTLING}, {@link #STATE_EXPANDED}, 59f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * {@link #STATE_COLLAPSED}, or {@link #STATE_HIDDEN}. 60f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 61f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public abstract void onStateChanged(@State int newState); 62f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 63f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 64f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Called when the bottom sheet is being dragged. 65f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 66f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param slideOffset The new offset of this bottom sheet within its range, from 0 to 1 67f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * when it is moving upward, and from 0 to -1 when it moving downward. 68f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 69f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public abstract void onSlide(float slideOffset); 70f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 71f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 72f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 73452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is dragging. 74452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 75452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_DRAGGING = 1; 76452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 77452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 78452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is settling. 79452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 80452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_SETTLING = 2; 81452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 82452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 83452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is expanded. 84452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 85452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_EXPANDED = 3; 86452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 87452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 88452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is collapsed. 89452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 90452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_COLLAPSED = 4; 91452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 92f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 93f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * The bottom sheet is hidden. 94f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 95f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public static final int STATE_HIDDEN = 5; 96f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 97452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** @hide */ 98f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN}) 99452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Retention(RetentionPolicy.SOURCE) 100452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public @interface State {} 101452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 102f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private static final float HIDE_THRESHOLD = 0.5f; 103f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 104f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private static final float HIDE_FRICTION = 0.1f; 105f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 106f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki // Whether to enable workaround for black non-rendered square 107f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private static final boolean NEEDS_INVALIDATING = Build.VERSION.SDK_INT < 23; 108f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 109f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private float mMaximumVelocity; 110f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 111452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mPeekHeight; 112452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 113452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mMinOffset; 114452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 115452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mMaxOffset; 116452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 117f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private boolean mHideable; 118f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 119452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 120452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mState = STATE_COLLAPSED; 121452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 122452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private ViewDragHelper mViewDragHelper; 123452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 124452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private boolean mIgnoreEvents; 125452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 126452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mLastNestedScrollDy; 127452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 128452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mParentHeight; 129452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 130452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private WeakReference<V> mViewRef; 131452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 1324df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki private BottomSheetCallback mCallback; 133f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 134f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private VelocityTracker mVelocityTracker; 135f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 136f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private int mActivePointerId; 137f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 138452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 139452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Default constructor for instantiating BottomSheetBehaviors. 140452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 141452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public BottomSheetBehavior() { 142452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 143452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 144452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 145452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Default constructor for inflating BottomSheetBehaviors from layout. 146452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 147452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param context The {@link Context}. 148452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param attrs The {@link AttributeSet}. 149452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 150452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public BottomSheetBehavior(Context context, AttributeSet attrs) { 151452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super(context, attrs); 152452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki TypedArray a = context.obtainStyledAttributes(attrs, 153452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki R.styleable.BottomSheetBehavior_Params); 154452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setPeekHeight(a.getDimensionPixelSize( 155452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki R.styleable.BottomSheetBehavior_Params_behavior_peekHeight, 0)); 156f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Params_behavior_hideable, false)); 157452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki a.recycle(); 158f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ViewConfiguration configuration = ViewConfiguration.get(context); 159f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 160452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 161452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 162452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 163452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) { 164452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return new SavedState(super.onSaveInstanceState(parent, child), mState); 165452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 166452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 167452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 168452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) { 169452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki SavedState ss = (SavedState) state; 170452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super.onRestoreInstanceState(parent, child, ss.getSuperState()); 171452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Intermediate states are restored as collapsed state 172f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) { 173452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mState = STATE_COLLAPSED; 174f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 175f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mState = ss.state; 176452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 177452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 178452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 179452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 180452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) { 181452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // First let the parent lay it out 182f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (mState != STATE_DRAGGING && mState != STATE_SETTLING) { 183f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki parent.onLayoutChild(child, layoutDirection); 184f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 185452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Offset the bottom sheet 186452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mParentHeight = parent.getHeight(); 187452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mMinOffset = Math.max(0, mParentHeight - child.getHeight()); 188452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mMaxOffset = mParentHeight - mPeekHeight; 189452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mState == STATE_EXPANDED) { 190452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.offsetTopAndBottom(child, mMinOffset); 191f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && mState == STATE_HIDDEN) { 192f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ViewCompat.offsetTopAndBottom(child, mParentHeight); 193f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mState == STATE_COLLAPSED) { 194452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.offsetTopAndBottom(child, mMaxOffset); 195452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 196452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper == null) { 197452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewDragHelper = ViewDragHelper.create(parent, mDragCallback); 198452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 199452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewRef = new WeakReference<>(child); 200452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return true; 201452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 202452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 203452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 204452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) { 205452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int action = MotionEventCompat.getActionMasked(event); 206f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki // Record the velocity 207f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (action == MotionEvent.ACTION_DOWN) { 208f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki reset(); 209f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 210f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (mVelocityTracker == null) { 211f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mVelocityTracker = VelocityTracker.obtain(); 212f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 213f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mVelocityTracker.addMovement(event); 214452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki switch (action) { 215452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_UP: 216452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_CANCEL: 217452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Reset the ignore flag 218452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mIgnoreEvents) { 219452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mIgnoreEvents = false; 220452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return false; 221452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 222452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki break; 223452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_DOWN: 224452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mIgnoreEvents = !parent.isPointInChildBounds(child, 225452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki (int) event.getX(), (int) event.getY()); 226f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mActivePointerId = MotionEventCompat.getPointerId(event, 0); 227452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki break; 228452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 229452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return !mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event); 230452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 231452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 232452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 233452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) { 234452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewDragHelper.processTouchEvent(event); 235f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki // Record the velocity 236f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { 237f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki reset(); 238f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 239f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (mVelocityTracker == null) { 240f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mVelocityTracker = VelocityTracker.obtain(); 241f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 242f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mVelocityTracker.addMovement(event); 243452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return true; 244452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 245452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 246452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 247452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, 248452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki View directTargetChild, View target, int nestedScrollAxes) { 249452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mLastNestedScrollDy = 0; 250452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0; 251452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 252452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 253452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 254452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, 255452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int dy, int[] consumed) { 256452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int currentTop = child.getTop(); 257452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int newTop = currentTop - dy; 258f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (dy > 0) { // Upward 259452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (newTop < mMinOffset) { 260452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki consumed[1] = currentTop - mMinOffset; 261452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki child.offsetTopAndBottom(-consumed[1]); 262f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (NEEDS_INVALIDATING && mState != STATE_EXPANDED) { 263f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki child.invalidate(); 264f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 265452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_EXPANDED); 266452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 267452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki consumed[1] = dy; 268452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki child.offsetTopAndBottom(-dy); 269452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_DRAGGING); 270f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (NEEDS_INVALIDATING) { 271f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki child.invalidate(); 272f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 273452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 274f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (dy < 0) { // Downward 275452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (!ViewCompat.canScrollVertically(target, -1)) { 276f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (newTop <= mMaxOffset || mHideable) { 277452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki consumed[1] = dy; 278452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki child.offsetTopAndBottom(-dy); 279452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_DRAGGING); 280f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (NEEDS_INVALIDATING) { 281f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki coordinatorLayout.invalidate(child.getLeft(), currentTop, 282f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki child.getRight(), coordinatorLayout.getHeight()); 283f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 284f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 285f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki consumed[1] = currentTop - mMaxOffset; 286f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki child.offsetTopAndBottom(-consumed[1]); 287f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(STATE_COLLAPSED); 288452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 289452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 290452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 291f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki dispatchOnSlide(child.getTop()); 292452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mLastNestedScrollDy = dy; 293452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 294452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 295452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 296452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) { 297f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (child.getTop() == mMinOffset) { 298452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return; 299452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 300452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int top; 301452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int targetState; 302452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mLastNestedScrollDy > 0) { 303452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMinOffset; 304452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki targetState = STATE_EXPANDED; 305f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && shouldHide(child, getYVelocity())) { 306f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki top = mParentHeight; 307f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki targetState = STATE_HIDDEN; 308452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 309452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMaxOffset; 310452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki targetState = STATE_COLLAPSED; 311452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 312452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { 313f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(STATE_SETTLING); 314452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState)); 315f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 316f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(targetState); 317452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 318452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 319452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 320f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki @Override 321f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, 322f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki float velocityX, float velocityY) { 323f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return mState != STATE_EXPANDED || 324f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY); 325f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 326f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 327452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 328452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Sets the height of the bottom sheet when it is collapsed. 329452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 330452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param peekHeight The height of the collapsed bottom sheet in pixels. 331452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight 332452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 333452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final void setPeekHeight(int peekHeight) { 334452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mPeekHeight = Math.max(0, peekHeight); 335452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mMaxOffset = mParentHeight - peekHeight; 336452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 337452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 338452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 339452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Gets the height of the bottom sheet when it is collapsed. 340452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 341452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return The height of the collapsed bottom sheet. 342452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight 343452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 344452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final int getPeekHeight() { 345452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return mPeekHeight; 346452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 347452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 348452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 349f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Sets whether this bottom sheet can hide when it is swiped down. 350f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 351f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param hideable {@code true} to make this bottom sheet hideable. 352f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_hideable 353f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 354f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public void setHideable(boolean hideable) { 355f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mHideable = hideable; 356f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 357f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 358f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 359f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Gets whether this bottom sheet can hide when it is swiped down. 360f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 361f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @return {@code true} if this bottom sheet can hide. 362f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_hideable 363f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 364f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public boolean isHideable() { 365f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return mHideable; 366f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 367f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 368f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 3694df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * Sets a callback to be notified of bottom sheet events. 370f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 3714df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * @param callback The callback to notify when bottom sheet events occur. 372f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 3734df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki public void setBottomSheetCallback(BottomSheetCallback callback) { 3744df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki mCallback = callback; 375f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 376f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 377f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 378452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Sets the state of the bottom sheet. The bottom sheet will transition to that state with 379452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * animation. 380452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 381f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, or 382f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * {@link #STATE_HIDDEN}. 383452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 384452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final void setState(@State int state) { 385452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki V child = mViewRef.get(); 386452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (child == null) { 387452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return; 388452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 389452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int top; 390452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (state == STATE_COLLAPSED) { 391452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMaxOffset; 392452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else if (state == STATE_EXPANDED) { 393452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMinOffset; 394f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && state == STATE_HIDDEN) { 395f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki top = mParentHeight; 396452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 397452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException("Illegal state argument: " + state); 398452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 399452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_SETTLING); 400452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { 401452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(child, new SettleRunnable(child, state)); 402452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 403452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 404452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 405452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 406452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Gets the current state of the bottom sheet. 407452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 408452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING}, 409452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * and {@link #STATE_SETTLING}. 410452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 411452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 412452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final int getState() { 413452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return mState; 414452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 415452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 416452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private void setStateInternal(@State int state) { 417452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mState == state) { 418452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return; 419452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 420452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mState = state; 4214df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki if (mCallback != null) { 4224df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki mCallback.onStateChanged(state); 423f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 424f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 425f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 426f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private void reset() { 427f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mActivePointerId = ViewDragHelper.INVALID_POINTER; 428f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (mVelocityTracker != null) { 429f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mVelocityTracker.recycle(); 430f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mVelocityTracker = null; 431f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 432f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 433f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 434f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private boolean shouldHide(View child, float yvel) { 435f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (child.getTop() < mMaxOffset) { 436f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki // It should not hide, but collapse. 437f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return false; 438f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 439f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki final float newTop = child.getTop() + yvel * HIDE_FRICTION; 440f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return Math.abs(newTop - mMaxOffset) / (float) mPeekHeight > HIDE_THRESHOLD; 441f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 442f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 443f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private float getYVelocity() { 444f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 445f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId); 446452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 447452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 448452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() { 449452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 450452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 451452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean tryCaptureView(View child, int pointerId) { 452f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return mViewRef != null && mViewRef.get() == child; 453f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 454f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 455f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki @Override 456f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { 457f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki dispatchOnSlide(top); 458f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (NEEDS_INVALIDATING) { 459f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (dy < 0) { // Upward 460f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki changedView.invalidate(); 461f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { // Downward 462f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ViewParent parent = changedView.getParent(); 463f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (parent instanceof View) { 464f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki View v = (View) parent; 465f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki v.invalidate(changedView.getLeft(), top - dy, 466f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki changedView.getRight(), v.getHeight()); 467f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 468f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 469f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 470452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 471452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 472452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 473452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onViewDragStateChanged(int state) { 474452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (state == ViewDragHelper.STATE_DRAGGING) { 475452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_DRAGGING); 476452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 477452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 478452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 479452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 480452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onViewReleased(View releasedChild, float xvel, float yvel) { 481452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int top; 482452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State int targetState; 483f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (yvel < 0) { // Moving up 484452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMinOffset; 485452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki targetState = STATE_EXPANDED; 486f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && shouldHide(releasedChild, yvel)) { 487f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki top = mParentHeight; 488f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki targetState = STATE_HIDDEN; 489452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 490452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMaxOffset; 491452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki targetState = STATE_COLLAPSED; 492452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 493452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) { 494f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(STATE_SETTLING); 495452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(releasedChild, 496452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki new SettleRunnable(releasedChild, targetState)); 497f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 498f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(targetState); 499452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 500452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 501452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 502452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 503452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public int clampViewPositionVertical(View child, int top, int dy) { 504f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return MathUtils.constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset); 505452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 506452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 507452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 508452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public int clampViewPositionHorizontal(View child, int left, int dx) { 509452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return child.getLeft(); 510452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 511f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 512452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki }; 513452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 514f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private void dispatchOnSlide(int top) { 5154df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki if (mCallback != null) { 516f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (top > mMaxOffset) { 5174df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki mCallback.onSlide((float) (mMaxOffset - top) / mPeekHeight); 518f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 5194df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki mCallback.onSlide((float) (mMaxOffset - top) / ((mMaxOffset - mMinOffset))); 520f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 521f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 522f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 523f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 524452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private class SettleRunnable implements Runnable { 525452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 526452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final View mView; 527452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 528452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 529452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final int mTargetState; 530452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 531452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki SettleRunnable(View view, @State int targetState) { 532452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mView = view; 533452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mTargetState = targetState; 534f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (NEEDS_INVALIDATING) { 535f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki // We need to invalidate the parent here, or the following animation won't be drawn. 536f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ViewParent parent = mView.getParent(); 537f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (parent instanceof View) { 538f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ((View) parent).invalidate(); 539f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 540f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 541452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 542452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 543452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 544452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void run() { 545452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) { 546452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(mView, this); 547452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 548452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(mTargetState); 549452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 550452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 551452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 552452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 553452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki protected static class SavedState extends View.BaseSavedState { 554452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 555452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 556452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki final int state; 557452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 558452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState(Parcel source) { 559452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super(source); 560452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki //noinspection ResourceType 561452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki state = source.readInt(); 562452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 563452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 564452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState(Parcelable superState, @State int state) { 565452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super(superState); 566452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki this.state = state; 567452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 568452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 569452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 570452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void writeToParcel(Parcel out, int flags) { 571452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super.writeToParcel(out, flags); 572452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki out.writeInt(state); 573452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 574452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 575452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final Parcelable.Creator<SavedState> CREATOR = 576452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki new Parcelable.Creator<SavedState>() { 577452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 578452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState createFromParcel(Parcel source) { 579452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return new SavedState(source); 580452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 581452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 582452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 583452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState[] newArray(int size) { 584452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return new SavedState[size]; 585452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 586452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki }; 587452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 588452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 589f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 590452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}. 591452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 592452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param view The {@link View} with {@link BottomSheetBehavior}. 593452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return The {@link BottomSheetBehavior} associated with the {@code view}. 594452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 595452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @SuppressWarnings("unchecked") 596452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static <V extends View> BottomSheetBehavior<V> from(V view) { 597452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewGroup.LayoutParams params = view.getLayoutParams(); 598452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (!(params instanceof CoordinatorLayout.LayoutParams)) { 599452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException("The view is not a child of CoordinatorLayout"); 600452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 601452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params) 602452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki .getBehavior(); 603452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (!(behavior instanceof BottomSheetBehavior)) { 604452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException( 605452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki "The view is not associated with BottomSheetBehavior"); 606452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 607452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return (BottomSheetBehavior<V>) behavior; 608452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 609452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 610452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki} 611