14
14
import android .support .v4 .widget .ViewDragHelper ;
15
15
import android .util .AttributeSet ;
16
16
import android .util .Log ;
17
+ import android .view .Gravity ;
17
18
import android .view .MotionEvent ;
18
19
import android .view .SoundEffectConstants ;
19
20
import android .view .View ;
@@ -47,6 +48,13 @@ public class SlidingUpPanelLayout extends ViewGroup {
47
48
*/
48
49
private static final int DEFAULT_MIN_FLING_VELOCITY = 400 ; // dips per second
49
50
51
+ /**
52
+ * Default attributes for layout
53
+ */
54
+ private static final int [] DEFAULT_ATTRS = new int [] {
55
+ android .R .attr .layout_gravity
56
+ };
57
+
50
58
/**
51
59
* Minimum velocity that will be detected as a fling
52
60
*/
@@ -77,6 +85,11 @@ public class SlidingUpPanelLayout extends ViewGroup {
77
85
*/
78
86
private int mShadowHeight = -1 ;
79
87
88
+ /**
89
+ * True if the collapsed panel should be dragged up.
90
+ */
91
+ private boolean mIsSlidingUp ;
92
+
80
93
/**
81
94
* True if a panel can slide with the current measurements
82
95
*/
@@ -218,6 +231,18 @@ public SlidingUpPanelLayout(Context context, AttributeSet attrs) {
218
231
public SlidingUpPanelLayout (Context context , AttributeSet attrs , int defStyle ) {
219
232
super (context , attrs , defStyle );
220
233
if (attrs != null ) {
234
+ TypedArray defAttrs = context .obtainStyledAttributes (attrs , DEFAULT_ATTRS );
235
+
236
+ if (defAttrs != null ) {
237
+ int gravity = defAttrs .getInt (0 , Gravity .NO_GRAVITY );
238
+ if (gravity != Gravity .TOP && gravity != Gravity .BOTTOM ) {
239
+ throw new IllegalArgumentException ("layout_gravity must be set to either top or bottom" );
240
+ }
241
+ mIsSlidingUp = gravity == Gravity .BOTTOM ;
242
+ }
243
+
244
+ defAttrs .recycle ();
245
+
221
246
TypedArray ta = context .obtainStyledAttributes (attrs , R .styleable .SlidingUpPanelLayout );
222
247
223
248
if (ta != null ) {
@@ -530,7 +555,12 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) {
530
555
mSlideRange = childHeight - mPanelHeight ;
531
556
}
532
557
533
- final int childTop = lp .slideable ? slidingTop + (int ) (mSlideRange * mSlideOffset ) : paddingTop ;
558
+ final int childTop ;
559
+ if (mIsSlidingUp ) {
560
+ childTop = lp .slideable ? slidingTop + (int ) (mSlideRange * mSlideOffset ) : paddingTop ;
561
+ } else {
562
+ childTop = lp .slideable ? slidingTop - (int ) (mSlideRange * mSlideOffset ) : paddingTop + mPanelHeight ;
563
+ }
534
564
final int childBottom = childTop + childHeight ;
535
565
final int childLeft = paddingLeft ;
536
566
final int childRight = childLeft + child .getMeasuredWidth ();
@@ -799,7 +829,9 @@ public void hidePane() {
799
829
800
830
private void onPanelDragged (int newTop ) {
801
831
final int topBound = getSlidingTop ();
802
- mSlideOffset = (float ) (newTop - topBound ) / mSlideRange ;
832
+ mSlideOffset = mIsSlidingUp
833
+ ? (float ) (newTop - topBound ) / mSlideRange
834
+ : (float ) (topBound - newTop ) / mSlideRange ;
803
835
dispatchOnPanelSlide (mSlideableView );
804
836
}
805
837
@@ -814,7 +846,11 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
814
846
if (mCanSlide && !lp .slideable && mSlideableView != null ) {
815
847
// Clip against the slider; no sense drawing what will immediately be covered.
816
848
canvas .getClipBounds (mTmpRect );
817
- mTmpRect .bottom = Math .min (mTmpRect .bottom , mSlideableView .getTop ());
849
+ if (mIsSlidingUp ) {
850
+ mTmpRect .bottom = Math .min (mTmpRect .bottom , mSlideableView .getTop ());
851
+ } else {
852
+ mTmpRect .top = Math .max (mTmpRect .top , mSlideableView .getBottom ());
853
+ }
818
854
canvas .clipRect (mTmpRect );
819
855
if (mSlideOffset < 1 ) {
820
856
drawScrim = true ;
@@ -848,7 +884,9 @@ boolean smoothSlideTo(float slideOffset, int velocity) {
848
884
}
849
885
850
886
final int topBound = getSlidingTop ();
851
- int y = (int ) (topBound + slideOffset * mSlideRange );
887
+ int y = mIsSlidingUp
888
+ ? (int ) (topBound + slideOffset * mSlideRange )
889
+ : (int ) (topBound - slideOffset * mSlideRange );
852
890
853
891
if (mDragHelper .smoothSlideViewTo (mSlideableView , mSlideableView .getLeft (), y )) {
854
892
setAllChildrenVisible ();
@@ -880,8 +918,15 @@ public void draw(Canvas c) {
880
918
}
881
919
882
920
final int right = mSlideableView .getRight ();
883
- final int top = mSlideableView .getTop () - mShadowHeight ;
884
- final int bottom = mSlideableView .getTop ();
921
+ final int top ;
922
+ final int bottom ;
923
+ if (mIsSlidingUp ) {
924
+ top = mSlideableView .getTop () - mShadowHeight ;
925
+ bottom = mSlideableView .getTop ();
926
+ } else {
927
+ top = mSlideableView .getBottom ();
928
+ bottom = mSlideableView .getBottom () + mShadowHeight ;
929
+ }
885
930
final int left = mSlideableView .getLeft ();
886
931
887
932
if (mShadowDrawable != null ) {
@@ -1010,11 +1055,20 @@ public void onViewPositionChanged(View changedView, int left, int top, int dx, i
1010
1055
1011
1056
@ Override
1012
1057
public void onViewReleased (View releasedChild , float xvel , float yvel ) {
1013
- int top = getSlidingTop ();
1058
+ int top = mIsSlidingUp
1059
+ ? getSlidingTop ()
1060
+ : getSlidingTop () - mSlideRange ;
1014
1061
1015
1062
if (mAnchorPoint != 0 ) {
1016
- int anchoredTop = (int )(mAnchorPoint *mSlideRange );
1017
- float anchorOffset = (float )anchoredTop /(float )mSlideRange ;
1063
+ int anchoredTop ;
1064
+ float anchorOffset ;
1065
+ if (mIsSlidingUp ) {
1066
+ anchoredTop = (int )(mAnchorPoint *mSlideRange );
1067
+ anchorOffset = (float )anchoredTop /(float )mSlideRange ;
1068
+ } else {
1069
+ anchoredTop = mPanelHeight - (int )(mAnchorPoint *mSlideRange );
1070
+ anchorOffset = (float )(mPanelHeight - anchoredTop )/(float )mSlideRange ;
1071
+ }
1018
1072
1019
1073
if (yvel > 0 || (yvel == 0 && mSlideOffset >= (1f +anchorOffset )/2 )) {
1020
1074
top += mSlideRange ;
@@ -1038,8 +1092,15 @@ public int getViewVerticalDragRange(View child) {
1038
1092
1039
1093
@ Override
1040
1094
public int clampViewPositionVertical (View child , int top , int dy ) {
1041
- final int topBound = getSlidingTop ();
1042
- final int bottomBound = topBound + mSlideRange ;
1095
+ final int topBound ;
1096
+ final int bottomBound ;
1097
+ if (mIsSlidingUp ) {
1098
+ topBound = getSlidingTop ();
1099
+ bottomBound = topBound + mSlideRange ;
1100
+ } else {
1101
+ bottomBound = getPaddingTop ();
1102
+ topBound = bottomBound - mSlideRange ;
1103
+ }
1043
1104
1044
1105
return Math .min (Math .max (top , topBound ), bottomBound );
1045
1106
}
0 commit comments