现在项目越来越多的应用了滑动删除的功能,Android本来遵循的是长按删除,IOS定制的是滑动删除,不可否认滑动删除确实在客户体验上要好一点,所以看了很多关于仿QQ滑动删除的例子,还是感觉代码家的Android Swipe Layout要好一点,至于为何好,下面我给大家实验一下大家就知道了

老规矩,贴上效果图,这样大家才能更近距离的了解

这是代码家的效果图,效果很多,支持listview,gridview,当然recylerview也是支持的。

但是呢,有个问题,代码家的效果很多,但是我们只是需要一个侧滑删除功能,如果按照代码家的库来集成,势必会增加代码量,以及不可控性,因为毕竟很多功能跟代码我们是不需要的,今天我教大家怎么仅仅只用一个SwipeLayout类就能来实现侧滑功能。

SwipeLayout类

package com.example.wangchang.testswipelayout;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.FrameLayout;import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;public class SwipeLayout extends FrameLayout {@Deprecatedpublic 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 static final DragEdge DefaultDragEdge = DragEdge.Right;private int mTouchSlop;private DragEdge mCurrentDragEdge = DefaultDragEdge;private ViewDragHelper mDragHelper;private int mDragDistance = 0;private LinkedHashMap<DragEdge, View> mDragEdges = new LinkedHashMap<>();private ShowMode mShowMode;private float[] mEdgeSwipesOffset = new float[4];private List<SwipeListener> mSwipeListeners = new ArrayList<>();private List<SwipeDenier> mSwipeDeniers = new ArrayList<>();private Map<View, ArrayList<OnRevealListener>> mRevealListeners = new HashMap<>();private Map<View, Boolean> mShowEntirely = new HashMap<>();private Map<View, Rect> mViewBoundCache = new HashMap<>();//save all children's bound, restore in onLayoutprivate DoubleClickListener mDoubleClickListener;private boolean mSwipeEnabled = true;private boolean[] mSwipesEnabled = new boolean[]{true, true, true, true};private boolean mClickToClose = false;private float mWillOpenPercentAfterOpen=0.75f;private float mWillOpenPercentAfterClose=0.25f;public enum DragEdge {Left,Top,Right,Bottom}public enum ShowMode {LayDown,PullOut}public SwipeLayout(Context context) {this(context, null);}public SwipeLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}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 dragEdgeChoices = a.getInt(R.styleable.SwipeLayout_drag_edge, DRAG_RIGHT);mEdgeSwipesOffset[DragEdge.Left.ordinal()] = a.getDimension(R.styleable.SwipeLayout_leftEdgeSwipeOffset, 0);mEdgeSwipesOffset[DragEdge.Right.ordinal()] = a.getDimension(R.styleable.SwipeLayout_rightEdgeSwipeOffset, 0);mEdgeSwipesOffset[DragEdge.Top.ordinal()] = a.getDimension(R.styleable.SwipeLayout_topEdgeSwipeOffset, 0);mEdgeSwipesOffset[DragEdge.Bottom.ordinal()] = a.getDimension(R.styleable.SwipeLayout_bottomEdgeSwipeOffset, 0);setClickToClose(a.getBoolean(R.styleable.SwipeLayout_clickToClose, mClickToClose));if ((dragEdgeChoices & DRAG_LEFT) == DRAG_LEFT) {mDragEdges.put(DragEdge.Left, null);}if ((dragEdgeChoices & DRAG_TOP) == DRAG_TOP) {mDragEdges.put(DragEdge.Top, null);}if ((dragEdgeChoices & DRAG_RIGHT) == DRAG_RIGHT) {mDragEdges.put(DragEdge.Right, null);}if ((dragEdgeChoices & DRAG_BOTTOM) == DRAG_BOTTOM) {mDragEdges.put(DragEdge.Bottom, null);}int ordinal = a.getInt(R.styleable.SwipeLayout_show_mode, ShowMode.PullOut.ordinal());mShowMode = ShowMode.values()[ordinal];a.recycle();}public interface SwipeListener {void onStartOpen(SwipeLayout layout);void onOpen(SwipeLayout layout);void onStartClose(SwipeLayout layout);void onClose(SwipeLayout layout);void onUpdate(SwipeLayout layout, int leftOffset, int topOffset);void onHandRelease(SwipeLayout layout, float xvel, float yvel);}public void addSwipeListener(SwipeListener l) {mSwipeListeners.add(l);}public void removeSwipeListener(SwipeListener l) {mSwipeListeners.remove(l);}public void removeAllSwipeListener() {mSwipeListeners.clear();}public 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*/boolean shouldDenySwipe(MotionEvent ev);}public void addSwipeDenier(SwipeDenier denier) {mSwipeDeniers.add(denier);}public void removeSwipeDenier(SwipeDenier denier) {mSwipeDeniers.remove(denier);}public void removeAllSwipeDeniers() {mSwipeDeniers.clear();}public interface OnRevealListener {void onReveal(View child, DragEdge edge, float fraction, int distance);}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)) {mShowEntirely.put(child, false);}if (mRevealListeners.get(child) == null)mRevealListeners.put(child, new ArrayList<OnRevealListener>());mRevealListeners.get(child).add(l);}public void addRevealListener(int[] childIds, OnRevealListener l) {for (int i : childIds)addRevealListener(i, l);}public void removeRevealListener(int childId, OnRevealListener l) {View child = findViewById(childId);if (child == null) return;mShowEntirely.remove(child);if (mRevealListeners.containsKey(child)) mRevealListeners.get(child).remove(l);}public void removeAllRevealListeners(int childId) {View child = findViewById(childId);if (child != null) {mRevealListeners.remove(child);mShowEntirely.remove(child);}}private ViewDragHelper.Callback mDragHelperCallback = new ViewDragHelper.Callback() {@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {if (child == getSurfaceView()) {switch (mCurrentDragEdge) {case Top:case Bottom:return getPaddingLeft();case Left:if (left < getPaddingLeft()) return getPaddingLeft();if (left > getPaddingLeft() + mDragDistance)return getPaddingLeft() + mDragDistance;break;case Right:if (left > getPaddingLeft()) return getPaddingLeft();if (left < getPaddingLeft() - mDragDistance)return getPaddingLeft() - mDragDistance;break;}} else if (getCurrentBottomView() == child) {switch (mCurrentDragEdge) {case Top:case Bottom:return getPaddingLeft();case Left:if (mShowMode == ShowMode.PullOut) {if (left > getPaddingLeft()) return getPaddingLeft();}break;case Right:if (mShowMode == ShowMode.PullOut) {if (left < getMeasuredWidth() - mDragDistance) {return getMeasuredWidth() - mDragDistance;}}break;}}return left;}@Overridepublic int clampViewPositionVertical(View child, int top, int dy) {if (child == getSurfaceView()) {switch (mCurrentDragEdge) {case Left:case Right:return getPaddingTop();case Top:if (top < getPaddingTop()) return getPaddingTop();if (top > getPaddingTop() + mDragDistance)return getPaddingTop() + mDragDistance;break;case Bottom:if (top < getPaddingTop() - mDragDistance) {return getPaddingTop() - mDragDistance;}if (top > getPaddingTop()) {return getPaddingTop();}}} else {View surfaceView = getSurfaceView();int surfaceViewTop = surfaceView == null ? 0 : surfaceView.getTop();switch (mCurrentDragEdge) {case Left:case Right:return getPaddingTop();case Top:if (mShowMode == ShowMode.PullOut) {if (top > getPaddingTop()) return getPaddingTop();} else {if (surfaceViewTop + dy < getPaddingTop())return getPaddingTop();if (surfaceViewTop + dy > getPaddingTop() + mDragDistance)return getPaddingTop() + mDragDistance;}break;case Bottom:if (mShowMode == ShowMode.PullOut) {if (top < getMeasuredHeight() - mDragDistance)return getMeasuredHeight() - mDragDistance;} else {if (surfaceViewTop + dy >= getPaddingTop())return getPaddingTop();if (surfaceViewTop + dy <= getPaddingTop() - mDragDistance)return getPaddingTop() - mDragDistance;}}}return top;}@Overridepublic boolean tryCaptureView(View child, int pointerId) {boolean result = child == getSurfaceView() || getBottomViews().contains(child);if (result) {isCloseBeforeDrag = getOpenStatus() == Status.Close;}return result;}@Overridepublic int getViewHorizontalDragRange(View child) {return mDragDistance;}@Overridepublic int getViewVerticalDragRange(View child) {return mDragDistance;}boolean isCloseBeforeDrag = true;@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {super.onViewReleased(releasedChild, xvel, yvel);processHandRelease(xvel, yvel, isCloseBeforeDrag);for (SwipeListener l : mSwipeListeners) {l.onHandRelease(SwipeLayout.this, xvel, yvel);}invalidate();}@Overridepublic void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {View surfaceView = getSurfaceView();if (surfaceView == null) return;View currentBottomView = getCurrentBottomView();int evLeft = surfaceView.getLeft(),evRight = surfaceView.getRight(),evTop = surfaceView.getTop(),evBottom = surfaceView.getBottom();if (changedView == surfaceView) {if (mShowMode == ShowMode.PullOut && currentBottomView != null) {if (mCurrentDragEdge == DragEdge.Left || mCurrentDragEdge == DragEdge.Right) {currentBottomView.offsetLeftAndRight(dx);} else {currentBottomView.offsetTopAndBottom(dy);}}} else if (getBottomViews().contains(changedView)) {if (mShowMode == ShowMode.PullOut) {surfaceView.offsetLeftAndRight(dx);surfaceView.offsetTopAndBottom(dy);} else {Rect rect = computeBottomLayDown(mCurrentDragEdge);if (currentBottomView != null) {currentBottomView.layout(rect.left, rect.top, rect.right, rect.bottom);}int newLeft = surfaceView.getLeft() + dx, newTop = surfaceView.getTop() + dy;if (mCurrentDragEdge == DragEdge.Left && newLeft < getPaddingLeft())newLeft = getPaddingLeft();else if (mCurrentDragEdge == DragEdge.Right && newLeft > getPaddingLeft())newLeft = getPaddingLeft();else if (mCurrentDragEdge == DragEdge.Top && newTop < getPaddingTop())newTop = getPaddingTop();else if (mCurrentDragEdge == DragEdge.Bottom && newTop > getPaddingTop())newTop = getPaddingTop();surfaceView.layout(newLeft, newTop, newLeft + getMeasuredWidth(), newTop + getMeasuredHeight());}}dispatchRevealEvent(evLeft, evTop, evRight, evBottom);dispatchSwipeEvent(evLeft, evTop, dx, dy);invalidate();captureChildrenBound();}};/*** save children's bounds, so they can restore the bound in {@link #onLayout(boolean, int, int, int, int)}*/private void captureChildrenBound(){View currentBottomView = getCurrentBottomView();if(getOpenStatus()==Status.Close){mViewBoundCache.remove(currentBottomView);return;}View[] views = new View[]{getSurfaceView(), currentBottomView};for (View child : views) {Rect rect = mViewBoundCache.get(child);if(rect==null){rect = new Rect();mViewBoundCache.put(child, rect);}rect.left = child.getLeft();rect.top = child.getTop();rect.right = child.getRight();rect.bottom = child.getBottom();}}/*** 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.*/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;}return r;}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) {case Right:if (surfaceRight > childLeft && surfaceRight <= childRight) {return true;}break;case Left:if (surfaceLeft < childRight && surfaceLeft >= childLeft) {return true;}break;case Top:if (surfaceTop >= childTop && surfaceTop < childBottom) {return true;}break;case Bottom:if (surfaceBottom > childTop && surfaceBottom <= childBottom) {return true;}break;}} else if (getShowMode() == ShowMode.PullOut) {switch (availableEdge) {case Right:if (childLeft <= getWidth() && childRight > getWidth()) return true;break;case Left:if (childRight >= getPaddingLeft() && childLeft < getPaddingLeft()) return true;break;case Top:if (childTop < getPaddingTop() && childBottom >= getPaddingTop()) return true;break;case Bottom:if (childTop < getHeight() && childTop >= getPaddingTop()) return true;break;}}return false;}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;r.left += t.getLeft();r.top += t.getTop();}r.right = r.left + child.getMeasuredWidth();r.bottom = r.top + child.getMeasuredHeight();return r;}private int mEventCounter = 0;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;}dispatchSwipeEvent(surfaceLeft, surfaceTop, open);}protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, boolean open) {safeBottomView();Status status = getOpenStatus();if (!mSwipeListeners.isEmpty()) {mEventCounter++;for (SwipeListener l : mSwipeListeners) {if (mEventCounter == 1) {if (open) {l.onStartOpen(this);} else {l.onStartClose(this);}}l.onUpdate(SwipeLayout.this, surfaceLeft - getPaddingLeft(), surfaceTop - getPaddingTop());}if (status == Status.Close) {for (SwipeListener l : mSwipeListeners) {l.onClose(SwipeLayout.this);}mEventCounter = 0;}if (status == Status.Open) {View currentBottomView = getCurrentBottomView();if (currentBottomView != null) {currentBottomView.setEnabled(true);}for (SwipeListener l : mSwipeListeners) {l.onOpen(SwipeLayout.this);}mEventCounter = 0;}}}/*** prevent bottom view get any touch event. Especially in LayDown mode.*/private void safeBottomView() {Status status = getOpenStatus();List<View> bottoms = getBottomViews();if (status == Status.Close) {for (View bottom : bottoms) {if (bottom != null && bottom.getVisibility() != INVISIBLE) {bottom.setVisibility(INVISIBLE);}}} else {View currentBottomView = getCurrentBottomView();if (currentBottomView != null && currentBottomView.getVisibility() != VISIBLE) {currentBottomView.setVisibility(VISIBLE);}}}protected void dispatchRevealEvent(final int surfaceLeft, final int surfaceTop, final int surfaceRight,final int surfaceBottom) {if (mRevealListeners.isEmpty()) return;for (Map.Entry<View, ArrayList<OnRevealListener>> entry : mRevealListeners.entrySet()) {View child = entry.getKey();Rect rect = getRelativePosition(child);if (isViewShowing(child, rect, mCurrentDragEdge, surfaceLeft, surfaceTop,surfaceRight, surfaceBottom)) {mShowEntirely.put(child, false);int distance = 0;float fraction = 0f;if (getShowMode() == ShowMode.LayDown) {switch (mCurrentDragEdge) {case Left:distance = rect.left - surfaceLeft;fraction = distance / (float) child.getWidth();break;case Right:distance = rect.right - surfaceRight;fraction = distance / (float) child.getWidth();break;case Top:distance = rect.top - surfaceTop;fraction = distance / (float) child.getHeight();break;case Bottom:distance = rect.bottom - surfaceBottom;fraction = distance / (float) child.getHeight();break;}} else if (getShowMode() == ShowMode.PullOut) {switch (mCurrentDragEdge) {case Left:distance = rect.right - getPaddingLeft();fraction = distance / (float) child.getWidth();break;case Right:distance = rect.left - getWidth();fraction = distance / (float) child.getWidth();break;case Top:distance = rect.bottom - getPaddingTop();fraction = distance / (float) child.getHeight();break;case Bottom:distance = rect.top - getHeight();fraction = distance / (float) child.getHeight();break;}}for (OnRevealListener l : entry.getValue()) {l.onReveal(child, mCurrentDragEdge, Math.abs(fraction), distance);if (Math.abs(fraction) == 1) {mShowEntirely.put(child, true);}}}if (isViewTotallyFirstShowed(child, rect, mCurrentDragEdge, surfaceLeft, surfaceTop,surfaceRight, surfaceBottom)) {mShowEntirely.put(child, true);for (OnRevealListener l : entry.getValue()) {if (mCurrentDragEdge == DragEdge.Left|| mCurrentDragEdge == DragEdge.Right)l.onReveal(child, mCurrentDragEdge, 1, child.getWidth());elsel.onReveal(child, mCurrentDragEdge, 1, child.getHeight());}}}}@Overridepublic void computeScroll() {super.computeScroll();if (mDragHelper.continueSettling(true)) {ViewCompat.postInvalidateOnAnimation(this);}}/*** {@link OnLayoutChangeListener} added in API 11. I need* to support it from API 8.*/public interface OnLayout {void onLayout(SwipeLayout v);}private List<OnLayout> mOnLayoutListeners;public void addOnLayoutListener(OnLayout l) {if (mOnLayoutListeners == null) mOnLayoutListeners = new ArrayList<OnLayout>();mOnLayoutListeners.add(l);}public void removeOnLayoutListener(OnLayout l) {if (mOnLayoutListeners != null) mOnLayoutListeners.remove(l);}public void clearDragEdge() {mDragEdges.clear();}public void setDrag(DragEdge dragEdge, int childId) {clearDragEdge();addDrag(dragEdge, childId);}public void setDrag(DragEdge dragEdge, View child) {clearDragEdge();addDrag(dragEdge, child);}public void addDrag(DragEdge dragEdge, int childId) {addDrag(dragEdge, findViewById(childId), null);}public void addDrag(DragEdge dragEdge, View child) {addDrag(dragEdge, child, null);}public void addDrag(DragEdge dragEdge, View child, ViewGroup.LayoutParams params) {if (child == null) return;if (params == null) {params = generateDefaultLayoutParams();}if (!checkLayoutParams(params)) {params = generateLayoutParams(params);}int gravity = -1;switch (dragEdge) {case Left:gravity = Gravity.LEFT;break;case Right:gravity = Gravity.RIGHT;break;case Top:gravity = Gravity.TOP;break;case Bottom:gravity = Gravity.BOTTOM;break;}if (params instanceof LayoutParams) {((LayoutParams) params).gravity = gravity;}addView(child, 0, params);}@Overridepublic void addView(View child, int index, ViewGroup.LayoutParams params) {if (child == null) return;int gravity = Gravity.NO_GRAVITY;try {gravity = (Integer) params.getClass().getField("gravity").get(params);} catch (Exception e) {e.printStackTrace();}if (gravity > 0) {gravity = GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(this));if ((gravity & Gravity.LEFT) == Gravity.LEFT) {mDragEdges.put(DragEdge.Left, child);}if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {mDragEdges.put(DragEdge.Right, child);}if ((gravity & Gravity.TOP) == Gravity.TOP) {mDragEdges.put(DragEdge.Top, child);}if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {mDragEdges.put(DragEdge.Bottom, child);}} else {for (Map.Entry<DragEdge, View> entry : mDragEdges.entrySet()) {if (entry.getValue() == null) {//means used the drag_edge attr, the no gravity child should be use setmDragEdges.put(entry.getKey(), child);break;}}}if (child.getParent() == this) {return;}super.addView(child, index, params);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {updateBottomViews();if (mOnLayoutListeners != null) for (int i = 0; i < mOnLayoutListeners.size(); i++) {mOnLayoutListeners.get(i).onLayout(this);}}void layoutPullOut() {View surfaceView = getSurfaceView();Rect surfaceRect = mViewBoundCache.get(surfaceView);if(surfaceRect == null) surfaceRect = computeSurfaceLayoutArea(false);if (surfaceView != null) {surfaceView.layout(surfaceRect.left, surfaceRect.top, surfaceRect.right, surfaceRect.bottom);bringChildToFront(surfaceView);}View currentBottomView = getCurrentBottomView();Rect bottomViewRect = mViewBoundCache.get(currentBottomView);if(bottomViewRect == null) bottomViewRect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, surfaceRect);if (currentBottomView != null) {currentBottomView.layout(bottomViewRect.left, bottomViewRect.top, bottomViewRect.right, bottomViewRect.bottom);}}void layoutLayDown() {View surfaceView = getSurfaceView();Rect surfaceRect = mViewBoundCache.get(surfaceView);if(surfaceRect == null) surfaceRect = computeSurfaceLayoutArea(false);if (surfaceView != null) {surfaceView.layout(surfaceRect.left, surfaceRect.top, surfaceRect.right, surfaceRect.bottom);bringChildToFront(surfaceView);}View currentBottomView = getCurrentBottomView();Rect bottomViewRect = mViewBoundCache.get(currentBottomView);if(bottomViewRect == null) bottomViewRect = computeBottomLayoutAreaViaSurface(ShowMode.LayDown, surfaceRect);if (currentBottomView != null) {currentBottomView.layout(bottomViewRect.left, bottomViewRect.top, bottomViewRect.right, bottomViewRect.bottom);}}private boolean mIsBeingDragged;private void checkCanDrag(MotionEvent ev) {if (mIsBeingDragged) return;if (getOpenStatus() == Status.Middle) {mIsBeingDragged = true;return;}Status status = getOpenStatus();float distanceX = ev.getRawX() - sX;float distanceY = ev.getRawY() - sY;float angle = Math.abs(distanceY / distanceX);angle = (float) Math.toDegrees(Math.atan(angle));if (getOpenStatus() == Status.Close) {DragEdge dragEdge;if (angle < 45) {if (distanceX > 0 && isLeftSwipeEnabled()) {dragEdge = DragEdge.Left;} else if (distanceX < 0 && isRightSwipeEnabled()) {dragEdge = DragEdge.Right;} else return;} else {if (distanceY > 0 && isTopSwipeEnabled()) {dragEdge = DragEdge.Top;} else if (distanceY < 0 && isBottomSwipeEnabled()) {dragEdge = DragEdge.Bottom;} else return;}setCurrentDragEdge(dragEdge);}boolean doNothing = false;if (mCurrentDragEdge == DragEdge.Right) {boolean suitable = (status == Status.Open && distanceX > mTouchSlop)|| (status == Status.Close && distanceX < -mTouchSlop);suitable = suitable || (status == Status.Middle);if (angle > 30 || !suitable) {doNothing = true;}}if (mCurrentDragEdge == DragEdge.Left) {boolean suitable = (status == Status.Open && distanceX < -mTouchSlop)|| (status == Status.Close && distanceX > mTouchSlop);suitable = suitable || status == Status.Middle;if (angle > 30 || !suitable) {doNothing = true;}}if (mCurrentDragEdge == DragEdge.Top) {boolean suitable = (status == Status.Open && distanceY < -mTouchSlop)|| (status == Status.Close && distanceY > mTouchSlop);suitable = suitable || status == Status.Middle;if (angle < 60 || !suitable) {doNothing = true;}}if (mCurrentDragEdge == DragEdge.Bottom) {boolean suitable = (status == Status.Open && distanceY > mTouchSlop)|| (status == Status.Close && distanceY < -mTouchSlop);suitable = suitable || status == Status.Middle;if (angle < 60 || !suitable) {doNothing = true;}}mIsBeingDragged = !doNothing;}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if (!isSwipeEnabled()) {return false;}if (mClickToClose && getOpenStatus() == Status.Open && isTouchOnSurface(ev)) {return true;}for (SwipeDenier denier : mSwipeDeniers) {if (denier != null && denier.shouldDenySwipe(ev)) {return false;}}switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:mDragHelper.processTouchEvent(ev);mIsBeingDragged = false;sX = ev.getRawX();sY = ev.getRawY();//if the swipe is in middle state(scrolling), should intercept the touchif (getOpenStatus() == Status.Middle) {mIsBeingDragged = true;}break;case MotionEvent.ACTION_MOVE:boolean beforeCheck = mIsBeingDragged;checkCanDrag(ev);if (mIsBeingDragged) {ViewParent parent = getParent();if (parent != null) {parent.requestDisallowInterceptTouchEvent(true);}}if (!beforeCheck && mIsBeingDragged) {//let children has one chance to catch the touch, and request the swipe not intercept//useful when swipeLayout wrap a swipeLayout or other gestural layoutreturn false;}break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:mIsBeingDragged = false;mDragHelper.processTouchEvent(ev);break;default://handle other action, such as ACTION_POINTER_DOWN/UPmDragHelper.processTouchEvent(ev);}return mIsBeingDragged;}private float sX = -1, sY = -1;@Overridepublic boolean onTouchEvent(MotionEvent event) {if (!isSwipeEnabled()) return super.onTouchEvent(event);int action = event.getActionMasked();gestureDetector.onTouchEvent(event);switch (action) {case MotionEvent.ACTION_DOWN:mDragHelper.processTouchEvent(event);sX = event.getRawX();sY = event.getRawY();case MotionEvent.ACTION_MOVE: {//the drag state and the direction are already judged at onInterceptTouchEventcheckCanDrag(event);if (mIsBeingDragged) {getParent().requestDisallowInterceptTouchEvent(true);mDragHelper.processTouchEvent(event);}break;}case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:mIsBeingDragged = false;mDragHelper.processTouchEvent(event);break;default://handle other action, such as ACTION_POINTER_DOWN/UPmDragHelper.processTouchEvent(event);}return super.onTouchEvent(event) || mIsBeingDragged || action == MotionEvent.ACTION_DOWN;}public boolean isClickToClose() {return mClickToClose;}public void setClickToClose(boolean mClickToClose) {this.mClickToClose = mClickToClose;}public void setSwipeEnabled(boolean enabled) {mSwipeEnabled = enabled;}public boolean isSwipeEnabled() {return mSwipeEnabled;}public boolean isLeftSwipeEnabled() {View bottomView = mDragEdges.get(DragEdge.Left);return bottomView != null && bottomView.getParent() == this&& bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Left.ordinal()];}public void setLeftSwipeEnabled(boolean leftSwipeEnabled) {this.mSwipesEnabled[DragEdge.Left.ordinal()] = leftSwipeEnabled;}public boolean isRightSwipeEnabled() {View bottomView = mDragEdges.get(DragEdge.Right);return bottomView != null && bottomView.getParent() == this&& bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Right.ordinal()];}public void setRightSwipeEnabled(boolean rightSwipeEnabled) {this.mSwipesEnabled[DragEdge.Right.ordinal()] = rightSwipeEnabled;}public boolean isTopSwipeEnabled() {View bottomView = mDragEdges.get(DragEdge.Top);return bottomView != null && bottomView.getParent() == this&& bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Top.ordinal()];}public void setTopSwipeEnabled(boolean topSwipeEnabled) {this.mSwipesEnabled[DragEdge.Top.ordinal()] = topSwipeEnabled;}public boolean isBottomSwipeEnabled() {View bottomView = mDragEdges.get(DragEdge.Bottom);return bottomView != null && bottomView.getParent() == this&& bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Bottom.ordinal()];}public void setBottomSwipeEnabled(boolean bottomSwipeEnabled) {this.mSwipesEnabled[DragEdge.Bottom.ordinal()] = bottomSwipeEnabled;}/**** Returns the percentage of revealing at which the view below should the view finish opening* if it was already open before dragging* @returns  The percentage of view revealed to trigger, default value is 0.25*/public float getWillOpenPercentAfterOpen() {return mWillOpenPercentAfterOpen;}/**** Allows to stablish at what percentage of revealing the view below should the view finish opening* if it was already open before dragging* @param willOpenPercentAfterOpen The percentage of view revealed to trigger, default value is 0.25*/public void setWillOpenPercentAfterOpen(float willOpenPercentAfterOpen) {this.mWillOpenPercentAfterOpen = willOpenPercentAfterOpen;}/**** Returns the percentage of revealing at which the view below should the view finish opening* if it was already closed before dragging* @returns  The percentage of view revealed to trigger, default value is 0.25*/public float getWillOpenPercentAfterClose() {return mWillOpenPercentAfterClose;}/**** Allows to stablish at what percentage of revealing the view below should the view finish opening* if it was already closed before dragging* @param willOpenPercentAfterClose The percentage of view revealed to trigger, default value is 0.75*/public void setWillOpenPercentAfterClose(float willOpenPercentAfterClose) {this.mWillOpenPercentAfterClose = willOpenPercentAfterClose;}private boolean insideAdapterView() {return getAdapterView() != null;}private AdapterView getAdapterView() {ViewParent t = getParent();if (t instanceof AdapterView) {return (AdapterView) t;}return null;}private void performAdapterViewItemClick() {if (getOpenStatus() != Status.Close) return;ViewParent t = getParent();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));}}}private boolean performAdapterViewItemLongClick() {if (getOpenStatus() != Status.Close) return false;ViewParent t = getParent();if (t instanceof AdapterView) {AdapterView view = (AdapterView) t;int p = view.getPositionForView(SwipeLayout.this);if (p == AdapterView.INVALID_POSITION) return false;long vId = view.getItemIdAtPosition(p);boolean handled = false;try {Method m = AbsListView.class.getDeclaredMethod("performLongPress", View.class, int.class, long.class);m.setAccessible(true);handled = (boolean) m.invoke(view, SwipeLayout.this, p, vId);} catch (Exception e) {e.printStackTrace();if (view.getOnItemLongClickListener() != null) {handled = view.getOnItemLongClickListener().onItemLongClick(view, SwipeLayout.this, p, vId);}if (handled) {view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);}}return handled;}return false;}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();if (insideAdapterView()) {if (clickListener == null) {setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {performAdapterViewItemClick();}});}if (longClickListener == null) {setOnLongClickListener(new OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {performAdapterViewItemLongClick();return true;}});}}}OnClickListener clickListener;@Overridepublic void setOnClickListener(OnClickListener l) {super.setOnClickListener(l);clickListener = l;}OnLongClickListener longClickListener;@Overridepublic void setOnLongClickListener(OnLongClickListener l) {super.setOnLongClickListener(l);longClickListener = l;}private Rect hitSurfaceRect;private boolean isTouchOnSurface(MotionEvent ev) {View surfaceView = getSurfaceView();if (surfaceView == null) {return false;}if (hitSurfaceRect == null) {hitSurfaceRect = new Rect();}surfaceView.getHitRect(hitSurfaceRect);return hitSurfaceRect.contains((int) ev.getX(), (int) ev.getY());}private GestureDetector gestureDetector = new GestureDetector(getContext(), new SwipeDetector());class SwipeDetector extends GestureDetector.SimpleOnGestureListener {@Overridepublic boolean onSingleTapUp(MotionEvent e) {if (mClickToClose && isTouchOnSurface(e)) {close();}return super.onSingleTapUp(e);}@Overridepublic boolean onDoubleTap(MotionEvent e) {if (mDoubleClickListener != null) {View target;View bottom = getCurrentBottomView();View surface = getSurfaceView();if (bottom != null && e.getX() > bottom.getLeft() && e.getX() < bottom.getRight()&& e.getY() > bottom.getTop() && e.getY() < bottom.getBottom()) {target = bottom;} else {target = surface;}mDoubleClickListener.onDoubleClick(SwipeLayout.this, target == surface);}return true;}}/*** set the drag distance, it will force set the bottom view's width or* height via this value.** @param max max distance in dp unit*/public void setDragDistance(int max) {if (max < 0) max = 0;mDragDistance = dp2px(max);requestLayout();}public void setShowMode(ShowMode mode) {mShowMode = mode;requestLayout();}public DragEdge getDragEdge() {return mCurrentDragEdge;}public int getDragDistance() {return mDragDistance;}public ShowMode getShowMode() {return mShowMode;}/*** return null if there is no surface view(no children)*/public View getSurfaceView() {if (getChildCount() == 0) return null;return getChildAt(getChildCount() - 1);}/*** return null if there is no bottom view*/@Nullablepublic View getCurrentBottomView() {List<View> bottoms = getBottomViews();if (mCurrentDragEdge.ordinal() < bottoms.size()) {return bottoms.get(mCurrentDragEdge.ordinal());}return null;}/*** @return all bottomViews: left, top, right, bottom (may null if the edge is not set)*/public List<View> getBottomViews() {ArrayList<View> bottoms = new ArrayList<View>();for (DragEdge dragEdge : DragEdge.values()) {bottoms.add(mDragEdges.get(dragEdge));}return bottoms;}public enum Status {Middle,Open,Close}public Status getOpenStatus() {View surfaceView = getSurfaceView();if (surfaceView == null) {return Status.Close;}int surfaceLeft = surfaceView.getLeft();int surfaceTop = surfaceView.getTop();if (surfaceLeft == getPaddingLeft() && surfaceTop == getPaddingTop()) return Status.Close;if (surfaceLeft == (getPaddingLeft() - mDragDistance) || surfaceLeft == (getPaddingLeft() + mDragDistance)|| surfaceTop == (getPaddingTop() - mDragDistance) || surfaceTop == (getPaddingTop() + mDragDistance))return Status.Open;return Status.Middle;}/*** Process the surface release event.** @param xvel                 xVelocity* @param yvel                 yVelocity* @param isCloseBeforeDragged the open state before drag*/protected void processHandRelease(float xvel, float yvel, boolean isCloseBeforeDragged) {float minVelocity = mDragHelper.getMinVelocity();View surfaceView = getSurfaceView();DragEdge currentDragEdge = mCurrentDragEdge;if (currentDragEdge == null || surfaceView == null) {return;}float willOpenPercent = (isCloseBeforeDragged ? mWillOpenPercentAfterClose : mWillOpenPercentAfterOpen);if (currentDragEdge == DragEdge.Left) {if (xvel > minVelocity) open();else if (xvel < -minVelocity) close();else {float openPercent = 1f * getSurfaceView().getLeft() / mDragDistance;if (openPercent > willOpenPercent) open();else close();}} else if (currentDragEdge == DragEdge.Right) {if (xvel > minVelocity) close();else if (xvel < -minVelocity) open();else {float openPercent = 1f * (-getSurfaceView().getLeft()) / mDragDistance;if (openPercent > willOpenPercent) open();else close();}} else if (currentDragEdge == DragEdge.Top) {if (yvel > minVelocity) open();else if (yvel < -minVelocity) close();else {float openPercent = 1f * getSurfaceView().getTop() / mDragDistance;if (openPercent > willOpenPercent) open();else close();}} else if (currentDragEdge == DragEdge.Bottom) {if (yvel > minVelocity) close();else if (yvel < -minVelocity) open();else {float openPercent = 1f * (-getSurfaceView().getTop()) / mDragDistance;if (openPercent > willOpenPercent) open();else close();}}}/*** smoothly open surface.*/public void open() {open(true, true);}public void open(boolean smooth) {open(smooth, true);}public void open(boolean smooth, boolean notify) {View surface = getSurfaceView(), bottom = getCurrentBottomView();if (surface == null) {return;}int dx, dy;Rect rect = computeSurfaceLayoutArea(true);if (smooth) {mDragHelper.smoothSlideViewTo(surface, rect.left, rect.top);} 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) {Rect bRect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, rect);if (bottom != null) {bottom.layout(bRect.left, bRect.top, bRect.right, bRect.bottom);}}if (notify) {dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom);dispatchSwipeEvent(rect.left, rect.top, dx, dy);} else {safeBottomView();}}invalidate();}public void open(DragEdge edge) {setCurrentDragEdge(edge);open(true, true);}public void open(boolean smooth, DragEdge edge) {setCurrentDragEdge(edge);open(smooth, true);}public void open(boolean smooth, boolean notify, DragEdge edge) {setCurrentDragEdge(edge);open(smooth, notify);}/*** smoothly close surface.*/public void close() {close(true, true);}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) {View surface = getSurfaceView();if (surface == null) {return;}int dx, dy;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) {dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom);dispatchSwipeEvent(rect.left, rect.top, dx, dy);} else {safeBottomView();}}invalidate();}public void toggle() {toggle(true);}public void toggle(boolean smooth) {if (getOpenStatus() == Status.Open)close(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.*/private Rect computeSurfaceLayoutArea(boolean open) {int l = getPaddingLeft(), t = getPaddingTop();if (open) {if (mCurrentDragEdge == DragEdge.Left)l = getPaddingLeft() + mDragDistance;else if (mCurrentDragEdge == DragEdge.Right)l = getPaddingLeft() - mDragDistance;else if (mCurrentDragEdge == 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) {Rect rect = surfaceArea;View bottomView = getCurrentBottomView();int bl = rect.left, bt = rect.top, br = rect.right, bb = rect.bottom;if (mode == ShowMode.PullOut) {if (mCurrentDragEdge == DragEdge.Left)bl = rect.left - mDragDistance;else if (mCurrentDragEdge == DragEdge.Right)bl = rect.right;else if (mCurrentDragEdge == DragEdge.Top)bt = rect.top - mDragDistance;else bt = rect.bottom;if (mCurrentDragEdge == DragEdge.Left || mCurrentDragEdge == DragEdge.Right) {bb = rect.bottom;br = bl + (bottomView == null ? 0 : bottomView.getMeasuredWidth());} else {bb = bt + (bottomView == null ? 0 : bottomView.getMeasuredHeight());br = rect.right;}} else if (mode == ShowMode.LayDown) {if (mCurrentDragEdge == DragEdge.Left)br = bl + mDragDistance;else if (mCurrentDragEdge == DragEdge.Right)bl = br - mDragDistance;else if (mCurrentDragEdge == DragEdge.Top)bb = bt + mDragDistance;else bt = bb - mDragDistance;}return new Rect(bl, bt, br, bb);}private Rect computeBottomLayDown(DragEdge dragEdge) {int bl = getPaddingLeft(), bt = getPaddingTop();int br, bb;if (dragEdge == DragEdge.Right) {bl = getMeasuredWidth() - mDragDistance;} else if (dragEdge == DragEdge.Bottom) {bt = getMeasuredHeight() - mDragDistance;}if (dragEdge == DragEdge.Left || dragEdge == DragEdge.Right) {br = bl + mDragDistance;bb = bt + getMeasuredHeight();} else {br = bl + getMeasuredWidth();bb = bt + mDragDistance;}return new Rect(bl, bt, br, bb);}public void setOnDoubleClickListener(DoubleClickListener doubleClickListener) {mDoubleClickListener = doubleClickListener;}public interface DoubleClickListener {void onDoubleClick(SwipeLayout layout, boolean surface);}private int dp2px(float dp) {return (int) (dp * getContext().getResources().getDisplayMetrics().density + 0.5f);}/*** Deprecated, use {@link #setDrag(DragEdge, View)}*/@Deprecatedpublic void setDragEdge(DragEdge dragEdge) {clearDragEdge();if (getChildCount() >= 2) {mDragEdges.put(dragEdge, getChildAt(getChildCount() - 2));}setCurrentDragEdge(dragEdge);}public void onViewRemoved(View child) {for (Map.Entry<DragEdge, View> entry : new HashMap<DragEdge, View>(mDragEdges).entrySet()) {if (entry.getValue() == child) {mDragEdges.remove(entry.getKey());}}}public Map<DragEdge, View> getDragEdgeMap() {return mDragEdges;}/*** Deprecated, use {@link #getDragEdgeMap()}*/@Deprecatedpublic List<DragEdge> getDragEdges() {return new ArrayList<DragEdge>(mDragEdges.keySet());}/*** Deprecated, use {@link #setDrag(DragEdge, View)}*/@Deprecatedpublic void setDragEdges(List<DragEdge> dragEdges) {clearDragEdge();for (int i = 0, size = Math.min(dragEdges.size(), getChildCount() - 1); i < size; i++) {DragEdge dragEdge = dragEdges.get(i);mDragEdges.put(dragEdge, getChildAt(i));}if (dragEdges.size() == 0 || dragEdges.contains(DefaultDragEdge)) {setCurrentDragEdge(DefaultDragEdge);} else {setCurrentDragEdge(dragEdges.get(0));}}/*** Deprecated, use {@link #addDrag(DragEdge, View)}*/@Deprecatedpublic void setDragEdges(DragEdge... mDragEdges) {clearDragEdge();setDragEdges(Arrays.asList(mDragEdges));}/*** Deprecated, use {@link #addDrag(DragEdge, View)}* 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)*/@Deprecatedpublic void setBottomViewIds(int leftId, int rightId, int topId, int bottomId) {addDrag(DragEdge.Left, findViewById(leftId));addDrag(DragEdge.Right, findViewById(rightId));addDrag(DragEdge.Top, findViewById(topId));addDrag(DragEdge.Bottom, findViewById(bottomId));}private float getCurrentOffset() {if (mCurrentDragEdge == null) return 0;return mEdgeSwipesOffset[mCurrentDragEdge.ordinal()];}private void setCurrentDragEdge(DragEdge dragEdge) {mCurrentDragEdge = dragEdge;updateBottomViews();}private void updateBottomViews() {View currentBottomView = getCurrentBottomView();if (currentBottomView != null) {if (mCurrentDragEdge == DragEdge.Left || mCurrentDragEdge == DragEdge.Right) {mDragDistance = currentBottomView.getMeasuredWidth() - dp2px(getCurrentOffset());} else {mDragDistance = currentBottomView.getMeasuredHeight() - dp2px(getCurrentOffset());}}if (mShowMode == ShowMode.PullOut) {layoutPullOut();} else if (mShowMode == ShowMode.LayDown) {layoutLayDown();}safeBottomView();}
}

