BottomSheetBehavior.java revision 17fc77f5ca7c91daeab2e110669d9baf9d1a8090
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; 25dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Arakiimport android.support.annotation.NonNull; 26452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.design.R; 27452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.MotionEventCompat; 289aec720809a123c6193304730acf8b55d6ce5a7aYuichi Arakiimport android.support.v4.view.NestedScrollingChild; 29452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.ViewCompat; 30452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.widget.ViewDragHelper; 31452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.util.AttributeSet; 32452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.MotionEvent; 33452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.View; 34452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.ViewGroup; 35f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.view.ViewParent; 36452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 37452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.Retention; 38452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.RetentionPolicy; 39452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.ref.WeakReference; 40452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 41452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 42452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki/** 43452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as 44452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * a bottom sheet. 45452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 46452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakipublic class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> { 47452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 48452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 494df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * Callback for monitoring events about bottom sheets. 50f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 514df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki public abstract static class BottomSheetCallback { 52f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 53f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 54f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Called when the bottom sheet changes its state. 55f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 56dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki * @param bottomSheet The bottom sheet view. 57dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki * @param newState The new state. This will be one of {@link #STATE_DRAGGING}, 58dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki * {@link #STATE_SETTLING}, {@link #STATE_EXPANDED}, 59dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki * {@link #STATE_COLLAPSED}, or {@link #STATE_HIDDEN}. 60f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 61dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki public abstract void onStateChanged(@NonNull View bottomSheet, @State int newState); 62f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 63f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 64f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Called when the bottom sheet is being dragged. 65f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 66dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki * @param bottomSheet The bottom sheet view. 67f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param slideOffset The new offset of this bottom sheet within its range, from 0 to 1 68f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * when it is moving upward, and from 0 to -1 when it moving downward. 69f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 70dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki public abstract void onSlide(@NonNull View bottomSheet, float slideOffset); 71f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 72f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 73f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 74452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is dragging. 75452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 76452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_DRAGGING = 1; 77452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 78452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 79452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is settling. 80452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 81452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_SETTLING = 2; 82452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 83452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 84452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is expanded. 85452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 86452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_EXPANDED = 3; 87452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 88452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 89452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * The bottom sheet is collapsed. 90452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 91452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final int STATE_COLLAPSED = 4; 92452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 93f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 94f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * The bottom sheet is hidden. 95f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 96f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public static final int STATE_HIDDEN = 5; 97f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 98452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** @hide */ 99f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN}) 100452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Retention(RetentionPolicy.SOURCE) 101452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public @interface State {} 102452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 103f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private static final float HIDE_THRESHOLD = 0.5f; 104f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 105f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private static final float HIDE_FRICTION = 0.1f; 106f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 107f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki // Whether to enable workaround for black non-rendered square 108f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private static final boolean NEEDS_INVALIDATING = Build.VERSION.SDK_INT < 23; 109f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 110452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mPeekHeight; 111452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 112452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mMinOffset; 113452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 114452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mMaxOffset; 115452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 116f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private boolean mHideable; 117f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 118452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 119452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mState = STATE_COLLAPSED; 120452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 121452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private ViewDragHelper mViewDragHelper; 122452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 123452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private boolean mIgnoreEvents; 124452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 125452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private int mParentHeight; 126452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 127452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private WeakReference<V> mViewRef; 128452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 1299aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki private WeakReference<View> mNestedScrollingChildRef; 130f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 1319aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki private BottomSheetCallback mCallback; 132f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 1339aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki private int mScrollingChildPointerId = MotionEvent.INVALID_POINTER_ID; 134f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 135452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 136452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Default constructor for instantiating BottomSheetBehaviors. 137452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 138452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public BottomSheetBehavior() { 139452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 140452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 141452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 142452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Default constructor for inflating BottomSheetBehaviors from layout. 143452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 144452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param context The {@link Context}. 145452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param attrs The {@link AttributeSet}. 146452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 147452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public BottomSheetBehavior(Context context, AttributeSet attrs) { 148452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super(context, attrs); 149452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki TypedArray a = context.obtainStyledAttributes(attrs, 150452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki R.styleable.BottomSheetBehavior_Params); 151452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setPeekHeight(a.getDimensionPixelSize( 152452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki R.styleable.BottomSheetBehavior_Params_behavior_peekHeight, 0)); 153f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Params_behavior_hideable, false)); 154452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki a.recycle(); 155452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 156452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 157452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 158452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) { 159452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return new SavedState(super.onSaveInstanceState(parent, child), mState); 160452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 161452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 162452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 163452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) { 164452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki SavedState ss = (SavedState) state; 165452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super.onRestoreInstanceState(parent, child, ss.getSuperState()); 166452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Intermediate states are restored as collapsed state 167f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) { 168452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mState = STATE_COLLAPSED; 169f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 170f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mState = ss.state; 171452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 172452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 173452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 174452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 175452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) { 176452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // First let the parent lay it out 177f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (mState != STATE_DRAGGING && mState != STATE_SETTLING) { 178f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki parent.onLayoutChild(child, layoutDirection); 179f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 180452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Offset the bottom sheet 181452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mParentHeight = parent.getHeight(); 182452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mMinOffset = Math.max(0, mParentHeight - child.getHeight()); 183452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mMaxOffset = mParentHeight - mPeekHeight; 184452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mState == STATE_EXPANDED) { 185452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.offsetTopAndBottom(child, mMinOffset); 186f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && mState == STATE_HIDDEN) { 187f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ViewCompat.offsetTopAndBottom(child, mParentHeight); 188f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mState == STATE_COLLAPSED) { 189452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.offsetTopAndBottom(child, mMaxOffset); 190452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 191452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper == null) { 192452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewDragHelper = ViewDragHelper.create(parent, mDragCallback); 193452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 194452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewRef = new WeakReference<>(child); 1959aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child)); 196452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return true; 197452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 198452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 199452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 200452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) { 20117fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki if (!child.isShown()) { 20217fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki return false; 20317fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki } 204452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int action = MotionEventCompat.getActionMasked(event); 205452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki switch (action) { 206452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_UP: 207452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_CANCEL: 2089aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki mScrollingChildPointerId = MotionEvent.INVALID_POINTER_ID; 209452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki // Reset the ignore flag 210452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mIgnoreEvents) { 211452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mIgnoreEvents = false; 212452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return false; 213452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 214452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki break; 215452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki case MotionEvent.ACTION_DOWN: 2169aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki int x = (int) event.getX(); 2179aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki int y = (int) event.getY(); 2189aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki View scroll = mNestedScrollingChildRef.get(); 2199aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (scroll != null && parent.isPointInChildBounds(scroll, x, y)) { 2209aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki mScrollingChildPointerId = event.getPointerId(event.getActionIndex()); 2219aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } else { 2229aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki mScrollingChildPointerId = MotionEvent.INVALID_POINTER_ID; 2239aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 2249aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki mIgnoreEvents = mScrollingChildPointerId == MotionEvent.INVALID_POINTER_ID && 2259aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki !parent.isPointInChildBounds(child, x, y); 226452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki break; 227452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 228452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return !mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event); 229452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 230452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 231452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 232452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) { 23317fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki if (!child.isShown()) { 23417fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki return false; 23517fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki } 236452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mViewDragHelper.processTouchEvent(event); 237452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return true; 238452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 239452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 240452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 241452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Sets the height of the bottom sheet when it is collapsed. 242452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 243452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param peekHeight The height of the collapsed bottom sheet in pixels. 244452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight 245452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 246452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final void setPeekHeight(int peekHeight) { 247452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mPeekHeight = Math.max(0, peekHeight); 248452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mMaxOffset = mParentHeight - peekHeight; 249452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 250452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 251452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 252452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Gets the height of the bottom sheet when it is collapsed. 253452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 254452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return The height of the collapsed bottom sheet. 255452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight 256452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 257452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final int getPeekHeight() { 258452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return mPeekHeight; 259452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 260452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 261452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 262f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Sets whether this bottom sheet can hide when it is swiped down. 263f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 264f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param hideable {@code true} to make this bottom sheet hideable. 265f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_hideable 266f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 267f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public void setHideable(boolean hideable) { 268f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki mHideable = hideable; 269f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 270f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 271f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 272f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * Gets whether this bottom sheet can hide when it is swiped down. 273f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 274f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @return {@code true} if this bottom sheet can hide. 275f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_hideable 276f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 277f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public boolean isHideable() { 278f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return mHideable; 279f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 280f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 281f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 2824df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * Sets a callback to be notified of bottom sheet events. 283f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * 2844df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki * @param callback The callback to notify when bottom sheet events occur. 285f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki */ 2864df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki public void setBottomSheetCallback(BottomSheetCallback callback) { 2874df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki mCallback = callback; 288f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 289f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 290f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 291452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Sets the state of the bottom sheet. The bottom sheet will transition to that state with 292452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * animation. 293452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 294f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, or 295f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki * {@link #STATE_HIDDEN}. 296452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 297452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final void setState(@State int state) { 298452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki V child = mViewRef.get(); 299452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (child == null) { 300452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return; 301452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 302452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int top; 303452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (state == STATE_COLLAPSED) { 304452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMaxOffset; 305452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else if (state == STATE_EXPANDED) { 306452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMinOffset; 307f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && state == STATE_HIDDEN) { 308f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki top = mParentHeight; 309452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 310452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException("Illegal state argument: " + state); 311452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 312452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_SETTLING); 313452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { 314452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(child, new SettleRunnable(child, state)); 315452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 316452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 317452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 318452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki /** 319452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Gets the current state of the bottom sheet. 320452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 321452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING}, 322452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * and {@link #STATE_SETTLING}. 323452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 324452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 325452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public final int getState() { 326452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return mState; 327452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 328452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 329452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private void setStateInternal(@State int state) { 330452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mState == state) { 331452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return; 332452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 333452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mState = state; 334dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki View bottomSheet = mViewRef.get(); 335dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki if (bottomSheet != null && mCallback != null) { 336dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki mCallback.onStateChanged(bottomSheet, state); 337f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 338f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 339f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 340f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private boolean shouldHide(View child, float yvel) { 341f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (child.getTop() < mMaxOffset) { 342f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki // It should not hide, but collapse. 343f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return false; 344f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 345f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki final float newTop = child.getTop() + yvel * HIDE_FRICTION; 346f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return Math.abs(newTop - mMaxOffset) / (float) mPeekHeight > HIDE_THRESHOLD; 347f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 348f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 3499aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki private View findScrollingChild(View view) { 3509aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (view instanceof NestedScrollingChild) { 3519aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return view; 3529aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 3539aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (view instanceof ViewGroup) { 3549aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki ViewGroup group = (ViewGroup) view; 3559aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki for (int i = 0, count = group.getChildCount(); i < count; i++) { 3569aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki View scrollingChild = findScrollingChild(group.getChildAt(i)); 3579aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (scrollingChild != null) { 3589aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return scrollingChild; 3599aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 3609aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 3619aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 3629aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return null; 363452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 364452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 365452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() { 366452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 367452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 368452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public boolean tryCaptureView(View child, int pointerId) { 3699aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (mState == STATE_EXPANDED && mScrollingChildPointerId == pointerId) { 3709aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki View scroll = mNestedScrollingChildRef.get(); 3719aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (scroll != null && ViewCompat.canScrollVertically(scroll, -1)) { 3729aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki // Let the content scroll up 3739aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return false; 3749aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 3759aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 376f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return mViewRef != null && mViewRef.get() == child; 377f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 378f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 379f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki @Override 380f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { 381f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki dispatchOnSlide(top); 382f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (NEEDS_INVALIDATING) { 383f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (dy < 0) { // Upward 384f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki changedView.invalidate(); 385f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { // Downward 386f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ViewParent parent = changedView.getParent(); 387f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (parent instanceof View) { 388f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki View v = (View) parent; 389f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki v.invalidate(changedView.getLeft(), top - dy, 390f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki changedView.getRight(), v.getHeight()); 391f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 392f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 393f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 394452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 395452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 396452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 397452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onViewDragStateChanged(int state) { 398452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (state == ViewDragHelper.STATE_DRAGGING) { 399452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(STATE_DRAGGING); 400452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 401452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 402452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 403452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 404452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void onViewReleased(View releasedChild, float xvel, float yvel) { 405452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki int top; 406452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State int targetState; 407f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (yvel < 0) { // Moving up 408452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMinOffset; 409452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki targetState = STATE_EXPANDED; 410f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else if (mHideable && shouldHide(releasedChild, yvel)) { 411f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki top = mParentHeight; 412f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki targetState = STATE_HIDDEN; 413452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 414452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki top = mMaxOffset; 415452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki targetState = STATE_COLLAPSED; 416452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 417452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) { 418f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(STATE_SETTLING); 419452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(releasedChild, 420452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki new SettleRunnable(releasedChild, targetState)); 421f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 422f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki setStateInternal(targetState); 423452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 424452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 425452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 426452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 427452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public int clampViewPositionVertical(View child, int top, int dy) { 428f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki return MathUtils.constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset); 429452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 430452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 431452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 432452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public int clampViewPositionHorizontal(View child, int left, int dx) { 433452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return child.getLeft(); 434452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 435f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 4369aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki @Override 4379aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki public int getViewVerticalDragRange(View child) { 4389aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki if (mHideable) { 4399aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return mParentHeight - mMinOffset; 4409aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } else { 4419aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki return mMaxOffset - mMinOffset; 4429aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 4439aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki } 444452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki }; 445452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 446f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki private void dispatchOnSlide(int top) { 447dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki View bottomSheet = mViewRef.get(); 448dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki if (bottomSheet != null && mCallback != null) { 449f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (top > mMaxOffset) { 450dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki mCallback.onSlide(bottomSheet, (float) (mMaxOffset - top) / mPeekHeight); 451f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } else { 452dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki mCallback.onSlide(bottomSheet, 453dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki (float) (mMaxOffset - top) / ((mMaxOffset - mMinOffset))); 454f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 455f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 456f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 457f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki 458452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private class SettleRunnable implements Runnable { 459452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 460452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final View mView; 461452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 462452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 463452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki private final int mTargetState; 464452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 465452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki SettleRunnable(View view, @State int targetState) { 466452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mView = view; 467452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki mTargetState = targetState; 468f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (NEEDS_INVALIDATING) { 469f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki // We need to invalidate the parent here, or the following animation won't be drawn. 470f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ViewParent parent = mView.getParent(); 471f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki if (parent instanceof View) { 472f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki ((View) parent).invalidate(); 473f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 474f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki } 475452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 476452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 477452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 478452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void run() { 479452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) { 480452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewCompat.postOnAnimation(mView, this); 481452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } else { 482452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki setStateInternal(mTargetState); 483452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 484452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 485452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 486452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 487452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki protected static class SavedState extends View.BaseSavedState { 488452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 489452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @State 490452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki final int state; 491452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 492452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState(Parcel source) { 493452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super(source); 494452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki //noinspection ResourceType 495452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki state = source.readInt(); 496452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 497452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 498452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState(Parcelable superState, @State int state) { 499452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super(superState); 500452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki this.state = state; 501452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 502452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 503452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 504452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public void writeToParcel(Parcel out, int flags) { 505452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki super.writeToParcel(out, flags); 506452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki out.writeInt(state); 507452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 508452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 509452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static final Parcelable.Creator<SavedState> CREATOR = 510452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki new Parcelable.Creator<SavedState>() { 511452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 512452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState createFromParcel(Parcel source) { 513452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return new SavedState(source); 514452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 515452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 516452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @Override 517452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public SavedState[] newArray(int size) { 518452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return new SavedState[size]; 519452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 520452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki }; 521452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 522452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 523f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki /** 524452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}. 525452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * 526452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @param view The {@link View} with {@link BottomSheetBehavior}. 527452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * @return The {@link BottomSheetBehavior} associated with the {@code view}. 528452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */ 529452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki @SuppressWarnings("unchecked") 530452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki public static <V extends View> BottomSheetBehavior<V> from(V view) { 531452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki ViewGroup.LayoutParams params = view.getLayoutParams(); 532452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (!(params instanceof CoordinatorLayout.LayoutParams)) { 533452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException("The view is not a child of CoordinatorLayout"); 534452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 535452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params) 536452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki .getBehavior(); 537452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki if (!(behavior instanceof BottomSheetBehavior)) { 538452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki throw new IllegalArgumentException( 539452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki "The view is not associated with BottomSheetBehavior"); 540452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 541452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki return (BottomSheetBehavior<V>) behavior; 542452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki } 543452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki 544452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki} 545