diff --git a/demo/build.gradle b/demo/build.gradle index 2b122cd..586f375 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -7,7 +7,6 @@ repositories { android { compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION - defaultConfig { minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION) targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) diff --git a/demo/src/main/java/com/daimajia/swipedemo/MyActivity.java b/demo/src/main/java/com/daimajia/swipedemo/MyActivity.java index f2aaff7..f3b06c9 100644 --- a/demo/src/main/java/com/daimajia/swipedemo/MyActivity.java +++ b/demo/src/main/java/com/daimajia/swipedemo/MyActivity.java @@ -27,8 +27,10 @@ public class MyActivity extends Activity { //sample1 sample1 = (SwipeLayout) findViewById(R.id.sample1); - sample1.setShowMode(SwipeLayout.ShowMode.LayDown); - sample1.setDragEdge(SwipeLayout.DragEdge.Left); + sample1.setShowMode(SwipeLayout.ShowMode.PullOut); + sample1.setDragEdges(SwipeLayout.DragEdge.Left, SwipeLayout.DragEdge.Right, SwipeLayout.DragEdge.Top); + // When using multiple drag edges it's a good idea to pass the ids of the views that you're using for the left, right, top bottom views (-1 if you're not using a particular view) + sample1.setBottomViewIds(R.id.bottom_wrapper, R.id.bottom_wrapper_2, R.id.starbott, SwipeLayout.EMPTY_LAYOUT); sample1.addRevealListener(R.id.delete, new SwipeLayout.OnRevealListener() { @Override public void onReveal(View child, SwipeLayout.DragEdge edge, float fraction, int distance) { @@ -36,10 +38,32 @@ public class MyActivity extends Activity { } }); + sample1.findViewById(R.id.star2).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(MyActivity.this, "Star", Toast.LENGTH_SHORT).show(); + } + }); + + sample1.findViewById(R.id.trash2).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(MyActivity.this, "Trash Bin", Toast.LENGTH_SHORT).show(); + } + }); + + sample1.findViewById(R.id.magnifier2).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(MyActivity.this, "Magnifier", Toast.LENGTH_SHORT).show(); + } + }); + //sample2 sample2 = (SwipeLayout) findViewById(R.id.sample2); sample2.setShowMode(SwipeLayout.ShowMode.LayDown); + sample2.setDragEdge(SwipeLayout.DragEdge.Right); // sample2.setShowMode(SwipeLayout.ShowMode.PullOut); sample2.findViewById(R.id.star).setOnClickListener(new View.OnClickListener() { @Override diff --git a/demo/src/main/res/layout/listview_item.xml b/demo/src/main/res/layout/listview_item.xml index 092f786..8962027 100644 --- a/demo/src/main/res/layout/listview_item.xml +++ b/demo/src/main/res/layout/listview_item.xml @@ -5,7 +5,8 @@ android:id="@+id/swipe" android:layout_width="match_parent" android:layout_height="wrap_content" - swipe:horizontalSwipeOffset="0dp"> + swipe:leftEdgeSwipeOffset="0dp" + swipe:rightEdgeSwipeOffset="0dp"> + swipe:leftEdgeSwipeOffset="0dp" + swipe:rightEdgeSwipeOffset="0dp"> + android:layout_width="match_parent" + android:layout_height="80dp"> + + + + + + + + + + + + + + + + + + + + diff --git a/library/src/main/java/com/daimajia/swipe/SwipeLayout.java b/library/src/main/java/com/daimajia/swipe/SwipeLayout.java index 9d1b0a8..8568aad 100644 --- a/library/src/main/java/com/daimajia/swipe/SwipeLayout.java +++ b/library/src/main/java/com/daimajia/swipe/SwipeLayout.java @@ -9,6 +9,7 @@ import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; import android.widget.Adapter; @@ -24,14 +25,34 @@ import java.util.Map; public class SwipeLayout extends FrameLayout { + public static final int EMPTY_LAYOUT = -1; + + private static final int DRAG_LEFT = 1; + private static final int DRAG_RIGHT = 2; + private static final int DRAG_TOP = 4; + private static final int DRAG_BOTTOM = 8; + + private int mTouchSlop; + + private int mLeftIndex; + private int mRightIndex; + private int mTopIndex; + private int mBottomIndex; + + private int mCurrentDirectionIndex = 0; private ViewDragHelper mDragHelper; private int mDragDistance = 0; - private DragEdge mDragEdge; + private List mDragEdges; private ShowMode mShowMode; - private float mHorizontalSwipeOffset; - private float mVerticalSwipeOffset; + private float mLeftEdgeSwipeOffset; + private float mRightEdgeSwipeOffset; + private float mTopEdgeSwipeOffset; + private float mBottomEdgeSwipeOffset; + + private Map mBottomViewIdMap = new HashMap(); + private boolean mBottomViewIdsSet = false; private List mSwipeListeners = new ArrayList(); private List mSwipeDeniers = new ArrayList(); @@ -41,18 +62,24 @@ public class SwipeLayout extends FrameLayout { private DoubleClickListener mDoubleClickListener; private boolean mSwipeEnabled = true; + private boolean mLeftSwipeEnabled = true; + private boolean mRightSwipeEnabled = true; + private boolean mTopSwipeEnabled = true; + private boolean mBottomSwipeEnabled = true; public static enum DragEdge { Left, Right, Top, Bottom; - }; - - public static enum ShowMode { - LayDown, PullOut } + ; + + public static enum ShowMode { + LayDown, + PullOut + } public SwipeLayout(Context context) { this(context, null); @@ -65,44 +92,64 @@ public class SwipeLayout extends FrameLayout { public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mDragHelper = ViewDragHelper.create(this, mDragHelperCallback); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeLayout); - int ordinal = a.getInt(R.styleable.SwipeLayout_drag_edge, DragEdge.Right.ordinal()); - mHorizontalSwipeOffset =a.getDimension(R.styleable.SwipeLayout_horizontalSwipeOffset,0); - mVerticalSwipeOffset =a.getDimension(R.styleable.SwipeLayout_verticalSwipeOffset,0); - mDragEdge = DragEdge.values()[ordinal]; - ordinal = a.getInt(R.styleable.SwipeLayout_show_mode, ShowMode.PullOut.ordinal()); + int dragEdgeChoices = a.getInt(R.styleable.SwipeLayout_drag_edge, DRAG_RIGHT); + mLeftEdgeSwipeOffset = a.getDimension(R.styleable.SwipeLayout_leftEdgeSwipeOffset, 0); + mRightEdgeSwipeOffset = a.getDimension(R.styleable.SwipeLayout_rightEdgeSwipeOffset, 0); + mTopEdgeSwipeOffset = a.getDimension(R.styleable.SwipeLayout_topEdgeSwipeOffset, 0); + mBottomEdgeSwipeOffset = a.getDimension(R.styleable.SwipeLayout_bottomEdgeSwipeOffset, 0); + + mDragEdges = new ArrayList(); + if ((dragEdgeChoices & DRAG_LEFT) == DRAG_LEFT) { + mDragEdges.add(DragEdge.Left); + } + if ((dragEdgeChoices & DRAG_RIGHT) == DRAG_RIGHT) { + mDragEdges.add(DragEdge.Right); + } + if ((dragEdgeChoices & DRAG_TOP) == DRAG_TOP) { + mDragEdges.add(DragEdge.Top); + } + if ((dragEdgeChoices & DRAG_BOTTOM) == DRAG_BOTTOM) { + mDragEdges.add(DragEdge.Bottom); + } + populateIndexes(); + int ordinal = a.getInt(R.styleable.SwipeLayout_show_mode, ShowMode.PullOut.ordinal()); mShowMode = ShowMode.values()[ordinal]; + a.recycle(); } - - public interface SwipeListener{ + public interface SwipeListener { public void onStartOpen(SwipeLayout layout); + public void onOpen(SwipeLayout layout); + public void onStartClose(SwipeLayout layout); + public void onClose(SwipeLayout layout); + public void onUpdate(SwipeLayout layout, int leftOffset, int topOffset); + public void onHandRelease(SwipeLayout layout, float xvel, float yvel); } - public void addSwipeListener(SwipeListener l){ + public void addSwipeListener(SwipeListener l) { mSwipeListeners.add(l); } - public void removeSwipeListener(SwipeListener l){ + public void removeSwipeListener(SwipeListener l) { mSwipeListeners.remove(l); } public static interface SwipeDenier { - /* - * Called in onInterceptTouchEvent - * Determines if this swipe event should be denied - * Implement this interface if you are using views with swipe gestures - * As a child of SwipeLayout - * - * @return true deny - * false allow - */ + /* + * Called in onInterceptTouchEvent Determines if this swipe event should + * be denied Implement this interface if you are using views with swipe + * gestures As a child of SwipeLayout + * + * @return true deny false allow + */ public boolean shouldDenySwipe(MotionEvent ev); } @@ -123,49 +170,52 @@ public class SwipeLayout extends FrameLayout { } /** - * bind a view with a specific {@link com.daimajia.swipe.SwipeLayout.OnRevealListener} + * bind a view with a specific + * {@link com.daimajia.swipe.SwipeLayout.OnRevealListener} + * * @param childId the view id. - * @param l the target {@link com.daimajia.swipe.SwipeLayout.OnRevealListener} + * @param l the target + * {@link com.daimajia.swipe.SwipeLayout.OnRevealListener} */ - public void addRevealListener(int childId, OnRevealListener l){ - View child = findViewById(childId); - if(child == null){ + public void addRevealListener(int childId, OnRevealListener l) { + View child = findViewById(childId); + if (child == null) { throw new IllegalArgumentException("Child does not belong to SwipeListener."); } - if(!mShowEntirely.containsKey(child)){ + if (!mShowEntirely.containsKey(child)) { mShowEntirely.put(child, false); } - if(mRevealListeners.get(child) == null) + if (mRevealListeners.get(child) == null) mRevealListeners.put(child, new ArrayList()); mRevealListeners.get(child).add(l); } /** - * bind multiple views with an {@link com.daimajia.swipe.SwipeLayout.OnRevealListener}. + * bind multiple views with an + * {@link com.daimajia.swipe.SwipeLayout.OnRevealListener}. + * * @param childIds the view id. - * @param l the {@link com.daimajia.swipe.SwipeLayout.OnRevealListener} + * @param l the {@link com.daimajia.swipe.SwipeLayout.OnRevealListener} */ - public void addRevealListener(int[] childIds, OnRevealListener l){ - for(int i : childIds) + public void addRevealListener(int[] childIds, OnRevealListener l) { + for (int i : childIds) addRevealListener(i, l); } - public void removeRevealListener(int childId, OnRevealListener l){ + public void removeRevealListener(int childId, OnRevealListener l) { View child = findViewById(childId); - if(child == null) - return; + if (child == null) return; mShowEntirely.remove(child); - if(mRevealListeners.containsKey(child)) - mRevealListeners.get(child).remove(l); + if (mRevealListeners.containsKey(child)) mRevealListeners.get(child).remove(l); } - public void removeAllRevealListeners(int childId){ + public void removeAllRevealListeners(int childId) { View child = findViewById(childId); - if(child != null){ + if (child != null) { mRevealListeners.remove(child); mShowEntirely.remove(child); } @@ -175,39 +225,36 @@ public class SwipeLayout extends FrameLayout { @Override public int clampViewPositionHorizontal(View child, int left, int dx) { - if(child == getSurfaceView()){ - switch (mDragEdge){ + if (child == getSurfaceView()) { + switch (mDragEdges.get(mCurrentDirectionIndex)) { case Top: case Bottom: return getPaddingLeft(); case Left: - if(left < getPaddingLeft()) - return getPaddingLeft(); - if(left > getPaddingLeft() + mDragDistance) + if (left < getPaddingLeft()) return getPaddingLeft(); + if (left > getPaddingLeft() + mDragDistance) return getPaddingLeft() + mDragDistance; break; case Right: - if(left > getPaddingLeft()) - return getPaddingLeft(); - if(left < getPaddingLeft() - mDragDistance) + if (left > getPaddingLeft()) return getPaddingLeft(); + if (left < getPaddingLeft() - mDragDistance) return getPaddingLeft() - mDragDistance; break; } - }else if(child == getBottomView()){ + } else if (getBottomViews().get(mCurrentDirectionIndex) == child) { - switch (mDragEdge){ + switch (mDragEdges.get(mCurrentDirectionIndex)) { case Top: case Bottom: return getPaddingLeft(); case Left: - if(mShowMode == ShowMode.PullOut){ - if(left > getPaddingLeft()) - return getPaddingLeft(); + if (mShowMode == ShowMode.PullOut) { + if (left > getPaddingLeft()) return getPaddingLeft(); } break; case Right: - if(mShowMode == ShowMode.PullOut){ - if(left < getMeasuredWidth() - mDragDistance){ + if (mShowMode == ShowMode.PullOut) { + if (left < getMeasuredWidth() - mDragDistance) { return getMeasuredWidth() - mDragDistance; } } @@ -219,49 +266,47 @@ public class SwipeLayout extends FrameLayout { @Override public int clampViewPositionVertical(View child, int top, int dy) { - if(child == getSurfaceView()){ - switch (mDragEdge){ + if (child == getSurfaceView()) { + switch (mDragEdges.get(mCurrentDirectionIndex)) { case Left: case Right: return getPaddingTop(); case Top: - if(top < getPaddingTop()) - return getPaddingTop(); - if(top > getPaddingTop() + mDragDistance) + if (top < getPaddingTop()) return getPaddingTop(); + if (top > getPaddingTop() + mDragDistance) return getPaddingTop() + mDragDistance; break; case Bottom: - if(top < getPaddingTop() - mDragDistance){ + if (top < getPaddingTop() - mDragDistance) { return getPaddingTop() - mDragDistance; } - if(top > getPaddingTop()){ + if (top > getPaddingTop()) { return getPaddingTop(); } } - }else{ - switch (mDragEdge){ + } else { + switch (mDragEdges.get(mCurrentDirectionIndex)) { case Left: case Right: return getPaddingTop(); case Top: - if(mShowMode == ShowMode.PullOut){ - if(top > getPaddingTop()) + if (mShowMode == ShowMode.PullOut) { + if (top > getPaddingTop()) return getPaddingTop(); + } else { + if (getSurfaceView().getTop() + dy < getPaddingTop()) return getPaddingTop(); - }else{ - if(getSurfaceView().getTop() + dy < getPaddingTop()) - return getPaddingTop(); - if(getSurfaceView().getTop() + dy > getPaddingTop() + mDragDistance) + if (getSurfaceView().getTop() + dy > getPaddingTop() + mDragDistance) return getPaddingTop() + mDragDistance; } break; case Bottom: - if(mShowMode == ShowMode.PullOut){ - if(top < getMeasuredHeight() - mDragDistance) + if (mShowMode == ShowMode.PullOut) { + if (top < getMeasuredHeight() - mDragDistance) return getMeasuredHeight() - mDragDistance; - }else{ - if(getSurfaceView().getTop() + dy >= getPaddingTop()) + } else { + if (getSurfaceView().getTop() + dy >= getPaddingTop()) return getPaddingTop(); - if(getSurfaceView().getTop() + dy <= getPaddingTop() - mDragDistance) + if (getSurfaceView().getTop() + dy <= getPaddingTop() - mDragDistance) return getPaddingTop() - mDragDistance; } } @@ -271,7 +316,7 @@ public class SwipeLayout extends FrameLayout { @Override public boolean tryCaptureView(View child, int pointerId) { - return child == getSurfaceView() || child == getBottomView(); + return child == getSurfaceView() || getBottomViews().contains(child); } @Override @@ -287,14 +332,14 @@ public class SwipeLayout extends FrameLayout { @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); - for(SwipeListener l : mSwipeListeners) + for (SwipeListener l : mSwipeListeners) l.onHandRelease(SwipeLayout.this, xvel, yvel); - if(releasedChild == getSurfaceView()){ + if (releasedChild == getSurfaceView()) { processSurfaceRelease(xvel, yvel); - }else if(releasedChild == getBottomView()){ - if(getShowMode() == ShowMode.PullOut){ + } else if (getBottomViews().contains(releasedChild)) { + if (getShowMode() == ShowMode.PullOut) { processBottomPullOutRelease(xvel, yvel); - }else if(getShowMode() == ShowMode.LayDown){ + } else if (getShowMode() == ShowMode.LayDown) { processBottomLayDownMode(xvel, yvel); } } @@ -304,34 +349,39 @@ public class SwipeLayout extends FrameLayout { @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { - int evLeft = getSurfaceView().getLeft(), evRight = getSurfaceView().getRight(), - evTop = getSurfaceView().getTop(),evBottom = getSurfaceView().getBottom(); - if(changedView == getSurfaceView()){ + int evLeft = getSurfaceView().getLeft(), evRight = getSurfaceView().getRight(), evTop = getSurfaceView() + .getTop(), evBottom = getSurfaceView().getBottom(); + if (changedView == getSurfaceView()) { - if(mShowMode == ShowMode.PullOut){ - if(mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) - getBottomView().offsetLeftAndRight(dx); - else - getBottomView().offsetTopAndBottom(dy); + if (mShowMode == ShowMode.PullOut) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left + || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + getBottomViews().get(mCurrentDirectionIndex).offsetLeftAndRight(dx); + else getBottomViews().get(mCurrentDirectionIndex).offsetTopAndBottom(dy); } - }else if(changedView == getBottomView()){ + } else if (getBottomViews().contains(changedView)) { - if(mShowMode == ShowMode.PullOut){ + if (mShowMode == ShowMode.PullOut) { getSurfaceView().offsetLeftAndRight(dx); getSurfaceView().offsetTopAndBottom(dy); - }else{ - Rect rect = computeBottomLayDown(mDragEdge); - getBottomView().layout(rect.left, rect.top, rect.right, rect.bottom); + } else { + Rect rect = computeBottomLayDown(mDragEdges.get(mCurrentDirectionIndex)); + getBottomViews().get(mCurrentDirectionIndex).layout(rect.left, rect.top, rect.right, rect.bottom); int newLeft = getSurfaceView().getLeft() + dx, newTop = getSurfaceView().getTop() + dy; - if(mDragEdge == DragEdge.Left && newLeft < getPaddingLeft()) newLeft = getPaddingLeft(); - else if(mDragEdge == DragEdge.Right && newLeft > getPaddingLeft()) newLeft = getPaddingLeft(); - else if(mDragEdge == DragEdge.Top && newTop < getPaddingTop()) newTop = getPaddingTop(); - else if(mDragEdge == DragEdge.Bottom && newTop > getPaddingTop()) newTop = getPaddingTop(); + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left && newLeft < getPaddingLeft()) + newLeft = getPaddingLeft(); + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right && newLeft > getPaddingLeft()) + newLeft = getPaddingLeft(); + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top && newTop < getPaddingTop()) + newTop = getPaddingTop(); + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Bottom && newTop > getPaddingTop()) + newTop = getPaddingTop(); - getSurfaceView().layout(newLeft, newTop, newLeft + getMeasuredWidth(), newTop + getMeasuredHeight()); + getSurfaceView() + .layout(newLeft, newTop, newLeft + getMeasuredWidth(), newTop + getMeasuredHeight()); } } @@ -344,8 +394,10 @@ public class SwipeLayout extends FrameLayout { }; /** - * the dispatchRevealEvent method may not always get accurate position, it makes the view may not always get the event when the view is - * totally show( fraction = 1), so , we need to calculate every time. + * the dispatchRevealEvent method may not always get accurate position, it + * makes the view may not always get the event when the view is totally + * show( fraction = 1), so , we need to calculate every time. + * * @param child * @param relativePosition * @param edge @@ -355,91 +407,82 @@ public class SwipeLayout extends FrameLayout { * @param surfaceBottom * @return */ - protected boolean isViewTotallyFirstShowed(View child, Rect relativePosition, DragEdge edge, int surfaceLeft, int surfaceTop, int surfaceRight, int surfaceBottom){ - if(mShowEntirely.get(child)) - return false; + protected boolean isViewTotallyFirstShowed(View child, Rect relativePosition, DragEdge edge, int surfaceLeft, + int surfaceTop, int surfaceRight, int surfaceBottom) { + if (mShowEntirely.get(child)) return false; int childLeft = relativePosition.left; int childRight = relativePosition.right; int childTop = relativePosition.top; int childBottom = relativePosition.bottom; boolean r = false; - if(getShowMode() == ShowMode.LayDown) { - if((edge == DragEdge.Right && surfaceRight <= childLeft) - || (edge == DragEdge.Left && surfaceLeft >= childRight) - || (edge == DragEdge.Top && surfaceTop >= childBottom) - || (edge == DragEdge.Bottom && surfaceBottom <= childTop)) - r = true; - } - else if(getShowMode() == ShowMode.PullOut){ - if((edge == DragEdge.Right && childRight <= getWidth()) - || (edge == DragEdge.Left && childLeft >= getPaddingLeft()) - || (edge == DragEdge.Top && childTop >= getPaddingTop()) - || (edge == DragEdge.Bottom && childBottom <= getHeight())) - r = true; + if (getShowMode() == ShowMode.LayDown) { + if ((edge == DragEdge.Right && surfaceRight <= childLeft) + || (edge == DragEdge.Left && surfaceLeft >= childRight) + || (edge == DragEdge.Top && surfaceTop >= childBottom) + || (edge == DragEdge.Bottom && surfaceBottom <= childTop)) r = true; + } else if (getShowMode() == ShowMode.PullOut) { + if ((edge == DragEdge.Right && childRight <= getWidth()) + || (edge == DragEdge.Left && childLeft >= getPaddingLeft()) + || (edge == DragEdge.Top && childTop >= getPaddingTop()) + || (edge == DragEdge.Bottom && childBottom <= getHeight())) r = true; } return r; } - protected boolean isViewShowing(View child, Rect relativePosition, DragEdge availableEdge, int surfaceLeft, int surfaceTop, int surfaceRight, int surfaceBottom){ + protected boolean isViewShowing(View child, Rect relativePosition, DragEdge availableEdge, int surfaceLeft, + int surfaceTop, int surfaceRight, int surfaceBottom) { int childLeft = relativePosition.left; int childRight = relativePosition.right; int childTop = relativePosition.top; int childBottom = relativePosition.bottom; - if(getShowMode() == ShowMode.LayDown){ - switch (availableEdge){ + if (getShowMode() == ShowMode.LayDown) { + switch (availableEdge) { case Right: - if(surfaceRight > childLeft && surfaceRight <= childRight){ + if (surfaceRight > childLeft && surfaceRight <= childRight) { return true; } break; case Left: - if(surfaceLeft < childRight && surfaceLeft >= childLeft){ + if (surfaceLeft < childRight && surfaceLeft >= childLeft) { return true; } break; case Top: - if(surfaceTop >= childTop && surfaceTop < childBottom){ - return true; + if (surfaceTop >= childTop && surfaceTop < childBottom) { + return true; } break; case Bottom: - if(surfaceBottom > childTop && surfaceBottom <= childBottom){ + if (surfaceBottom > childTop && surfaceBottom <= childBottom) { return true; } break; } - }else if(getShowMode() == ShowMode.PullOut){ - switch (availableEdge){ + } else if (getShowMode() == ShowMode.PullOut) { + switch (availableEdge) { case Right: - if(childLeft <= getWidth() && childRight > getWidth()) - return true; + if (childLeft <= getWidth() && childRight > getWidth()) return true; break; case Left: - if(childRight >= getPaddingLeft() && childLeft < getPaddingLeft()) - return true; + if (childRight >= getPaddingLeft() && childLeft < getPaddingLeft()) return true; break; case Top: - if(childTop < getPaddingTop() && childBottom >= getPaddingTop()) - return true; + if (childTop < getPaddingTop() && childBottom >= getPaddingTop()) return true; break; case Bottom: - if(childTop < getHeight() && childTop >= getPaddingTop()) - return true; + if (childTop < getHeight() && childTop >= getPaddingTop()) return true; break; } } return false; } - - - protected Rect getRelativePosition(View child){ + protected Rect getRelativePosition(View child) { View t = child; - Rect r = new Rect(t.getLeft(), t.getTop(), 0 , 0); - while(t.getParent() != null && t != getRootView()){ - t = (View)t.getParent(); - if(t == this) - break; + Rect r = new Rect(t.getLeft(), t.getTop(), 0, 0); + while (t.getParent() != null && t != getRootView()) { + t = (View) t.getParent(); + if (t == this) break; r.left += t.getLeft(); r.top += t.getTop(); } @@ -450,49 +493,49 @@ public class SwipeLayout extends FrameLayout { private int mEventCounter = 0; - protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, int dx, int dy){ + protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, int dx, int dy) { DragEdge edge = getDragEdge(); boolean open = true; - if(edge == DragEdge.Left){ - if(dx < 0) open = false; - }else if(edge == DragEdge.Right){ - if(dx > 0) open = false; - }else if(edge == DragEdge.Top){ - if(dy < 0) open = false; - }else if(edge == DragEdge.Bottom){ - if(dy > 0) open = false; + if (edge == DragEdge.Left) { + if (dx < 0) open = false; + } else if (edge == DragEdge.Right) { + if (dx > 0) open = false; + } else if (edge == DragEdge.Top) { + if (dy < 0) open = false; + } else if (edge == DragEdge.Bottom) { + if (dy > 0) open = false; } dispatchSwipeEvent(surfaceLeft, surfaceTop, open); } - protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, boolean open){ + protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, boolean open) { safeBottomView(); Status status = getOpenStatus(); - if(!mSwipeListeners.isEmpty()){ + if (!mSwipeListeners.isEmpty()) { mEventCounter++; - for(SwipeListener l : mSwipeListeners){ - if(mEventCounter == 1){ - if(open){ + for (SwipeListener l : mSwipeListeners) { + if (mEventCounter == 1) { + if (open) { l.onStartOpen(this); - }else{ + } else { l.onStartClose(this); } } l.onUpdate(SwipeLayout.this, surfaceLeft - getPaddingLeft(), surfaceTop - getPaddingTop()); } - if(status == Status.Close){ - for(SwipeListener l : mSwipeListeners){ + if (status == Status.Close) { + for (SwipeListener l : mSwipeListeners) { l.onClose(SwipeLayout.this); } mEventCounter = 0; } - if(status == Status.Open){ - getBottomView().setEnabled(true); - for(SwipeListener l : mSwipeListeners){ + if (status == Status.Open) { + getBottomViews().get(mCurrentDirectionIndex).setEnabled(true); + for (SwipeListener l : mSwipeListeners) { l.onOpen(SwipeLayout.this); } mEventCounter = 0; @@ -503,84 +546,88 @@ public class SwipeLayout extends FrameLayout { /** * prevent bottom view get any touch event. Especially in LayDown mode. */ - private void safeBottomView(){ + private void safeBottomView() { Status status = getOpenStatus(); - ViewGroup bottom = getBottomView(); + List bottoms = getBottomViews(); - if(status == Status.Close){ - if(bottom.getVisibility() != INVISIBLE) - bottom.setVisibility(INVISIBLE); - }else { - if(bottom.getVisibility() != VISIBLE) - bottom.setVisibility(VISIBLE); + if (status == Status.Close) { + for (ViewGroup bottom : bottoms) { + if (bottom.getVisibility() != INVISIBLE) bottom.setVisibility(INVISIBLE); + } + } else { + if (bottoms.get(mCurrentDirectionIndex).getVisibility() != VISIBLE) + bottoms.get(mCurrentDirectionIndex).setVisibility(VISIBLE); } } - - protected void dispatchRevealEvent(final int surfaceLeft, final int surfaceTop, final int surfaceRight, final int surfaceBottom){ - if(mRevealListeners.isEmpty()) return; - for(Map.Entry> entry : mRevealListeners.entrySet()){ + protected void dispatchRevealEvent(final int surfaceLeft, final int surfaceTop, final int surfaceRight, + final int surfaceBottom) { + if (mRevealListeners.isEmpty()) return; + for (Map.Entry> entry : mRevealListeners.entrySet()) { View child = entry.getKey(); Rect rect = getRelativePosition(child); - if(isViewShowing(child,rect, mDragEdge, surfaceLeft, surfaceTop, surfaceRight, surfaceBottom)){ + if (isViewShowing(child, rect, mDragEdges.get(mCurrentDirectionIndex), surfaceLeft, surfaceTop, + surfaceRight, surfaceBottom)) { mShowEntirely.put(child, false); int distance = 0; float fraction = 0f; - if(getShowMode() == ShowMode.LayDown){ - switch (mDragEdge){ + if (getShowMode() == ShowMode.LayDown) { + switch (mDragEdges.get(mCurrentDirectionIndex)) { case Left: distance = rect.left - surfaceLeft; - fraction = distance/(float)child.getWidth(); + fraction = distance / (float) child.getWidth(); break; case Right: distance = rect.right - surfaceRight; - fraction = distance/(float)child.getWidth(); + fraction = distance / (float) child.getWidth(); break; case Top: distance = rect.top - surfaceTop; - fraction = distance/(float)child.getHeight(); + fraction = distance / (float) child.getHeight(); break; case Bottom: distance = rect.bottom - surfaceBottom; - fraction = distance/(float)child.getHeight(); + fraction = distance / (float) child.getHeight(); break; } - }else if(getShowMode() == ShowMode.PullOut){ - switch (mDragEdge){ + } else if (getShowMode() == ShowMode.PullOut) { + switch (mDragEdges.get(mCurrentDirectionIndex)) { case Left: distance = rect.right - getPaddingLeft(); - fraction = distance / (float)child.getWidth(); + fraction = distance / (float) child.getWidth(); break; case Right: distance = rect.left - getWidth(); - fraction = distance / (float)child.getWidth(); + fraction = distance / (float) child.getWidth(); break; case Top: distance = rect.bottom - getPaddingTop(); - fraction = distance/(float)child.getHeight(); + fraction = distance / (float) child.getHeight(); break; case Bottom: distance = rect.top - getHeight(); - fraction = distance/(float)child.getHeight(); + fraction = distance / (float) child.getHeight(); break; } } - for(OnRevealListener l : entry.getValue()){ - l.onReveal(child, mDragEdge, Math.abs(fraction), distance); - if(Math.abs(fraction) == 1){ + for (OnRevealListener l : entry.getValue()) { + l.onReveal(child, mDragEdges.get(mCurrentDirectionIndex), Math.abs(fraction), distance); + if (Math.abs(fraction) == 1) { mShowEntirely.put(child, true); } } } - if(isViewTotallyFirstShowed(child, rect, mDragEdge, surfaceLeft, surfaceTop, surfaceRight, surfaceBottom)){ + if (isViewTotallyFirstShowed(child, rect, mDragEdges.get(mCurrentDirectionIndex), surfaceLeft, surfaceTop, + surfaceRight, surfaceBottom)) { mShowEntirely.put(child, true); - for(OnRevealListener l : entry.getValue()){ - if(mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) - l.onReveal(child, mDragEdge, 1, child.getWidth()); + for (OnRevealListener l : entry.getValue()) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left + || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + l.onReveal(child, mDragEdges.get(mCurrentDirectionIndex), 1, child.getWidth()); else - l.onReveal(child, mDragEdge, 1, child.getHeight()); + l.onReveal(child, mDragEdges.get(mCurrentDirectionIndex), 1, child.getHeight()); } } @@ -590,81 +637,80 @@ public class SwipeLayout extends FrameLayout { @Override public void computeScroll() { super.computeScroll(); - if(mDragHelper.continueSettling(true)) { + if (mDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } /** - * {@link android.view.View.OnLayoutChangeListener} added in API 11. - * I need to support it from API 8. + * {@link android.view.View.OnLayoutChangeListener} added in API 11. I need + * to support it from API 8. */ - public interface OnLayout{ + public interface OnLayout { public void onLayout(SwipeLayout v); } private List mOnLayoutListeners; - public void addOnLayoutListener(OnLayout l){ - if(mOnLayoutListeners == null) - mOnLayoutListeners = new ArrayList(); + public void addOnLayoutListener(OnLayout l) { + if (mOnLayoutListeners == null) mOnLayoutListeners = new ArrayList(); mOnLayoutListeners.add(l); } - public void removeOnLayoutListener(OnLayout l){ - if(mOnLayoutListeners != null) - mOnLayoutListeners.remove(l); + public void removeOnLayoutListener(OnLayout l) { + if (mOnLayoutListeners != null) mOnLayoutListeners.remove(l); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = getChildCount(); - if(childCount != 2){ - throw new IllegalStateException("You need 2 views in SwipeLayout"); + if (childCount != 1 + mDragEdges.size()) { + throw new IllegalStateException("You need to have one surface view plus one view for each of your drag edges"); } - if(!(getChildAt(0) instanceof ViewGroup) || !(getChildAt(1) instanceof ViewGroup)){ - throw new IllegalArgumentException("The 2 children in SwipeLayout must be an instance of ViewGroup"); + for (int i = 0; i < childCount; i++) { + if (!(getChildAt(i) instanceof ViewGroup)) { + throw new IllegalArgumentException("All the children in SwipeLayout must be an instance of ViewGroup"); + } } - if(mShowMode == ShowMode.PullOut) + if (mShowMode == ShowMode.PullOut) layoutPullOut(); - else if(mShowMode == ShowMode.LayDown) - layoutLayDown(); + else if (mShowMode == ShowMode.LayDown) layoutLayDown(); safeBottomView(); - if(mOnLayoutListeners != null) - for(int i = 0; i < mOnLayoutListeners.size(); i++){ - mOnLayoutListeners.get(i).onLayout(this); - } + if (mOnLayoutListeners != null) for (int i = 0; i < mOnLayoutListeners.size(); i++) { + mOnLayoutListeners.get(i).onLayout(this); + } } - void layoutPullOut(){ + void layoutPullOut() { Rect rect = computeSurfaceLayoutArea(false); getSurfaceView().layout(rect.left, rect.top, rect.right, rect.bottom); rect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, rect); - getBottomView().layout(rect.left, rect.top, rect.right, rect.bottom); + getBottomViews().get(mCurrentDirectionIndex).layout(rect.left, rect.top, rect.right, rect.bottom); bringChildToFront(getSurfaceView()); } - void layoutLayDown(){ + void layoutLayDown() { Rect rect = computeSurfaceLayoutArea(false); getSurfaceView().layout(rect.left, rect.top, rect.right, rect.bottom); rect = computeBottomLayoutAreaViaSurface(ShowMode.LayDown, rect); - getBottomView().layout(rect.left, rect.top, rect.right, rect.bottom); + getBottomViews().get(mCurrentDirectionIndex).layout(rect.left, rect.top, rect.right, rect.bottom); bringChildToFront(getSurfaceView()); } - @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if(mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) - mDragDistance = getBottomView().getMeasuredWidth()-dp2px(mHorizontalSwipeOffset); - else - mDragDistance = getBottomView().getMeasuredHeight()-dp2px(mVerticalSwipeOffset); + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left + || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + mDragDistance = getBottomViews().get(mCurrentDirectionIndex).getMeasuredWidth() + - dp2px(getCurrentOffset()); + else mDragDistance = getBottomViews().get(mCurrentDirectionIndex).getMeasuredHeight() + - dp2px(getCurrentOffset()); } private boolean mTouchConsumedByChild = false; @@ -672,11 +718,11 @@ public class SwipeLayout extends FrameLayout { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - if(!isEnabled() || !isEnabledInAdapterView()){ + if (!isEnabled() || !isEnabledInAdapterView()) { return true; } - if(!isSwipeEnabled()){ + if (!isSwipeEnabled()) { return false; } @@ -686,17 +732,17 @@ public class SwipeLayout extends FrameLayout { } } // - //if a child wants to handle the touch event, - //then let it do it. + // if a child wants to handle the touch event, + // then let it do it. // int action = ev.getActionMasked(); - switch (action){ + switch (action) { case MotionEvent.ACTION_DOWN: Status status = getOpenStatus(); - if(status == Status.Close){ + if (status == Status.Close) { mTouchConsumedByChild = childNeedHandleTouchEvent(getSurfaceView(), ev) != null; - }else if(status == Status.Open){ - mTouchConsumedByChild = childNeedHandleTouchEvent(getBottomView(), ev) != null; + } else if (status == Status.Open) { + mTouchConsumedByChild = childNeedHandleTouchEvent(getBottomViews().get(mCurrentDirectionIndex), ev) != null; } break; case MotionEvent.ACTION_UP: @@ -704,31 +750,29 @@ public class SwipeLayout extends FrameLayout { mTouchConsumedByChild = false; } - if(mTouchConsumedByChild) return false; + if (mTouchConsumedByChild) return false; return mDragHelper.shouldInterceptTouchEvent(ev); } /** * if the ViewGroup children want to handle this event. + * * @param v * @param event * @return */ - private View childNeedHandleTouchEvent(ViewGroup v, MotionEvent event){ - if(v == null) return null; - if(v.onTouchEvent(event)) - return v; + private View childNeedHandleTouchEvent(ViewGroup v, MotionEvent event) { + if (v == null) return null; + if (v.onTouchEvent(event)) return v; int childCount = v.getChildCount(); - for(int i = childCount - 1; i >= 0; i--){ + for (int i = childCount - 1; i >= 0; i--) { View child = v.getChildAt(i); - if(child instanceof ViewGroup){ + if (child instanceof ViewGroup) { View grandChild = childNeedHandleTouchEvent((ViewGroup) child, event); - if(grandChild != null) - return grandChild; - }else{ - if(childNeedHandleTouchEvent(v.getChildAt(i), event)) - return v.getChildAt(i); + if (grandChild != null) return grandChild; + } else { + if (childNeedHandleTouchEvent(v.getChildAt(i), event)) return v.getChildAt(i); } } return null; @@ -736,33 +780,41 @@ public class SwipeLayout extends FrameLayout { /** * if the view (v) wants to handle this event. + * * @param v * @param event * @return */ - private boolean childNeedHandleTouchEvent(View v, MotionEvent event){ - if(v == null) return false; + private boolean childNeedHandleTouchEvent(View v, MotionEvent event) { + if (v == null) return false; int[] loc = new int[2]; v.getLocationOnScreen(loc); int left = loc[0], top = loc[1]; - if(event.getRawX() > left && event.getRawX() < left + v.getWidth() - && event.getRawY() > top && event.getRawY() < top + v.getHeight()){ + if (event.getRawX() > left && event.getRawX() < left + v.getWidth() && event.getRawY() > top + && event.getRawY() < top + v.getHeight()) { return v.onTouchEvent(event); } return false; } - private float sX = -1 , sY = -1; + private float sX = -1, sY = -1; + + private boolean shouldAllowSwipe() { + if (mCurrentDirectionIndex == mLeftIndex && !mLeftSwipeEnabled) return false; + if (mCurrentDirectionIndex == mRightIndex && !mRightSwipeEnabled) return false; + if (mCurrentDirectionIndex == mTopIndex && !mTopSwipeEnabled) return false; + if (mCurrentDirectionIndex == mBottomIndex && !mBottomSwipeEnabled) return false; + return true; + } + @Override public boolean onTouchEvent(MotionEvent event) { - if(!isEnabledInAdapterView() || !isEnabled()) - return true; + if (!isEnabledInAdapterView() || !isEnabled()) return true; - if(!isSwipeEnabled()) - return super.onTouchEvent(event); + if (!isSwipeEnabled()) return super.onTouchEvent(event); int action = event.getActionMasked(); ViewParent parent = getParent(); @@ -770,13 +822,13 @@ public class SwipeLayout extends FrameLayout { gestureDetector.onTouchEvent(event); Status status = getOpenStatus(); ViewGroup touching = null; - if(status == Status.Close){ + if (status == Status.Close) { touching = getSurfaceView(); - }else if(status == Status.Open){ - touching = getBottomView(); + } else if (status == Status.Open) { + touching = getBottomViews().get(mCurrentDirectionIndex); } - switch (action){ + switch (action) { case MotionEvent.ACTION_DOWN: mDragHelper.processTouchEvent(event); parent.requestDisallowInterceptTouchEvent(true); @@ -784,57 +836,80 @@ public class SwipeLayout extends FrameLayout { sX = event.getRawX(); sY = event.getRawY(); - if(touching != null) - touching.setPressed(true); + if (touching != null) touching.setPressed(true); return true; - case MotionEvent.ACTION_MOVE:{ + case MotionEvent.ACTION_MOVE: { float distanceX = event.getRawX() - sX; float distanceY = event.getRawY() - sY; float angle = Math.abs(distanceY / distanceX); - angle = (float)Math.toDegrees(Math.atan(angle)); + angle = (float) Math.toDegrees(Math.atan(angle)); + if (getOpenStatus() == Status.Close) { + int lastCurrentDirectionIndex = mCurrentDirectionIndex; + if (angle < 45) { + if (mLeftIndex != -1 && distanceX > 0 && isLeftSwipeEnabled()) { + mCurrentDirectionIndex = mLeftIndex; + } else if (mRightIndex != -1 && distanceX < 0 && isRightSwipeEnabled()) { + mCurrentDirectionIndex = mRightIndex; + } + } else { + if (mTopIndex != -1 && distanceY > 0 && isTopSwipeEnabled()) { + mCurrentDirectionIndex = mTopIndex; + } else if (mBottomIndex != -1 && distanceY < 0 && isBottomSwipeEnabled()) { + mCurrentDirectionIndex = mBottomIndex; + } + } + if (lastCurrentDirectionIndex != mCurrentDirectionIndex) { + updateBottomViews(); + } + } + if (!shouldAllowSwipe()) return super.onTouchEvent(event); boolean doNothing = false; - if(mDragEdge == DragEdge.Right){ - boolean suitable = (status == Status.Open && distanceX > 0) || (status == Status.Close && distanceX < 0); + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) { + boolean suitable = (status == Status.Open && distanceX > mTouchSlop) + || (status == Status.Close && distanceX < -mTouchSlop); suitable = suitable || (status == Status.Middle); - if(angle > 30 || !suitable){ + if (angle > 30 || !suitable) { doNothing = true; } } - if(mDragEdge == DragEdge.Left){ - boolean suitable = (status == Status.Open && distanceX < 0 ) || (status == Status.Close && distanceX > 0); + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) { + boolean suitable = (status == Status.Open && distanceX < -mTouchSlop) + || (status == Status.Close && distanceX > mTouchSlop); suitable = suitable || status == Status.Middle; - if(angle > 30 || ! suitable){ + if (angle > 30 || !suitable) { doNothing = true; } } - if(mDragEdge == DragEdge.Top){ - boolean suitable = (status == Status.Open && distanceY < 0 ) || (status == Status.Close && distanceY > 0); + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) { + boolean suitable = (status == Status.Open && distanceY < -mTouchSlop) + || (status == Status.Close && distanceY > mTouchSlop); suitable = suitable || status == Status.Middle; - if(angle < 60 || ! suitable){ + if (angle < 60 || !suitable) { doNothing = true; } } - if(mDragEdge == DragEdge.Bottom){ - boolean suitable = (status == Status.Open && distanceY > 0 ) || (status == Status.Close && distanceY < 0); + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Bottom) { + boolean suitable = (status == Status.Open && distanceY > mTouchSlop) + || (status == Status.Close && distanceY < -mTouchSlop); suitable = suitable || status == Status.Middle; - if(angle < 60 || ! suitable){ + if (angle < 60 || !suitable) { doNothing = true; } } - if(doNothing){ + if (doNothing) { parent.requestDisallowInterceptTouchEvent(false); return false; - }else{ - if(touching != null){ + } else { + if (touching != null) { touching.setPressed(false); } parent.requestDisallowInterceptTouchEvent(true); @@ -843,11 +918,10 @@ public class SwipeLayout extends FrameLayout { break; } case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - { + case MotionEvent.ACTION_CANCEL: { sX = -1; sY = -1; - if(touching != null){ + if (touching != null) { touching.setPressed(false); } } @@ -860,20 +934,21 @@ public class SwipeLayout extends FrameLayout { } /** - * if working in {@link android.widget.AdapterView}, we should response {@link android.widget.Adapter} - * isEnable(int position). + * if working in {@link android.widget.AdapterView}, we should response + * {@link android.widget.Adapter} isEnable(int position). + * * @return true when item is enabled, else disabled. */ - private boolean isEnabledInAdapterView(){ + private boolean isEnabledInAdapterView() { AdapterView adapterView = getAdapterView(); boolean enable = true; - if(adapterView != null){ + if (adapterView != null) { Adapter adapter = adapterView.getAdapter(); - if(adapter != null){ + if (adapter != null) { int p = adapterView.getPositionForView(SwipeLayout.this); - if(adapter instanceof BaseAdapter){ + if (adapter instanceof BaseAdapter) { enable = ((BaseAdapter) adapter).isEnabled(p); - }else if(adapter instanceof ListAdapter){ + } else if (adapter instanceof ListAdapter) { enable = ((ListAdapter) adapter).isEnabled(p); } } @@ -881,63 +956,98 @@ public class SwipeLayout extends FrameLayout { return enable; } - public void setSwipeEnabled(boolean enabled){ + public void setSwipeEnabled(boolean enabled) { mSwipeEnabled = enabled; } - public boolean isSwipeEnabled(){ + public boolean isSwipeEnabled() { return mSwipeEnabled; } - private boolean insideAdapterView(){ + public boolean isLeftSwipeEnabled() { + return mLeftSwipeEnabled; + } + + public void setLeftSwipeEnabled(boolean leftSwipeEnabled) { + this.mLeftSwipeEnabled = leftSwipeEnabled; + } + + public boolean isRightSwipeEnabled() { + return mRightSwipeEnabled; + } + + public void setRightSwipeEnabled(boolean rightSwipeEnabled) { + this.mRightSwipeEnabled = rightSwipeEnabled; + } + + public boolean isTopSwipeEnabled() { + return mTopSwipeEnabled; + } + + public void setTopSwipeEnabled(boolean topSwipeEnabled) { + this.mTopSwipeEnabled = topSwipeEnabled; + } + + public boolean isBottomSwipeEnabled() { + return mBottomSwipeEnabled; + } + + public void setBottomSwipeEnabled(boolean bottomSwipeEnabled) { + this.mBottomSwipeEnabled = bottomSwipeEnabled; + } + + private boolean insideAdapterView() { return getAdapterView() != null; } - private AdapterView getAdapterView(){ + private AdapterView getAdapterView() { ViewParent t = getParent(); - while(t != null){ - if(t instanceof AdapterView){ - return (AdapterView)t; + while (t != null) { + if (t instanceof AdapterView) { + return (AdapterView) t; } t = t.getParent(); } return null; } - private void performAdapterViewItemClick(MotionEvent e){ + private void performAdapterViewItemClick(MotionEvent e) { ViewParent t = getParent(); - while(t != null) { - if(t instanceof AdapterView){ - AdapterView view = (AdapterView)t; + while (t != null) { + if (t instanceof AdapterView) { + AdapterView view = (AdapterView) t; int p = view.getPositionForView(SwipeLayout.this); - if( p != AdapterView.INVALID_POSITION && - view.performItemClick(view.getChildAt(p-view.getFirstVisiblePosition()), p, view.getAdapter().getItemId(p))) - return; - }else{ - if(t instanceof View && ((View) t).performClick()) - return; + if (p != AdapterView.INVALID_POSITION + && view.performItemClick(view.getChildAt(p - view.getFirstVisiblePosition()), p, view + .getAdapter().getItemId(p))) return; + } else { + if (t instanceof View && ((View) t).performClick()) return; } t = t.getParent(); } } private GestureDetector gestureDetector = new GestureDetector(getContext(), new SwipeDetector()); - class SwipeDetector extends GestureDetector.SimpleOnGestureListener{ + + class SwipeDetector extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } /** - * Simulate the touch event lifecycle. If you use SwipeLayout in {@link android.widget.AdapterView} - * ({@link android.widget.ListView}, {@link android.widget.GridView} etc.) It will manually call - * {@link android.widget.AdapterView}.performItemClick, performItemLongClick. + * Simulate the touch event lifecycle. If you use SwipeLayout in + * {@link android.widget.AdapterView} ({@link android.widget.ListView}, + * {@link android.widget.GridView} etc.) It will manually call + * {@link android.widget.AdapterView}.performItemClick, + * performItemLongClick. + * * @param e * @return */ @Override public boolean onSingleTapUp(MotionEvent e) { - if(mDoubleClickListener == null){ + if (mDoubleClickListener == null) { performAdapterViewItemClick(e); } return true; @@ -945,7 +1055,7 @@ public class SwipeLayout extends FrameLayout { @Override public boolean onSingleTapConfirmed(MotionEvent e) { - if(mDoubleClickListener != null){ + if (mDoubleClickListener != null) { performAdapterViewItemClick(e); } return true; @@ -958,14 +1068,14 @@ public class SwipeLayout extends FrameLayout { @Override public boolean onDoubleTap(MotionEvent e) { - if(mDoubleClickListener != null){ + if (mDoubleClickListener != null) { View target; - ViewGroup bottom = getBottomView(); + ViewGroup bottom = getBottomViews().get(mCurrentDirectionIndex); ViewGroup surface = getSurfaceView(); - if(e.getX() > bottom.getLeft() && e.getX() < bottom.getRight() - && e.getY() > bottom.getTop() && e.getY() < bottom.getBottom()){ + if (e.getX() > bottom.getLeft() && e.getX() < bottom.getRight() && e.getY() > bottom.getTop() + && e.getY() < bottom.getBottom()) { target = bottom; - }else{ + } else { target = surface; } mDoubleClickListener.onDoubleClick(SwipeLayout.this, target == surface); @@ -974,68 +1084,136 @@ public class SwipeLayout extends FrameLayout { } } - public void setDragEdge(DragEdge dragEdge){ - mDragEdge = dragEdge; + public void setDragEdge(DragEdge dragEdge) { + mDragEdges = new ArrayList(); + mDragEdges.add(dragEdge); + mCurrentDirectionIndex = 0; + populateIndexes(); requestLayout(); + updateBottomViews(); } /** - * set the drag distance, it will force set the bottom view's width or height via this value. + * set the drag distance, it will force set the bottom view's width or + * height via this value. + * * @param max */ - public void setDragDistance(int max){ - if(max < 0) - throw new IllegalArgumentException("Drag distance can not be < 0"); + public void setDragDistance(int max) { + if (max < 0) throw new IllegalArgumentException("Drag distance can not be < 0"); mDragDistance = dp2px(max); requestLayout(); } /** * There are 2 diffirent show mode. - * {@link com.daimajia.swipe.SwipeLayout.ShowMode}.PullOut and {@link com.daimajia.swipe.SwipeLayout.ShowMode}.LayDown. + * {@link com.daimajia.swipe.SwipeLayout.ShowMode}.PullOut and + * {@link com.daimajia.swipe.SwipeLayout.ShowMode}.LayDown. + * * @param mode */ - public void setShowMode(ShowMode mode){ + public void setShowMode(ShowMode mode) { mShowMode = mode; requestLayout(); } - public DragEdge getDragEdge(){ - return mDragEdge; + public DragEdge getDragEdge() { + return mDragEdges.get(mCurrentDirectionIndex); } - public int getDragDistance(){ + public int getDragDistance() { return mDragDistance; } - public ShowMode getShowMode(){ + public ShowMode getShowMode() { return mShowMode; } - public ViewGroup getSurfaceView(){ - return (ViewGroup)getChildAt(1); + public ViewGroup getSurfaceView() { + return (ViewGroup) getChildAt(getChildCount() - 1); } - public ViewGroup getBottomView(){ - return (ViewGroup)getChildAt(0); + public List getBottomViews() { + List lvg = new ArrayList(); + // If the user has provided a map for views to + if (mBottomViewIdsSet) { + if (mDragEdges.contains(DragEdge.Left)) { + lvg.add(mLeftIndex, ((ViewGroup) findViewById(mBottomViewIdMap.get(DragEdge.Left)))); + } + if (mDragEdges.contains(DragEdge.Right)) { + lvg.add(mRightIndex, ((ViewGroup) findViewById(mBottomViewIdMap.get(DragEdge.Right)))); + } + if (mDragEdges.contains(DragEdge.Top)) { + lvg.add(mTopIndex, ((ViewGroup) findViewById(mBottomViewIdMap.get(DragEdge.Top)))); + } + if (mDragEdges.contains(DragEdge.Bottom)) { + lvg.add(mBottomIndex, ((ViewGroup) findViewById(mBottomViewIdMap.get(DragEdge.Bottom)))); + } + } + // Default behaviour is to simply use the first n-1 children in the order they're listed in the layout + // and return them in + else { + for (int i = 0; i < (getChildCount() - 1); i++) { + lvg.add((ViewGroup) getChildAt(i)); + } + } + return lvg; + } + + // Pass the id of the view if set, otherwise pass -1 + public void setBottomViewIds(int left, int right, int top, int bottom) { + if (mDragEdges.contains(DragEdge.Left)) { + if (left == EMPTY_LAYOUT) { + mBottomViewIdsSet = false; + } else { + mBottomViewIdMap.put(DragEdge.Left, left); + mBottomViewIdsSet = true; + } + } + if (mDragEdges.contains(DragEdge.Right)) { + if (right == EMPTY_LAYOUT) { + mBottomViewIdsSet = false; + } else { + mBottomViewIdMap.put(DragEdge.Right, right); + mBottomViewIdsSet = true; + } + } + if (mDragEdges.contains(DragEdge.Top)) { + if (top == EMPTY_LAYOUT) { + mBottomViewIdsSet = false; + } else { + mBottomViewIdMap.put(DragEdge.Top, top); + mBottomViewIdsSet = true; + } + } + if (mDragEdges.contains(DragEdge.Bottom)) { + if (bottom == EMPTY_LAYOUT) { + mBottomViewIdsSet = false; + } else { + mBottomViewIdMap.put(DragEdge.Bottom, bottom); + mBottomViewIdsSet = true; + } + } } public enum Status { - Middle , Open, Close + Middle, + Open, + Close } /** * get the open status. - * @return {@link com.daimajia.swipe.SwipeLayout.Status} - * Open , Close or Middle. + * + * @return {@link com.daimajia.swipe.SwipeLayout.Status} Open , Close or + * Middle. */ - public Status getOpenStatus(){ + public Status getOpenStatus() { int surfaceLeft = getSurfaceView().getLeft(); int surfaceTop = getSurfaceView().getTop(); - if(surfaceLeft == getPaddingLeft() && surfaceTop == getPaddingTop()) - return Status.Close; + if (surfaceLeft == getPaddingLeft() && surfaceTop == getPaddingTop()) return Status.Close; - if(surfaceLeft == (getPaddingLeft() - mDragDistance) || surfaceLeft == (getPaddingLeft() + mDragDistance) + if (surfaceLeft == (getPaddingLeft() - mDragDistance) || surfaceLeft == (getPaddingLeft() + mDragDistance) || surfaceTop == (getPaddingTop() - mDragDistance) || surfaceTop == (getPaddingTop() + mDragDistance)) return Status.Open; @@ -1044,29 +1222,34 @@ public class SwipeLayout extends FrameLayout { /** * Process the surface release event. + * * @param xvel * @param yvel */ - private void processSurfaceRelease(float xvel, float yvel){ - if(xvel == 0 && getOpenStatus() == Status.Middle) - close(); + private void processSurfaceRelease(float xvel, float yvel) { + if (xvel == 0 && getOpenStatus() == Status.Middle) close(); - if(mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right){ - if(xvel > 0){ - if(mDragEdge == DragEdge.Left) open(); + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left + || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) { + if (xvel > 0) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) + open(); else close(); } - if(xvel < 0){ - if(mDragEdge == DragEdge.Left) close(); + if (xvel < 0) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) + close(); else open(); } - }else{ - if(yvel > 0){ - if(mDragEdge == DragEdge.Top) open(); + } else { + if (yvel > 0) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) + open(); else close(); } - if(yvel < 0){ - if(mDragEdge == DragEdge.Top) close(); + if (yvel < 0) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) + close(); else open(); } } @@ -1074,53 +1257,60 @@ public class SwipeLayout extends FrameLayout { /** * process bottom (PullOut mode) hand release event. + * * @param xvel * @param yvel */ - private void processBottomPullOutRelease(float xvel, float yvel){ + private void processBottomPullOutRelease(float xvel, float yvel) { - if(xvel == 0 && getOpenStatus() == Status.Middle) - close(); + if (xvel == 0 && getOpenStatus() == Status.Middle) close(); - if(mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right){ - if(xvel > 0){ - if(mDragEdge == DragEdge.Left) open(); + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left + || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) { + if (xvel > 0) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) + open(); else close(); } - if(xvel < 0){ - if(mDragEdge == DragEdge.Left) close(); + if (xvel < 0) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) + close(); else open(); } - }else{ - if(yvel > 0) { - if (mDragEdge == DragEdge.Top) open(); + } else { + if (yvel > 0) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) + open(); else close(); } - if(yvel < 0){ - if(mDragEdge == DragEdge.Top) close(); - else open(); + if (yvel < 0) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) + close(); + else open(); } } } /** * process bottom (LayDown mode) hand release event. + * * @param xvel * @param yvel */ - private void processBottomLayDownMode(float xvel, float yvel){ + private void processBottomLayDownMode(float xvel, float yvel) { - if(xvel == 0 && getOpenStatus() == Status.Middle) - close(); + if (xvel == 0 && getOpenStatus() == Status.Middle) close(); int l = getPaddingLeft(), t = getPaddingTop(); - if(xvel < 0 && mDragEdge == DragEdge.Right) l -= mDragDistance; - if(xvel > 0 && mDragEdge == DragEdge.Left) l += mDragDistance; + if (xvel < 0 && mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + l -= mDragDistance; + if (xvel > 0 && mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) l += mDragDistance; - if(yvel > 0 && mDragEdge == DragEdge.Top) t += mDragDistance; - if(yvel < 0 && mDragEdge == DragEdge.Bottom) t -= mDragDistance; + if (yvel > 0 && mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) t += mDragDistance; + if (yvel < 0 && mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Bottom) + t -= mDragDistance; mDragHelper.smoothSlideViewTo(getSurfaceView(), l, t); invalidate(); @@ -1129,151 +1319,200 @@ public class SwipeLayout extends FrameLayout { /** * smoothly open surface. */ - public void open(){ + public void open() { open(true, true); } - public void open(boolean smooth){ + public void open(boolean smooth) { open(smooth, true); } - public void open(boolean smooth, boolean notify){ - ViewGroup surface = getSurfaceView(), bottom = getBottomView(); - int dx,dy; + public void open(boolean smooth, boolean notify) { + ViewGroup surface = getSurfaceView(), bottom = getBottomViews().get(mCurrentDirectionIndex); + int dx, dy; Rect rect = computeSurfaceLayoutArea(true); - if(smooth) { + if (smooth) { mDragHelper.smoothSlideViewTo(getSurfaceView(), rect.left, rect.top); - } - else{ + } else { dx = rect.left - surface.getLeft(); dy = rect.top - surface.getTop(); surface.layout(rect.left, rect.top, rect.right, rect.bottom); - if(getShowMode() == ShowMode.PullOut){ + if (getShowMode() == ShowMode.PullOut) { Rect bRect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, rect); bottom.layout(bRect.left, bRect.top, bRect.right, bRect.bottom); } - if(notify) { + if (notify) { dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom); dispatchSwipeEvent(rect.left, rect.top, dx, dy); - }else{ + } else { safeBottomView(); } } invalidate(); } + public void open(DragEdge edge) { + switch (edge) { + case Left: + mCurrentDirectionIndex = mLeftIndex; + case Right: + mCurrentDirectionIndex = mRightIndex; + case Top: + mCurrentDirectionIndex = mTopIndex; + case Bottom: + mCurrentDirectionIndex = mBottomIndex; + } + open(true, true); + } + + public void open(boolean smooth, DragEdge edge) { + switch (edge) { + case Left: + mCurrentDirectionIndex = mLeftIndex; + case Right: + mCurrentDirectionIndex = mRightIndex; + case Top: + mCurrentDirectionIndex = mTopIndex; + case Bottom: + mCurrentDirectionIndex = mBottomIndex; + } + open(smooth, true); + } + + public void open(boolean smooth, boolean notify, DragEdge edge) { + switch (edge) { + case Left: + mCurrentDirectionIndex = mLeftIndex; + case Right: + mCurrentDirectionIndex = mRightIndex; + case Top: + mCurrentDirectionIndex = mTopIndex; + case Bottom: + mCurrentDirectionIndex = mBottomIndex; + } + open(smooth, notify); + } + /** * smoothly close surface. */ - public void close(){ + public void close() { close(true, true); } - public void close(boolean smooth){ + public void close(boolean smooth) { close(smooth, true); } /** * close surface + * * @param smooth smoothly or not. * @param notify if notify all the listeners. */ - public void close(boolean smooth, boolean notify){ + public void close(boolean smooth, boolean notify) { ViewGroup surface = getSurfaceView(); int dx, dy; - if(smooth) + if (smooth) mDragHelper.smoothSlideViewTo(getSurfaceView(), getPaddingLeft(), getPaddingTop()); else { Rect rect = computeSurfaceLayoutArea(false); dx = rect.left - surface.getLeft(); dy = rect.top - surface.getTop(); surface.layout(rect.left, rect.top, rect.right, rect.bottom); - if(notify) { + if (notify) { dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom); dispatchSwipeEvent(rect.left, rect.top, dx, dy); - }else{ + } else { safeBottomView(); } } invalidate(); } - public void toggle(){ + public void toggle() { toggle(true); } - public void toggle(boolean smooth){ - if(getOpenStatus() == Status.Open) + public void toggle(boolean smooth) { + if (getOpenStatus() == Status.Open) close(smooth); - else if(getOpenStatus() == Status.Close) - open(smooth); + else if (getOpenStatus() == Status.Close) open(smooth); } /** * a helper function to compute the Rect area that surface will hold in. + * * @param open open status or close status. * @return */ - private Rect computeSurfaceLayoutArea(boolean open){ + private Rect computeSurfaceLayoutArea(boolean open) { int l = getPaddingLeft(), t = getPaddingTop(); - if(open){ - if(mDragEdge == DragEdge.Left) l = getPaddingLeft() + mDragDistance; - else if(mDragEdge == DragEdge.Right) l = getPaddingLeft() - mDragDistance; - else if(mDragEdge == DragEdge.Top) t = getPaddingTop() + mDragDistance; - else t = getPaddingTop() - mDragDistance; + if (open) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) + l = getPaddingLeft() + mDragDistance; + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + l = getPaddingLeft() - mDragDistance; + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) + t = getPaddingTop() + mDragDistance; + else t = getPaddingTop() - mDragDistance; } return new Rect(l, t, l + getMeasuredWidth(), t + getMeasuredHeight()); } - - private Rect computeBottomLayoutAreaViaSurface(ShowMode mode, Rect surfaceArea){ + private Rect computeBottomLayoutAreaViaSurface(ShowMode mode, Rect surfaceArea) { Rect rect = surfaceArea; int bl = rect.left, bt = rect.top, br = rect.right, bb = rect.bottom; - if(mode == ShowMode.PullOut){ - if (mDragEdge == DragEdge.Left) bl = rect.left - mDragDistance; - else if (mDragEdge == DragEdge.Right) bl = rect.right; - else if (mDragEdge == DragEdge.Top) bt = rect.top - mDragDistance; - else bt = rect.bottom; + if (mode == ShowMode.PullOut) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) + bl = rect.left - mDragDistance; + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + bl = rect.right; + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) + bt = rect.top - mDragDistance; + else bt = rect.bottom; - if (mDragEdge == DragEdge.Left || mDragEdge == DragEdge.Right) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) { bb = rect.bottom; - br = bl + getBottomView().getMeasuredWidth(); + br = bl + getBottomViews().get(mCurrentDirectionIndex).getMeasuredWidth(); } else { - bb = bt + getBottomView().getMeasuredHeight(); + bb = bt + getBottomViews().get(mCurrentDirectionIndex).getMeasuredHeight(); br = rect.right; } - }else if(mode == ShowMode.LayDown){ - if(mDragEdge == DragEdge.Left) br = bl + mDragDistance; - else if(mDragEdge == DragEdge.Right) bl = br - mDragDistance; - else if(mDragEdge == DragEdge.Top) bb = bt + mDragDistance; - else bt = bb - mDragDistance; + } else if (mode == ShowMode.LayDown) { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) + br = bl + mDragDistance; + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + bl = br - mDragDistance; + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) + bb = bt + mDragDistance; + else bt = bb - mDragDistance; } return new Rect(bl, bt, br, bb); - } - private Rect computeBottomLayDown(DragEdge dragEdge){ + private Rect computeBottomLayDown(DragEdge dragEdge) { int bl = getPaddingLeft(), bt = getPaddingTop(); int br, bb; - if(dragEdge == DragEdge.Right){ + if (dragEdge == DragEdge.Right) { bl = getMeasuredWidth() - mDragDistance; - }else if(dragEdge == DragEdge.Bottom){ + } else if (dragEdge == DragEdge.Bottom) { bt = getMeasuredHeight() - mDragDistance; } - if(dragEdge == DragEdge.Left || dragEdge == DragEdge.Right){ + if (dragEdge == DragEdge.Left || dragEdge == DragEdge.Right) { br = bl + mDragDistance; bb = bt + getMeasuredHeight(); - }else{ + } else { br = bl + getMeasuredWidth(); bb = bt + mDragDistance; } return new Rect(bl, bt, br, bb); } - public void setOnDoubleClickListener(DoubleClickListener doubleClickListener){ + public void setOnDoubleClickListener(DoubleClickListener doubleClickListener) { mDoubleClickListener = doubleClickListener; } @@ -1281,7 +1520,60 @@ public class SwipeLayout extends FrameLayout { public void onDoubleClick(SwipeLayout layout, boolean surface); } - private int dp2px(float dp){ + private int dp2px(float dp) { return (int) (dp * getContext().getResources().getDisplayMetrics().density + 0.5f); } + + public List getDragEdges() { + return mDragEdges; + } + + public void setDragEdges(List mDragEdges) { + this.mDragEdges = mDragEdges; + mCurrentDirectionIndex = 0; + populateIndexes(); + updateBottomViews(); + } + + public void setDragEdges(DragEdge... mDragEdges) { + this.mDragEdges = new ArrayList(); + for (DragEdge e : mDragEdges) { + this.mDragEdges.add(e); + } + mCurrentDirectionIndex = 0; + populateIndexes(); + updateBottomViews(); + } + + private void populateIndexes() { + mLeftIndex = this.mDragEdges.indexOf(DragEdge.Left); + mRightIndex = this.mDragEdges.indexOf(DragEdge.Right); + mTopIndex = this.mDragEdges.indexOf(DragEdge.Top); + mBottomIndex = this.mDragEdges.indexOf(DragEdge.Bottom); + } + + private float getCurrentOffset() { + if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) return mLeftEdgeSwipeOffset; + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + return mRightEdgeSwipeOffset; + else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) return mTopEdgeSwipeOffset; + else return mBottomEdgeSwipeOffset; + } + + private void updateBottomViews() { +// removeAllViews(); +// addView(getBottomViews().get(mCurrentDirectionIndex)); +// addView(getSurfaceView()); +// getBottomViews().get(mCurrentDirectionIndex).bringToFront(); +// getSurfaceView().bringToFront(); + if (mShowMode == ShowMode.PullOut) + layoutPullOut(); + else if (mShowMode == ShowMode.LayDown) layoutLayDown(); + + safeBottomView(); + + if (mOnLayoutListeners != null) for (int i = 0; i < mOnLayoutListeners.size(); i++) { + mOnLayoutListeners.get(i).onLayout(this); + } + } } diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index 9f69031..249b944 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -1,17 +1,19 @@ - - - - - + + + + + - - + + + + - - + + \ No newline at end of file