import android.content.Context; import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.RelativeLayout; /** * Created by alanchen on 15/7/29. */ public class SwipeBackRelativelayout extends RelativeLayout { public static final String TAG = SwipeBackRelativelayout.class.getSimpleName(); private ViewDragHelper mDragHelper; /*通过九个数字来表示空白格的位置 * 1 2 3 * 4 5 6 * 7 8 9*/ private int blank; private int maxLeft; private int maxTop; public SwipeBackRelativelayout(Context context) { this(context, null); } public SwipeBackRelativelayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { //初始化空白格的位置 blank = 9; //ViewDragHelper是很好用的拖拽用设计,建议大家学习 mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelperCallback()); //这句没用上 mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { mDragHelper.processTouchEvent(event); return true; } @Override protected void onFinishInflate() { super.onFinishInflate(); /*会有8个带图片的控件在本ViewGroup里,不能多不能少, 此处打上初始化标记,标记的意义参照变量blank*/ for (int i = 0; i < 8; i++) { getChildAt(i).setTag(i + 1); } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); //获取max maxLeft = getChildAt(0).getWidth() * 2; maxTop = getChildAt(0).getHeight() * 2; } //Notice view 刚初始化的时候就会被调用一次 @Override public void computeScroll() { super.computeScroll(); if (mDragHelper.continueSettling(true)) { invalidate(); } } class ViewDragHelperCallback extends ViewDragHelper.Callback { //当前拖拽的view还在正位时候的位置 public int curViewTop; public int curViewLeft; //当前拖拽的view的tag private int curDragView; @Override public boolean tryCaptureView(View child, int pointerId) { //如果返回false,那么这个child是完全不会动的 Log.v(TAG,"tryCaptureView"); if (curDragView != 0) return (int) child.getTag() == curDragView; else { curDragView = (int) child.getTag(); curViewLeft = child.getLeft(); curViewTop = child.getTop(); return true; } } @Override public void onEdgeTouched(int edgeFlags, int pointerId) { //好像跟setEdgeTrackingEnabled有关系,没用上 Log.v(TAG,"onEdgeTouched"); } @Override public int getViewHorizontalDragRange(View child) { return 1; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { // Log.d(TAG, "clampViewPositionHorizontal() called with dx = [" + dx + "]"); int c = (int) child.getTag(); if (blank % 3 == 0) { if (c + 1 == blank) { return mycalc(maxLeft, maxLeft / 2, left); } } else if (blank % 3 == 1) { if (c - 1 == blank) { return mycalc(maxLeft / 2, 0, left); } } else { if (c + 1 == blank) { return mycalc(maxLeft / 2, 0, left); } else if (c - 1 == blank) { return mycalc(maxLeft, maxLeft / 2, left); } } return left - dx; } @Override public int clampViewPositionVertical(View child, int top, int dy) { int c = (int) child.getTag(); if (blank < 4) { if (c - 3 == blank) { return mycalc(maxTop / 2, 0, top); } } else if (blank < 7) { if (c + 3 == blank) { return mycalc(maxTop / 2, 0, top); } else if (c - 3 == blank) { return mycalc(maxTop, maxTop / 2, top); } } else { if (c + 3 == blank) { return mycalc(maxTop, maxTop / 2, top); } } return top - dy; } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { Log.v(TAG, "onviewreleased"); Log.v(TAG,curViewLeft+","+curViewTop); if (Math.abs(releasedChild.getLeft() - curViewLeft) == maxLeft / 2 || Math.abs(releasedChild.getTop() - curViewTop) == maxTop / 2) { Log.v(TAG, "onviewreleased in"); int i = blank; blank = (int) releasedChild.getTag(); releasedChild.setTag(i); curDragView = 0; } else if (releasedChild.getLeft() == curViewLeft && releasedChild.getTop() == curViewTop) { curDragView = 0; } Log.v(TAG,"curDragView:"+curDragView+",blank:"+blank); } int mycalc(int max, int min, int input) { return input > max ? max : input < min ? min : input; } @Override public void onViewCaptured(View capturedChild, int activePointerId) { Log.v(TAG,"onViewCaptured"); super.onViewCaptured(capturedChild, activePointerId); } @Override public void onViewDragStateChanged(int state) { Log.v(TAG, "onViewDragStateChanged"); super.onViewDragStateChanged(state); if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) { Log.v(TAG, "onviewdragstatechanged finish"); } } } }
以上就是主要代码,以下是布局文件相关
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/swipeackframelayout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.inthecheesefactory.lab.designlibrary.Main2Activity"> <com.inthecheesefactory.lab.designlibrary.SwipeBackRelativelayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"> <View android:id="@+id/view0" android:layout_width="180dp" android:layout_height="80dp" android:background="@drawable/header" /> <View android:id="@+id/view8" android:layout_width="180dp" android:layout_height="80dp" android:layout_alignParentTop="true" android:layout_toEndOf="@+id/view0" android:layout_toRightOf="@+id/view0" android:background="@drawable/header" /> <View android:id="@+id/view7" android:layout_width="180dp" android:layout_height="80dp" android:layout_alignParentTop="true" android:layout_toEndOf="@+id/view8" android:layout_toRightOf="@+id/view8" android:background="@drawable/header" /> <View android:id="@+id/view6" android:layout_width="180dp" android:layout_height="80dp" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_below="@+id/view0" android:background="@drawable/header" /> <View android:id="@+id/view5" android:layout_width="180dp" android:layout_height="80dp" android:layout_below="@+id/view0" android:layout_toEndOf="@+id/view0" android:layout_toRightOf="@+id/view0" android:background="@drawable/header" /> <View android:id="@+id/view4" android:layout_width="180dp" android:layout_height="80dp" android:layout_below="@+id/view7" android:layout_toEndOf="@+id/view5" android:layout_toRightOf="@+id/view5" android:background="@drawable/header" /> <View android:id="@+id/view3" android:layout_width="180dp" android:layout_height="80dp" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_below="@+id/view5" android:background="@drawable/header" /> <View android:id="@+id/view2" android:layout_width="180dp" android:layout_height="80dp" android:layout_below="@+id/view5" android:layout_toEndOf="@+id/view3" android:layout_toRightOf="@+id/view3" android:background="@drawable/header" /> </com.inthecheesefactory.lab.designlibrary.SwipeBackRelativelayout> </RelativeLayout>
demo还没写完