在values里面创建attrs文件

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="SwitchButton"><attr name="frameDrawable" format="reference|color" /><attr name="stateDrawable" format="reference|color" /><attr name="stateMaskDrawable" format="reference|color" /><attr name="sliderDrawable" format="reference|color" /><attr name="withTextInterval" format="dimension" /></declare-styleable><declare-styleable name="CircleImageView"><attr name="border_width" format="dimension" /><attr name="border_color" format="color" /><attr name="border_overlay" format="boolean" /></declare-styleable><declare-styleable name="SwipeLayout"><attr name="drag_edge"><flag name="left" value="1" /><flag name="right" value="2" /><flag name="top" value="4" /><flag name="bottom" value="8" /></attr><attr name="leftEdgeSwipeOffset" format="dimension" /><attr name="rightEdgeSwipeOffset" format="dimension" /><attr name="topEdgeSwipeOffset" format="dimension" /><attr name="bottomEdgeSwipeOffset" format="dimension" /><attr name="show_mode" format="enum"><enum name="lay_down" value="0" /><enum name="pull_out" value="1" /></attr><attr name="clickToClose" format="boolean" /></declare-styleable>
</resources>

只仅仅需要在布局中设置引用SwipeLayout即可,即可实现侧滑效果啦,这里设置了三个滑动例子

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><com.example.wangchang.testswipelayout.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="80dp"app:clickToClose="true"><LinearLayout
            android:id="@+id/bottom_wrapper"android:layout_width="160dp"android:layout_height="match_parent"android:background="#66ddff00"android:tag="Bottom1"android:weightSum="1"><TextView
                android:id="@+id/archive"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_weight="0.5"android:background="@drawable/red"android:clickable="true"android:gravity="center"android:text="Archive"android:textColor="#fff" /><TextView
                android:id="@+id/delete"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_weight="0.5"android:background="#C7C7CC"android:gravity="center"android:text="Delete" /></LinearLayout><LinearLayout
            android:id="@+id/bottom_wrapper_2"android:layout_width="wrap_content"android:layout_height="match_parent"android:tag="Bottom4"><ImageView
                android:id="@+id/magnifier2"android:layout_width="70dp"android:layout_height="match_parent"android:background="#f7e79c"android:paddingLeft="25dp"android:paddingRight="25dp"android:src="@drawable/magnifier" /><ImageView
                android:id="@+id/star2"android:layout_width="70dp"android:layout_height="match_parent"android:background="#4cd964"android:paddingLeft="25dp"android:paddingRight="25dp"android:src="@drawable/star" /><ImageView
                android:id="@+id/trash2"android:layout_width="70dp"android:layout_height="match_parent"android:background="@drawable/red"android:paddingLeft="25dp"android:paddingRight="25dp"android:src="@drawable/trash" /></LinearLayout><LinearLayout
            android:id="@+id/starbott"android:layout_width="match_parent"android:layout_height="match_parent"android:tag="Bottom3"><RelativeLayout
                android:id="@+id/bottom_wrapper_child1"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/dark_gray"android:clickable="true"><ImageView
                    android:id="@+id/stars"android:layout_width="20dp"android:layout_height="20dp"android:layout_alignParentTop="true"android:layout_centerHorizontal="true"android:src="@drawable/star" /></RelativeLayout></LinearLayout><TextView
            android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/white"android:padding="10dp"android:tag="Hover"android:text="要有最樸素的生活和最遙遠的夢想,即使明天天寒地凍,山高水遠,路遠馬亡。" /></com.example.wangchang.testswipelayout.SwipeLayout><com.example.wangchang.testswipelayout.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="80dp"><LinearLayout
            android:layout_width="wrap_content"android:layout_height="match_parent"android:tag="Bottom2"><ImageView
                android:id="@+id/magnifier"android:layout_width="70dp"android:layout_height="match_parent"android:background="#f7e79c"android:paddingLeft="25dp"android:paddingRight="25dp"android:src="@drawable/magnifier" /><ImageView
                android:id="@+id/star"android:layout_width="70dp"android:layout_height="match_parent"android:background="#4cd964"android:paddingLeft="25dp"android:paddingRight="25dp"android:src="@drawable/star" /><ImageView
                android:id="@+id/trash"android:layout_width="70dp"android:layout_height="match_parent"android:background="@drawable/red"android:paddingLeft="25dp"android:paddingRight="25dp"android:src="@drawable/trash" /></LinearLayout><LinearLayout
            android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/white"android:orientation="vertical"android:padding="10dp"><TextView
                android:layout_width="wrap_content"android:layout_height="wrap_content"android:tag="Hover"android:text="理解(りかい)されるということは、一種(いっしゅ)の贅沢(ぜいたく)である。" /><Button
                android:id="@+id/click"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Click"android:visibility="invisible" /></LinearLayout></com.example.wangchang.testswipelayout.SwipeLayout><com.example.wangchang.testswipelayout.SwipeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="80dp"><LinearLayout
            android:tag="Bottom3"android:layout_width="match_parent"android:layout_height="match_parent"><RelativeLayout
                android:id="@+id/bottom_wrapper_child2"android:background="#BDBEC2"android:layout_width="match_parent"android:layout_height="match_parent"><ImageView
                    android:id="@+id/star3"android:layout_alignParentTop="true"android:layout_centerHorizontal="true"android:src="@drawable/star"android:layout_width="20dp"android:layout_height="20dp" /></RelativeLayout></LinearLayout><TextView
            android:padding="10dp"android:background="#ffffff"android:tag="Hover"android:text="None is of freedom or of life deserving unless he daily conquers it anew. "android:layout_width="match_parent"android:layout_height="match_parent" /></com.example.wangchang.testswipelayout.SwipeLayout><com.example.wangchang.testswipelayout.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent" android:layout_height="80dp"><LinearLayout
            android:layout_width="80dp"android:layout_height="match_parent"><ImageView
                android:id="@+id/trashss"android:src="@drawable/trash"android:layout_width="match_parent"android:background="#FF3B30"android:paddingLeft="25dp"android:paddingRight="25dp"android:layout_height="match_parent" /></LinearLayout><LinearLayout
            android:padding="10dp"android:background="#ffffff"android:layout_width="match_parent"android:layout_height="match_parent"><TextView
                android:text="EditText"android:layout_width="wrap_content"android:layout_height="wrap_content" /><EditText
                android:layout_gravity="right"android:layout_width="200dp"android:layout_height="wrap_content" /></LinearLayout></com.example.wangchang.testswipelayout.SwipeLayout><com.example.wangchang.testswipelayout.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent" android:layout_height="80dp"><LinearLayout
            android:layout_width="80dp"android:layout_height="match_parent"><ImageView
                android:id="@+id/trashsss"android:src="@drawable/trash"android:layout_width="match_parent"android:background="#FF3B30"android:paddingLeft="25dp"android:paddingRight="25dp"android:layout_height="match_parent" /></LinearLayout><LinearLayout
            android:padding="10dp"android:background="#ffffff"android:layout_width="match_parent"android:layout_height="match_parent"><TextView
                android:text="SeekBar"android:layout_width="wrap_content"android:layout_height="wrap_content" />![这里写图片描述](https://img-blog.csdn.net/20160324012557953)<SeekBar
                android:layout_gravity="center"android:layout_width="200dp"android:layout_height="wrap_content" /></LinearLayout></com.example.wangchang.testswipelayout.SwipeLayout>
</LinearLayout>

这样就结束了,当然资源文件大家随便替换就行了,这里就不上传了,在活动中不需要任何代码设置,哈哈,简单吧,从此妈妈再也不用担心我做滑动功能啦,希望对大家有所帮助。贴上实现效果图。

下面是我的实现结果,大家可以优化一下,就这样啦,还是很简单的。

实在觉得有困难的,please留言@我,我会把代码发给各位。嗯今天的学习就到此吧,晚安吧

Android学习之仿QQ侧滑功能的实现相关推荐

  1. Android学习之仿QQ側滑功能的实现

    如今项目越来越多的应用了滑动删除的功能,Android本来遵循的是长按删除,IOS定制的是滑动删除,不可否认滑动删除确实在客户体验上要好一点,所以看了非常多关于仿QQ滑动删除的样例,还是感觉代码家的A ...

  2. Swing学习----------实现仿QQ注册功能

    在上一次的博客中实现了一个仿QQ的登录界面,现在将实现一个注册QQ账号的功能,在本文中将制作一个QQ注册的页面,然后通过一些swing中的组件来获取用户的信息,最后通过点击注册按钮将注册信息保存到My ...

  3. Android学习之仿QQ讨论组和微信群聊头像

    GroupView 一.前言 最近做东西的时候要用到qq讨论组群头像的功能,网上找了下,发现别人的并不是特别的好用,效果并不是和qq这个很像,或者是使用gridView,(NineGridImageV ...

  4. 名片夹android布局代码,Android自定义布局实现仿qq侧滑部分代码

    自定义布局实现仿qq侧滑部分Android代码,供大家参考,具体内容如下 实现说明: 通过自定义布局实现: SlidingLayout继承于 HorizontalScrollView /** * Cr ...

  5. android仿qq布局,Android自定义布局实现仿qq侧滑部分代码

    自定义布局实现仿qq侧滑部分android代码,供大家参考,具体内容如下 实现说明: 通过自定义布局实现: slidinglayout继承于 horizontalscrollview /** * cr ...

  6. Android 仿QQ侧滑菜单

    前言 集成方式 兼容超强的BaseRecyclerViewAdapterHelper 方法及属性介绍 THANKS 侧滑的雏形 测绘布局 onLayout onMeasure MotionEvent事 ...

  7. Android仿QQ侧滑菜单

    先上效果图: GIF图有点模糊,源码已上传Github:Android仿QQ侧滑菜单 ####整体思路: 自定义ItemView的根布局(SwipeMenuLayout extends LinearL ...

  8. Android高仿QQ侧滑菜单

    文章目录 效果图 整体思路 实现过程 先分析SwipeMenuLayout 再分析下SwipeRecycleView 踩过的坑 后记 效果图 GIF图有点模糊,源码已上传Github:Android仿 ...

  9. Android开发之仿QQ表情实现(上)

    大家晚上好,,小鹿又来了..最近小鹿特别忙,忙到没时间发表博客了(注:以下内容过于简单请大家不要喷,仅提供初学者学习) 今天发表两篇文章,分别是讲解模拟QQ表情的实现,先给大家看效果图,,,, 开始了 ...

最新文章

  1. IIS负载均衡-Application Request Route详解第一篇: ARR介绍
  2. win10开始不显示python_Win 10 使用 Python遇到奇怪的问题
  3. 《数据结构与算法Python语言描述》习题第二章第二题(python版)
  4. Git push “fatal: Authentication failed ”
  5. 淘宝快捷通道——百汇家园
  6. c语言大作业_2018 C语言大作业--21_Ekko制作教程
  7. 为什么总是有人说Java啰嗦,却没人说C++啰嗦?
  8. 向量表示 运动抛物线_初学讲义之高中物理(四)常见运动类型
  9. 43 FI配置-财务会计-固定资产-一般评估-定义折旧范围
  10. html5视频播放自定义视频播放暂停,解决暂停按钮在视频画面中的问题
  11. php中案值传递和安引用传递,PHP里的值传递与引用传递
  12. 两个类相互包含对方成员的问题(2)
  13. 在ppt中怎么加入倒计时 里面怎么加入倒计时【方法】
  14. linux添加jdk权限不够
  15. python selenium span_如何使用selenium从span获取文本
  16. 关于oracle的锁的级别以及介绍
  17. php中的where用法,ThinkPHP中where()使用方法详解
  18. c# WPF 动态设置button的IsEnabled属性
  19. DSPE-PEG-DBCO 磷脂-聚乙二醇-二苯并环辛炔 一种线性杂双官能聚乙二醇化试剂
  20. Minecraft我的世界云服务器搭建教程(小白看过来)

热门文章

  1. 页面静态化--Nginx
  2. python 进程间同步_python之路29 -- 多进程与进程同步(进程锁、信号量、事件)与进程间的通讯(队列和管道、生产者与消费者模型)与进程池...
  3. (转载)图像语义分割
  4. 1163:阿克曼(Ackmann)函数
  5. JAVA学习笔记-----Thirteen(正则表达式,Math)
  6. 苹果终于要认真发力智能家居了!挖来前微软副总裁掌舵其人工智能部门!
  7. 4核处理器_Intel加速淘汰14nm处理器 4核6W奔腾/赛扬退役
  8. mysql - sql语句 之 mysql错误代码大合(转载)
  9. 到家服务公司php源码,微信小程序-仿五洲到家商城源码
  10. linux 编辑如何退出命令模式,linux退出编辑模式的命令