diff --git a/library/src/main/java/com/sothree/slidinguppanel/SlidingUpPanelLayout.java b/library/src/main/java/com/sothree/slidinguppanel/SlidingUpPanelLayout.java
index 57f89a12..b8b67289 100644
--- a/library/src/main/java/com/sothree/slidinguppanel/SlidingUpPanelLayout.java
+++ b/library/src/main/java/com/sothree/slidinguppanel/SlidingUpPanelLayout.java
@@ -8,15 +8,12 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.Bundle;
-import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.NonNull;
-import android.support.v4.app.BundleCompat;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -37,22 +34,28 @@ public class SlidingUpPanelLayout extends ViewGroup {
/**
* Default peeking out panel height
*/
- private static final int DEFAULT_PANEL_HEIGHT = 68; // dp;
+ private static final int DEFAULT_PANEL_SIZE = 68; // dp;
/**
* Default anchor point height
*/
private static final float DEFAULT_ANCHOR_POINT = 1.0f; // In relative %
+ /**
+ * Default gravity
+ */
+ private static final int DEFAULT_GRAVITY = Gravity.BOTTOM;
+
/**
* Default initial state for the component
*/
private static PanelState DEFAULT_SLIDE_STATE = PanelState.COLLAPSED;
+
/**
* Default height of the shadow above the peeking out panel
*/
- private static final int DEFAULT_SHADOW_HEIGHT = 4; // dp;
+ private static final int DEFAULT_SHADOW_SIZE = 4; // dp;
/**
* If no fade color is given by default it will fade to 80% gray.
@@ -110,7 +113,7 @@ public class SlidingUpPanelLayout extends ViewGroup {
/**
* The size of the overhang in pixels.
*/
- private int mPanelHeight = -1;
+ private int mPaneSize = -1;
/**
* The size of the shadow in pixels.
@@ -122,10 +125,7 @@ public class SlidingUpPanelLayout extends ViewGroup {
*/
private int mParallaxOffset = -1;
- /**
- * True if the collapsed panel should be dragged up.
- */
- private boolean mIsSlidingUp;
+ private boolean mIsSlidingVertically = true;
/**
* Panel overlays the windows instead of putting it underneath it.
@@ -179,6 +179,11 @@ public enum PanelState {
private PanelState mSlideState = DEFAULT_SLIDE_STATE;
+ /**
+ *
+ */
+ private int mGravity = DEFAULT_GRAVITY;
+
/**
* If the current slide state is DRAGGING, this will store the last non dragging state
*/
@@ -211,7 +216,7 @@ public enum PanelState {
*/
private boolean mIsTouchEnabled;
- private float mPrevMotionY;
+ private float mPrevMotionLocation;
private float mInitialMotionX;
private float mInitialMotionY;
private boolean mIsScrollableViewHandlingTouch = false;
@@ -295,7 +300,7 @@ public SlidingUpPanelLayout(Context context, AttributeSet attrs, int defStyle) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingUpPanelLayout);
if (ta != null) {
- mPanelHeight = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoPanelHeight, -1);
+ mPaneSize = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoPanelHeight, -1);
mShadowHeight = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoShadowHeight, -1);
mParallaxOffset = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoParallaxOffset, -1);
@@ -322,21 +327,32 @@ public SlidingUpPanelLayout(Context context, AttributeSet attrs, int defStyle) {
}
final float density = context.getResources().getDisplayMetrics().density;
- if (mPanelHeight == -1) {
- mPanelHeight = (int) (DEFAULT_PANEL_HEIGHT * density + 0.5f);
+ if (mPaneSize == -1) {
+ mPaneSize = (int) (DEFAULT_PANEL_SIZE * density + 0.5f);
}
if (mShadowHeight == -1) {
- mShadowHeight = (int) (DEFAULT_SHADOW_HEIGHT * density + 0.5f);
+ mShadowHeight = (int) (DEFAULT_SHADOW_SIZE * density + 0.5f);
}
if (mParallaxOffset == -1) {
mParallaxOffset = (int) (DEFAULT_PARALLAX_OFFSET * density);
}
// If the shadow height is zero, don't show the shadow
if (mShadowHeight > 0) {
- if (mIsSlidingUp) {
- mShadowDrawable = getResources().getDrawable(R.drawable.above_shadow);
- } else {
- mShadowDrawable = getResources().getDrawable(R.drawable.below_shadow);
+ switch (mGravity) {
+ case Gravity.BOTTOM:
+ mShadowDrawable = getResources().getDrawable(R.drawable.above_shadow);
+ break;
+ case Gravity.TOP:
+ mShadowDrawable = getResources().getDrawable(R.drawable.below_shadow);
+ break;
+ case Gravity.RIGHT:
+ mShadowDrawable = getResources().getDrawable(R.drawable.left_shadow);
+ break;
+ case Gravity.LEFT:
+ mShadowDrawable = getResources().getDrawable(R.drawable.right_shadow);
+ break;
+ default:
+ mShadowDrawable = null;
}
} else {
mShadowDrawable = null;
@@ -365,10 +381,20 @@ protected void onFinishInflate() {
}
public void setGravity(int gravity) {
- if (gravity != Gravity.TOP && gravity != Gravity.BOTTOM) {
- throw new IllegalArgumentException("gravity must be set to either top or bottom");
+ if (gravity != Gravity.TOP && gravity != Gravity.BOTTOM
+ && gravity != Gravity.LEFT && gravity != Gravity.RIGHT) {
+ throw new IllegalArgumentException("gravity must be set to either top, bottom, left or right");
+ }
+
+ mGravity = gravity;
+ switch (gravity) {
+ case Gravity.BOTTOM: case Gravity.TOP:
+ mIsSlidingVertically = true;
+ break;
+ case Gravity.LEFT: case Gravity.RIGHT:
+ mIsSlidingVertically = false;
+ break;
}
- mIsSlidingUp = gravity == Gravity.BOTTOM;
if (!mFirstLayout) {
requestLayout();
}
@@ -415,7 +441,7 @@ public void setPanelHeight(int val) {
return;
}
- mPanelHeight = val;
+ mPaneSize = val;
if (!mFirstLayout) {
requestLayout();
}
@@ -454,7 +480,7 @@ public void setShadowHeight(int val) {
* @return The current collapsed panel height
*/
public int getPanelHeight() {
- return mPanelHeight;
+ return mPaneSize;
}
/**
@@ -463,7 +489,8 @@ public int getPanelHeight() {
public int getCurrentParallaxOffset() {
// Clamp slide offset at zero for parallax computation;
int offset = (int) (mParallaxOffset * Math.max(mSlideOffset, 0));
- return mIsSlidingUp ? -offset : offset;
+
+ return mGravity == Gravity.BOTTOM || mGravity == Gravity.RIGHT ? -offset : offset;
}
/**
@@ -769,42 +796,82 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = layoutWidth;
if (child == mMainView) {
if (!mOverlayContent && mSlideState != PanelState.HIDDEN) {
- height -= mPanelHeight;
+ if(mIsSlidingVertically){
+ height -= mPaneSize;
+ } else {
+ width -= mPaneSize;
+ }
}
- width -= lp.leftMargin + lp.rightMargin;
+ if (mIsSlidingVertically){
+ width -= lp.leftMargin + lp.rightMargin;
+ } else {
+ height -= lp.topMargin + lp.bottomMargin;
+ }
} else if (child == mSlideableView) {
// The slideable view should be aware of its top margin.
// See https://github.com/umano/AndroidSlidingUpPanel/issues/412.
- height -= lp.topMargin;
+ if(mIsSlidingVertically){
+ height -= lp.topMargin;
+ } else {
+ width -= lp.leftMargin;
+ }
}
int childWidthSpec;
- if (lp.width == LayoutParams.WRAP_CONTENT) {
- childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST);
- } else if (lp.width == LayoutParams.MATCH_PARENT) {
- childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
- } else {
- childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
- }
-
int childHeightSpec;
- if (lp.height == LayoutParams.WRAP_CONTENT) {
- childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
- } else {
- // Modify the height based on the weight.
- if (lp.weight > 0 && lp.weight < 1) {
- height = (int) (height * lp.weight);
- } else if (lp.height != LayoutParams.MATCH_PARENT) {
- height = lp.height;
+
+ if(mIsSlidingVertically){
+ if (lp.width == LayoutParams.WRAP_CONTENT) {
+ childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST);
+ } else if (lp.width == LayoutParams.MATCH_PARENT) {
+ childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ } else {
+ childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
+ }
+
+ if (lp.height == LayoutParams.WRAP_CONTENT) {
+ childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+ } else {
+ // Modify the height based on the weight.
+ if (lp.weight > 0 && lp.weight < 1) {
+ height = (int) (height * lp.weight);
+ } else if (lp.height != LayoutParams.MATCH_PARENT) {
+ height = lp.height;
+ }
+ childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ }
+ } else { // Horizontally
+ if (lp.height == LayoutParams.WRAP_CONTENT) {
+ childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+ } else if (lp.height == LayoutParams.MATCH_PARENT) {
+ childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ } else {
+ childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
+ }
+
+ if (lp.width == LayoutParams.WRAP_CONTENT) {
+ childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST);
+ } else {
+ // Modify the width based on the weight.
+ if (lp.weight > 0 && lp.weight < 1) {
+ width = (int) (width * lp.weight);
+ } else if (lp.width != LayoutParams.MATCH_PARENT) {
+ width = lp.width;
+ }
+ childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
}
- childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
+
child.measure(childWidthSpec, childHeightSpec);
if (child == mSlideableView) {
- mSlideRange = mSlideableView.getMeasuredHeight() - mPanelHeight;
+ if(mIsSlidingVertically){
+ mSlideRange = mSlideableView.getMeasuredHeight() - mPaneSize;
+ } else {
+ mSlideRange = mSlideableView.getMeasuredWidth() - mPaneSize;
+ }
}
}
@@ -827,8 +894,14 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) {
mSlideOffset = mAnchorPoint;
break;
case HIDDEN:
- int newTop = computePanelTopPosition(0.0f) + (mIsSlidingUp ? +mPanelHeight : -mPanelHeight);
- mSlideOffset = computeSlideOffset(newTop);
+ if(mIsSlidingVertically){
+ int newTop = computePanelTopPosition(0.0f) + (mGravity == Gravity.BOTTOM ? +mPaneSize : -mPaneSize);
+ mSlideOffset = computeSlideOffset(newTop);
+ } else {
+ int newLeft = computePanelLeftPosition(0.0f) + (mGravity == Gravity.RIGHT ? +mPaneSize : -mPaneSize);
+ mSlideOffset = computeSlideOffset(newLeft);
+ }
+
break;
default:
mSlideOffset = 0.f;
@@ -845,23 +918,46 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) {
continue;
}
- final int childHeight = child.getMeasuredHeight();
- int childTop = paddingTop;
+ if (mIsSlidingVertically) {
- if (child == mSlideableView) {
- childTop = computePanelTopPosition(mSlideOffset);
- }
+ int childTop = paddingTop;
+ if (child == mSlideableView) {
+ childTop = computePanelTopPosition(mSlideOffset);
+ }
- if (!mIsSlidingUp) {
- if (child == mMainView && !mOverlayContent) {
- childTop = computePanelTopPosition(mSlideOffset) + mSlideableView.getMeasuredHeight();
+ if (mGravity == Gravity.TOP) {
+ if (child == mMainView && !mOverlayContent) {
+ childTop = computePanelTopPosition(mSlideOffset) + mSlideableView.getMeasuredHeight();
+ }
}
+
+ final int childHeight = child.getMeasuredHeight();
+ final int childBottom = childTop + childHeight;
+ final int childLeft = paddingLeft + lp.leftMargin;
+ final int childRight = childLeft + child.getMeasuredWidth();
+
+ child.layout(childLeft, childTop, childRight, childBottom);
+ } else {
+ int childLeft = paddingLeft;
+
+ if (child == mSlideableView) {
+ childLeft = computePanelLeftPosition(mSlideOffset);
+ }
+
+ if (mGravity == Gravity.LEFT) {
+ if (child == mMainView && !mOverlayContent) {
+ childLeft = computePanelLeftPosition(mSlideOffset) + mSlideableView.getMeasuredWidth();
+ }
+ }
+
+ final int childWidth = child.getMeasuredWidth();
+ final int childRight = childLeft + childWidth;
+ final int childTop = paddingTop + lp.topMargin;
+ final int childBottom = childTop + child.getMeasuredHeight();
+
+ child.layout(childLeft, childTop, childRight, childBottom);
}
- final int childBottom = childTop + childHeight;
- final int childLeft = paddingLeft + lp.leftMargin;
- final int childRight = childLeft + child.getMeasuredWidth();
- child.layout(childLeft, childTop, childRight, childBottom);
}
if (mFirstLayout) {
@@ -964,14 +1060,19 @@ public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
- final float y = ev.getY();
+ final float location;
+ if (mIsSlidingVertically) {
+ location = ev.getY();
+ } else {
+ location = ev.getX();
+ }
if (action == MotionEvent.ACTION_DOWN) {
mIsScrollableViewHandlingTouch = false;
- mPrevMotionY = y;
+ mPrevMotionLocation = location;
} else if (action == MotionEvent.ACTION_MOVE) {
- float dy = y - mPrevMotionY;
- mPrevMotionY = y;
+ float deltaLocation = location - mPrevMotionLocation;
+ mPrevMotionLocation = location;
// If the scroll view isn't under the touch, pass the
// event along to the dragView.
@@ -980,10 +1081,17 @@ public boolean dispatchTouchEvent(MotionEvent ev) {
}
// Which direction (up or down) is the drag moving?
- if (dy * (mIsSlidingUp ? 1 : -1) > 0) { // Collapsing
+ int factor = 0;
+ if(mGravity == Gravity.BOTTOM || mGravity == Gravity.RIGHT){
+ factor = 1;
+ } else {
+ factor = -1;
+ }
+ if (deltaLocation * factor > 0) { // Collapsing
// Is the child less than fully scrolled?
// Then let the child handle it.
- if (mScrollableViewHelper.getScrollableViewScrollPosition(mScrollableView, mIsSlidingUp) > 0) {
+ // TODO: Does the ScrollableViewHandler need to know about horizontal sliding?
+ if (mScrollableViewHelper.getScrollableViewScrollPosition(mScrollableView, mGravity == Gravity.BOTTOM) > 0) {
mIsScrollableViewHandlingTouch = true;
return super.dispatchTouchEvent(ev);
}
@@ -1005,7 +1113,7 @@ public boolean dispatchTouchEvent(MotionEvent ev) {
mIsScrollableViewHandlingTouch = false;
return this.onTouchEvent(ev);
- } else if (dy * (mIsSlidingUp ? 1 : -1) < 0) { // Expanding
+ } else if (deltaLocation * factor < 0) { // Expanding
// Is the panel less than fully expanded?
// Then we'll handle the drag here.
if (mSlideOffset < 1.0f) {
@@ -1055,23 +1163,40 @@ private int computePanelTopPosition(float slideOffset) {
int slidingViewHeight = mSlideableView != null ? mSlideableView.getMeasuredHeight() : 0;
int slidePixelOffset = (int) (slideOffset * mSlideRange);
// Compute the top of the panel if its collapsed
- return mIsSlidingUp
- ? getMeasuredHeight() - getPaddingBottom() - mPanelHeight - slidePixelOffset
- : getPaddingTop() - slidingViewHeight + mPanelHeight + slidePixelOffset;
+ return mGravity == Gravity.BOTTOM
+ ? getMeasuredHeight() - getPaddingBottom() - mPaneSize - slidePixelOffset
+ : getPaddingTop() - slidingViewHeight + mPaneSize + slidePixelOffset;
+ }
+
+ /*
+ * Computes the left position of the panel based on the slide offset.
+ */
+ private int computePanelLeftPosition(float slideOffset) {
+ int slidingViewWidth = mSlideableView != null ? mSlideableView.getMeasuredWidth() : 0;
+ int slidePixelOffset = (int) (slideOffset * mSlideRange);
+ // Compute the top of the panel if its collapsed
+ return mGravity == Gravity.RIGHT
+ ? getMeasuredWidth() - getPaddingRight() - mPaneSize - slidePixelOffset
+ : getPaddingLeft() - slidingViewWidth + mPaneSize + slidePixelOffset;
}
/*
* Computes the slide offset based on the top position of the panel
*/
- private float computeSlideOffset(int topPosition) {
+ private float computeSlideOffset(int topOrLeftPosition) {
// Compute the panel top position if the panel is collapsed (offset 0)
- final int topBoundCollapsed = computePanelTopPosition(0);
+ final int topOrLeftBoundCollapsed;
+ if(mIsSlidingVertically){
+ topOrLeftBoundCollapsed = computePanelTopPosition(0);
+ } else {
+ topOrLeftBoundCollapsed = computePanelLeftPosition(0);
+ }
// Determine the new slide offset based on the collapsed top position and the new required
// top position
- return (mIsSlidingUp
- ? (float) (topBoundCollapsed - topPosition) / mSlideRange
- : (float) (topPosition - topBoundCollapsed) / mSlideRange);
+ return (mGravity == Gravity.BOTTOM || mGravity == Gravity.RIGHT
+ ? (float) (topOrLeftBoundCollapsed - topOrLeftPosition) / mSlideRange
+ : (float) (topOrLeftPosition - topOrLeftBoundCollapsed) / mSlideRange);
}
/**
@@ -1089,6 +1214,13 @@ public PanelState getPanelState() {
* @param state - new panel state
*/
public void setPanelState(PanelState state) {
+
+ // Abort any running animation, to allow state change
+ if(mDragHelper.getViewDragState() == ViewDragHelper.STATE_SETTLING){
+ Log.d(TAG, "View is settling. Aborting animation.");
+ mDragHelper.abort();
+ }
+
if (state == null || state == PanelState.DRAGGING) {
throw new IllegalArgumentException("Panel state cannot be null or DRAGGING.");
}
@@ -1115,8 +1247,14 @@ public void setPanelState(PanelState state) {
smoothSlideTo(1.0f, 0);
break;
case HIDDEN:
- int newTop = computePanelTopPosition(0.0f) + (mIsSlidingUp ? +mPanelHeight : -mPanelHeight);
- smoothSlideTo(computeSlideOffset(newTop), 0);
+ if (mIsSlidingVertically) {
+ int newTop = computePanelTopPosition(0.0f) + (mGravity == Gravity.BOTTOM ? +mPaneSize : -mPaneSize);
+ smoothSlideTo(computeSlideOffset(newTop), 0);
+ } else {
+ int newTop = computePanelLeftPosition(0.0f) + (mGravity == Gravity.RIGHT ? +mPaneSize : -mPaneSize);
+ smoothSlideTo(computeSlideOffset(newTop), 0);
+ }
+
break;
}
}
@@ -1136,35 +1274,51 @@ private void setPanelStateInternal(PanelState state) {
private void applyParallaxForCurrentSlideOffset() {
if (mParallaxOffset > 0) {
int mainViewOffset = getCurrentParallaxOffset();
- ViewCompat.setTranslationY(mMainView, mainViewOffset);
+ if (mIsSlidingVertically){
+ ViewCompat.setTranslationY(mMainView, mainViewOffset);
+ } else {
+ ViewCompat.setTranslationX(mMainView, mainViewOffset);
+ }
}
}
- private void onPanelDragged(int newTop) {
+ private void onPanelDragged(int newTopOrLeft) {
if (mSlideState != PanelState.DRAGGING) {
mLastNotDraggingSlideState = mSlideState;
}
setPanelStateInternal(PanelState.DRAGGING);
// Recompute the slide offset based on the new top position
- mSlideOffset = computeSlideOffset(newTop);
+ mSlideOffset = computeSlideOffset(newTopOrLeft);
applyParallaxForCurrentSlideOffset();
// Dispatch the slide event
dispatchOnPanelSlide(mSlideableView);
// If the slide offset is negative, and overlay is not on, we need to increase the
// height of the main content
LayoutParams lp = (LayoutParams) mMainView.getLayoutParams();
- int defaultHeight = getHeight() - getPaddingBottom() - getPaddingTop() - mPanelHeight;
+ int defaultHeight = getHeight() - getPaddingBottom() - getPaddingTop() - mPaneSize;
+ int defaultWidth = getWidth() - getPaddingRight() - getPaddingLeft() - mPaneSize;
if (mSlideOffset <= 0 && !mOverlayContent) {
// expand the main view
- lp.height = mIsSlidingUp ? (newTop - getPaddingBottom()) : (getHeight() - getPaddingBottom() - mSlideableView.getMeasuredHeight() - newTop);
- if (lp.height == defaultHeight) {
- lp.height = LayoutParams.MATCH_PARENT;
+ if(mIsSlidingVertically){
+ lp.height = mGravity == Gravity.BOTTOM ? (newTopOrLeft - getPaddingBottom()) : (getHeight() - getPaddingBottom() - mSlideableView.getMeasuredHeight() - newTopOrLeft);
+ if (lp.height == defaultHeight) {
+ lp.height = LayoutParams.MATCH_PARENT;
+ }
+ } else {
+ lp.width = mGravity == Gravity.RIGHT ? (newTopOrLeft - getPaddingRight()) : (getWidth() - getPaddingRight() - mSlideableView.getMeasuredWidth() - newTopOrLeft);
+ if (lp.width == defaultWidth) {
+ lp.width = LayoutParams.MATCH_PARENT;
+ }
}
+
mMainView.requestLayout();
- } else if (lp.height != LayoutParams.MATCH_PARENT && !mOverlayContent) {
+ } else if (mIsSlidingVertically && (lp.height != LayoutParams.MATCH_PARENT && !mOverlayContent)) {
lp.height = LayoutParams.MATCH_PARENT;
mMainView.requestLayout();
+ } else if (!mIsSlidingVertically && (lp.width != LayoutParams.MATCH_PARENT && !mOverlayContent)) {
+ lp.width = LayoutParams.MATCH_PARENT;
+ mMainView.requestLayout();
}
}
@@ -1178,10 +1332,18 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
// Unless the panel is set to overlay content
canvas.getClipBounds(mTmpRect);
if (!mOverlayContent) {
- if (mIsSlidingUp) {
- mTmpRect.bottom = Math.min(mTmpRect.bottom, mSlideableView.getTop());
- } else {
- mTmpRect.top = Math.max(mTmpRect.top, mSlideableView.getBottom());
+ switch (mGravity){
+ case Gravity.BOTTOM:
+ mTmpRect.bottom = Math.min(mTmpRect.bottom, mSlideableView.getTop());
+ break;
+ case Gravity.TOP:
+ mTmpRect.top = Math.max(mTmpRect.top, mSlideableView.getBottom());
+ break;
+ case Gravity.RIGHT:
+ mTmpRect.right = Math.min(mTmpRect.right, mSlideableView.getLeft());
+ break;
+ case Gravity.LEFT:
+ mTmpRect.left = Math.max(mTmpRect.left, mSlideableView.getRight());
}
}
if (mClipPanel) {
@@ -1218,8 +1380,16 @@ boolean smoothSlideTo(float slideOffset, int velocity) {
return false;
}
- int panelTop = computePanelTopPosition(slideOffset);
- if (mDragHelper.smoothSlideViewTo(mSlideableView, mSlideableView.getLeft(), panelTop)) {
+ boolean success;
+ if(mIsSlidingVertically){
+ int panelTop = computePanelTopPosition(slideOffset);
+ success = mDragHelper.smoothSlideViewTo(mSlideableView, mSlideableView.getLeft(), panelTop);
+ } else {
+ int panelLeft = computePanelLeftPosition(slideOffset);
+ success = mDragHelper.smoothSlideViewTo(mSlideableView, panelLeft, mSlideableView.getTop());
+ }
+
+ if (success) {
setAllChildrenVisible();
ViewCompat.postInvalidateOnAnimation(this);
return true;
@@ -1245,17 +1415,31 @@ public void draw(Canvas c) {
// draw the shadow
if (mShadowDrawable != null && mSlideableView != null) {
- final int right = mSlideableView.getRight();
- final int top;
- final int bottom;
- if (mIsSlidingUp) {
- top = mSlideableView.getTop() - mShadowHeight;
- bottom = mSlideableView.getTop();
+ final int top, bottom, left, right;
+ if(mIsSlidingVertically){
+ if (mGravity == Gravity.BOTTOM) {
+ top = mSlideableView.getTop() - mShadowHeight;
+ bottom = mSlideableView.getTop();
+ } else {
+ top = mSlideableView.getBottom();
+ bottom = mSlideableView.getBottom() + mShadowHeight;
+ }
+
+ right = mSlideableView.getRight();
+ left = mSlideableView.getLeft();
} else {
- top = mSlideableView.getBottom();
- bottom = mSlideableView.getBottom() + mShadowHeight;
+ if (mGravity == Gravity.RIGHT) {
+ left = mSlideableView.getLeft() - mShadowHeight;
+ right = mSlideableView.getLeft();
+ } else {
+ left = mSlideableView.getRight();
+ right = mSlideableView.getRight() + mShadowHeight;
+ }
+
+ top = mSlideableView.getTop();
+ bottom = mSlideableView.getBottom();
}
- final int left = mSlideableView.getLeft();
+
mShadowDrawable.setBounds(left, top, right, bottom);
mShadowDrawable.draw(c);
}
@@ -1348,7 +1532,11 @@ public boolean tryCaptureView(View child, int pointerId) {
@Override
public void onViewDragStateChanged(int state) {
if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) {
- mSlideOffset = computeSlideOffset(mSlideableView.getTop());
+ if(mIsSlidingVertically){
+ mSlideOffset = computeSlideOffset(mSlideableView.getTop());
+ } else {
+ mSlideOffset = computeSlideOffset(mSlideableView.getLeft());
+ }
applyParallaxForCurrentSlideOffset();
if (mSlideOffset == 1) {
@@ -1373,7 +1561,11 @@ public void onViewCaptured(View capturedChild, int activePointerId) {
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
- onPanelDragged(top);
+ if(mIsSlidingVertically){
+ onPanelDragged(top);
+ } else {
+ onPanelDragged(left);
+ }
invalidate();
}
@@ -1382,48 +1574,100 @@ public void onViewReleased(View releasedChild, float xvel, float yvel) {
int target = 0;
// direction is always positive if we are sliding in the expanded direction
- float direction = mIsSlidingUp ? -yvel : yvel;
+ float direction;
+ if (mIsSlidingVertically){
+ direction = mGravity == Gravity.BOTTOM ? -yvel : yvel;
+ } else {
+ direction = mGravity == Gravity.RIGHT ? -xvel : xvel;
+ }
if (direction > 0 && mSlideOffset <= mAnchorPoint) {
// swipe up -> expand and stop at anchor point
- target = computePanelTopPosition(mAnchorPoint);
+ if (mIsSlidingVertically) target = computePanelTopPosition(mAnchorPoint);
+ else target = computePanelLeftPosition(mAnchorPoint);
} else if (direction > 0 && mSlideOffset > mAnchorPoint) {
// swipe up past anchor -> expand
- target = computePanelTopPosition(1.0f);
+ if (mIsSlidingVertically) target = computePanelTopPosition(1.0f);
+ else target = computePanelLeftPosition(1.0f);
} else if (direction < 0 && mSlideOffset >= mAnchorPoint) {
// swipe down -> collapse and stop at anchor point
- target = computePanelTopPosition(mAnchorPoint);
+ if (mIsSlidingVertically) target = computePanelTopPosition(mAnchorPoint);
+ else target = computePanelLeftPosition(mAnchorPoint);
} else if (direction < 0 && mSlideOffset < mAnchorPoint) {
// swipe down past anchor -> collapse
- target = computePanelTopPosition(0.0f);
+ if(mIsSlidingVertically) target = computePanelTopPosition(0.0f);
+ else target = computePanelLeftPosition(0.0f);
} else if (mSlideOffset >= (1.f + mAnchorPoint) / 2) {
// zero velocity, and far enough from anchor point => expand to the top
- target = computePanelTopPosition(1.0f);
+ if(mIsSlidingVertically) target = computePanelTopPosition(1.0f);
+ else target = computePanelLeftPosition(1.0f);
} else if (mSlideOffset >= mAnchorPoint / 2) {
// zero velocity, and close enough to anchor point => go to anchor
- target = computePanelTopPosition(mAnchorPoint);
+ if(mIsSlidingVertically) target = computePanelTopPosition(mAnchorPoint);
+ else target = computePanelLeftPosition(mAnchorPoint);
} else {
// settle at the bottom
- target = computePanelTopPosition(0.0f);
+ if (mIsSlidingVertically) target = computePanelTopPosition(0.0f);
+ else target = computePanelLeftPosition(0.0f);
}
- mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), target);
+ if(mIsSlidingVertically){
+ mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), target);
+ } else {
+ mDragHelper.settleCapturedViewAt(target, releasedChild.getTop());
+ }
invalidate();
}
@Override
public int getViewVerticalDragRange(View child) {
- return mSlideRange;
+ if(mIsSlidingVertically){ // Vertical
+ return mSlideRange;
+ } else { // Horizontal
+ return super.getViewVerticalDragRange(child);
+ }
+ }
+
+ @Override
+ public int getViewHorizontalDragRange(View child) {
+ if(!mIsSlidingVertically){ // Horizontal
+ return mSlideRange;
+ } else { // Vertical
+ return super.getViewHorizontalDragRange(child);
+ }
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
- final int collapsedTop = computePanelTopPosition(0.f);
- final int expandedTop = computePanelTopPosition(1.0f);
- if (mIsSlidingUp) {
- return Math.min(Math.max(top, expandedTop), collapsedTop);
- } else {
- return Math.min(Math.max(top, collapsedTop), expandedTop);
+ // The ViewDragHelper does not know, which scrolling direction is allowed and which not.
+ // Therefore only clamp view position, if vertical scrolling is enabled, here.
+ if(mIsSlidingVertically){
+ final int collapsedTop = computePanelTopPosition(0.f);
+ final int expandedTop = computePanelTopPosition(1.0f);
+ if (mGravity == Gravity.BOTTOM) {
+ return Math.min(Math.max(top, expandedTop), collapsedTop);
+ } else {
+ return Math.min(Math.max(top, collapsedTop), expandedTop);
+ }
+ } else { // Horizontally
+ return super.clampViewPositionVertical(child, top, dy);
+ }
+ }
+
+ @Override
+ public int clampViewPositionHorizontal(View child, int left, int dx) {
+ // The ViewDragHelper does not know, which scrolling direction is allowed and which not.
+ // Therefore only clamp view position, if horizontal scrolling is enabled, here.
+ if(!mIsSlidingVertically) {// Horizontally
+ final int collapsedLeft = computePanelLeftPosition(0.f);
+ final int expandedLeft = computePanelLeftPosition(1.0f);
+ if (mGravity == Gravity.RIGHT) {
+ return Math.min(Math.max(left, expandedLeft), collapsedLeft);
+ } else {
+ return Math.min(Math.max(left, collapsedLeft), expandedLeft);
+ }
+ } else { // Vertically
+ return super.clampViewPositionHorizontal(child, left, dx);
}
}
}
diff --git a/library/src/main/java/com/sothree/slidinguppanel/ViewDragHelper.java b/library/src/main/java/com/sothree/slidinguppanel/ViewDragHelper.java
index 58a4e82a..e8cae58b 100644
--- a/library/src/main/java/com/sothree/slidinguppanel/ViewDragHelper.java
+++ b/library/src/main/java/com/sothree/slidinguppanel/ViewDragHelper.java
@@ -760,6 +760,12 @@ public boolean continueSettling(boolean deferCallbacks) {
return true;
}
+ if(!keepGoing && dx != 0) { //fix #525 (Copy for horizontal sliding
+ //Invalid drag state
+ mCapturedView.setLeft(0);
+ return true;
+ }
+
if (dx != 0) {
mCapturedView.offsetLeftAndRight(dx);
}
diff --git a/library/src/main/res/drawable/left_shadow.xml b/library/src/main/res/drawable/left_shadow.xml
new file mode 100644
index 00000000..a473b631
--- /dev/null
+++ b/library/src/main/res/drawable/left_shadow.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/res/drawable/right_shadow.xml b/library/src/main/res/drawable/right_shadow.xml
new file mode 100644
index 00000000..e08e48cf
--- /dev/null
+++ b/library/src/main/res/drawable/right_shadow.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file