diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..797c2f4b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: android +android: + components: + - tools + - platform-tools + - build-tools-25.0.2 + - android-25 + - extra-android-support + - extra + - extra-android-m2repository +script: + - ./gradlew assembleDebug \ No newline at end of file diff --git a/README.md b/README.md index 01124a0c..55c53938 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -# Android Swipe Layout +# Android Swipe Layout [![Build Status](https://travis-ci.org/daimajia/AndroidSwipeLayout.svg?branch=master)](https://travis-ci.org/daimajia/AndroidSwipeLayout) [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/daimajia/AndroidSwipeLayout?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Insight.io](https://insight.io/repoBadge/github.com/daimajia/AndroidSwipeLayout)](https://insight.io/github.com/daimajia/AndroidSwipeLayout) + This is the brother of [AndroidViewHover](https://github.com/daimajia/AndroidViewHover). One year ago, I started to make an app named [EverMemo](https://play.google.com/store/apps/details?id=com.zhan_dui.evermemo) with my good friends. The designer gave me a design picture, the design like this: @@ -40,7 +42,7 @@ When I start to make this library, I set some goals: dependencies { compile 'com.android.support:recyclerview-v7:21.0.0' compile 'com.android.support:support-v4:20.+' - compile "com.daimajia.swipelayout:library:1.1.9@aar" + compile "com.daimajia.swipelayout:library:1.2.0@aar" } ``` @@ -60,7 +62,7 @@ dependencies { com.daimajia.swipelayout library - 1.1.9 + 1.2.0 apklib ``` @@ -71,6 +73,8 @@ dependencies { ### Step 2 +**Make sure to use the internal adapter instead of your own!** + [Wiki Usage](https://github.com/daimajia/AndroidSwipeLayout/wiki/usage) ## Wiki diff --git a/build.gradle b/build.gradle index 6356aabd..82697f55 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,13 @@ buildscript { repositories { jcenter() + maven { + url "https://jitpack.io" + } } dependencies { - classpath 'com.android.tools.build:gradle:1.0.0' + classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.github.dcendents:android-maven-plugin:1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -15,5 +19,8 @@ buildscript { allprojects { repositories { jcenter() + maven { + url "https://jitpack.io" + } } } diff --git a/demo/build.gradle b/demo/build.gradle index 586f375b..09dca2ba 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -26,7 +26,7 @@ android { dependencies { compile project(":library") - compile 'com.android.support:recyclerview-v7:21.0.0' + compile 'com.android.support:recyclerview-v7:25.1.1' compile 'com.daimajia.easing:library:1.0.0@aar' compile 'com.daimajia.androidanimations:library:1.1.2@aar' compile 'com.nineoldandroids:library:2.4.0' diff --git a/demo/src/main/java/com/daimajia/swipedemo/GridViewExample.java b/demo/src/main/java/com/daimajia/swipedemo/GridViewExample.java index ff465889..42fae4da 100644 --- a/demo/src/main/java/com/daimajia/swipedemo/GridViewExample.java +++ b/demo/src/main/java/com/daimajia/swipedemo/GridViewExample.java @@ -7,7 +7,6 @@ import android.widget.AdapterView; import android.widget.GridView; -import com.daimajia.swipe.implments.SwipeItemMangerImpl; import com.daimajia.swipe.util.Attributes; import com.daimajia.swipedemo.adapter.GridViewAdapter; diff --git a/demo/src/main/java/com/daimajia/swipedemo/ListViewExample.java b/demo/src/main/java/com/daimajia/swipedemo/ListViewExample.java index ab6edf4c..f957fc8d 100644 --- a/demo/src/main/java/com/daimajia/swipedemo/ListViewExample.java +++ b/demo/src/main/java/com/daimajia/swipedemo/ListViewExample.java @@ -17,7 +17,6 @@ import android.widget.Toast; import com.daimajia.swipe.SwipeLayout; -import com.daimajia.swipe.implments.SwipeItemMangerImpl; import com.daimajia.swipe.util.Attributes; import com.daimajia.swipedemo.adapter.ListViewAdapter; @@ -68,7 +67,7 @@ public boolean onTouch(View v, MotionEvent event) { @Override public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { Toast.makeText(mContext, "OnItemLongClickListener", Toast.LENGTH_SHORT).show(); - return false; + return true; } }); mListView.setOnScrollListener(new AbsListView.OnScrollListener() { diff --git a/demo/src/main/java/com/daimajia/swipedemo/MyActivity.java b/demo/src/main/java/com/daimajia/swipedemo/MyActivity.java index 0db17605..8a476218 100644 --- a/demo/src/main/java/com/daimajia/swipedemo/MyActivity.java +++ b/demo/src/main/java/com/daimajia/swipedemo/MyActivity.java @@ -4,6 +4,7 @@ import android.content.Intent; import android.graphics.Color; import android.os.Bundle; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -28,9 +29,11 @@ protected void onCreate(Bundle savedInstanceState) { sample1 = (SwipeLayout) findViewById(R.id.sample1); 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); + View starBottView = sample1.findViewById(R.id.starbott); + sample1.addDrag(SwipeLayout.DragEdge.Left, sample1.findViewById(R.id.bottom_wrapper)); + sample1.addDrag(SwipeLayout.DragEdge.Right, sample1.findViewById(R.id.bottom_wrapper_2)); + sample1.addDrag(SwipeLayout.DragEdge.Top, starBottView); + sample1.addDrag(SwipeLayout.DragEdge.Bottom, starBottView); sample1.addRevealListener(R.id.delete, new SwipeLayout.OnRevealListener() { @Override public void onReveal(View child, SwipeLayout.DragEdge edge, float fraction, int distance) { @@ -38,6 +41,21 @@ public void onReveal(View child, SwipeLayout.DragEdge edge, float fraction, int } }); + sample1.getSurfaceView().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(MyActivity.this, "Click on surface", Toast.LENGTH_SHORT).show(); + Log.d(MyActivity.class.getName(), "click on surface"); + } + }); + sample1.getSurfaceView().setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + Toast.makeText(MyActivity.this, "longClick on surface", Toast.LENGTH_SHORT).show(); + Log.d(MyActivity.class.getName(), "longClick on surface"); + return true; + } + }); sample1.findViewById(R.id.star2).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -74,7 +92,7 @@ public void onReveal(View child, SwipeLayout.DragEdge edge, float fraction, int sample2 = (SwipeLayout) findViewById(R.id.sample2); sample2.setShowMode(SwipeLayout.ShowMode.LayDown); - sample2.setDragEdge(SwipeLayout.DragEdge.Right); + sample2.addDrag(SwipeLayout.DragEdge.Right, sample2.findViewWithTag("Bottom2")); // sample2.setShowMode(SwipeLayout.ShowMode.PullOut); sample2.findViewById(R.id.star).setOnClickListener(new View.OnClickListener() { @Override @@ -103,11 +121,17 @@ public void onClick(View v) { Toast.makeText(MyActivity.this, "Yo", Toast.LENGTH_SHORT).show(); } }); + sample2.getSurfaceView().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(MyActivity.this, "Click on surface", Toast.LENGTH_SHORT).show(); + } + }); //sample3 sample3 = (SwipeLayout) findViewById(R.id.sample3); - sample3.setDragEdge(SwipeLayout.DragEdge.Top); + sample3.addDrag(SwipeLayout.DragEdge.Top, sample3.findViewWithTag("Bottom3")); sample3.addRevealListener(R.id.bottom_wrapper_child1, new SwipeLayout.OnRevealListener() { @Override public void onReveal(View child, SwipeLayout.DragEdge edge, float fraction, int distance) { @@ -120,12 +144,18 @@ public void onReveal(View child, SwipeLayout.DragEdge edge, float fraction, int child.setBackgroundColor(c); } }); - sample3.findViewById(R.id.star).setOnClickListener(new View.OnClickListener() { + sample3.findViewById(R.id.bottom_wrapper_child1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MyActivity.this, "Yo!", Toast.LENGTH_SHORT).show(); } }); + sample3.getSurfaceView().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(MyActivity.this, "Click on surface", Toast.LENGTH_SHORT).show(); + } + }); } diff --git a/demo/src/main/java/com/daimajia/swipedemo/RecyclerViewExample.java b/demo/src/main/java/com/daimajia/swipedemo/RecyclerViewExample.java index 2c34426d..fd42733f 100644 --- a/demo/src/main/java/com/daimajia/swipedemo/RecyclerViewExample.java +++ b/demo/src/main/java/com/daimajia/swipedemo/RecyclerViewExample.java @@ -2,7 +2,6 @@ import android.app.ActionBar; import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; diff --git a/demo/src/main/java/com/daimajia/swipedemo/adapter/ListViewAdapter.java b/demo/src/main/java/com/daimajia/swipedemo/adapter/ListViewAdapter.java index 074e2de2..e34f31de 100644 --- a/demo/src/main/java/com/daimajia/swipedemo/adapter/ListViewAdapter.java +++ b/demo/src/main/java/com/daimajia/swipedemo/adapter/ListViewAdapter.java @@ -43,6 +43,12 @@ public void onDoubleClick(SwipeLayout layout, boolean surface) { Toast.makeText(mContext, "DoubleClick", Toast.LENGTH_SHORT).show(); } }); + v.findViewById(R.id.delete).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(mContext, "click delete", Toast.LENGTH_SHORT).show(); + } + }); return v; } diff --git a/demo/src/main/java/com/daimajia/swipedemo/adapter/RecyclerViewAdapter.java b/demo/src/main/java/com/daimajia/swipedemo/adapter/RecyclerViewAdapter.java index 206733bc..3b4c34d4 100644 --- a/demo/src/main/java/com/daimajia/swipedemo/adapter/RecyclerViewAdapter.java +++ b/demo/src/main/java/com/daimajia/swipedemo/adapter/RecyclerViewAdapter.java @@ -15,7 +15,6 @@ import com.daimajia.swipe.SimpleSwipeListener; import com.daimajia.swipe.SwipeLayout; import com.daimajia.swipe.adapters.RecyclerSwipeAdapter; -import com.daimajia.swipe.implments.SwipeItemRecyclerMangerImpl; import com.daimajia.swipedemo.R; import java.util.ArrayList; @@ -90,7 +89,7 @@ public void onClick(View view) { }); viewHolder.textViewPos.setText((position + 1) + "."); viewHolder.textViewData.setText(item); - mItemManger.bindView(viewHolder.itemView, position); + mItemManger.bind(viewHolder.itemView, position); } @Override diff --git a/demo/src/main/java/com/daimajia/swipedemo/adapter/util/RecyclerItemClickListener.java b/demo/src/main/java/com/daimajia/swipedemo/adapter/util/RecyclerItemClickListener.java index af4021b1..613e8e52 100644 --- a/demo/src/main/java/com/daimajia/swipedemo/adapter/util/RecyclerItemClickListener.java +++ b/demo/src/main/java/com/daimajia/swipedemo/adapter/util/RecyclerItemClickListener.java @@ -37,4 +37,9 @@ public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { } + + @Override + public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { + + } } diff --git a/demo/src/main/res/drawable/dark_gray.xml b/demo/src/main/res/drawable/dark_gray.xml new file mode 100644 index 00000000..46878503 --- /dev/null +++ b/demo/src/main/res/drawable/dark_gray.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/demo/src/main/res/drawable/red.xml b/demo/src/main/res/drawable/red.xml new file mode 100644 index 00000000..707047e9 --- /dev/null +++ b/demo/src/main/res/drawable/red.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/demo/src/main/res/drawable/white.xml b/demo/src/main/res/drawable/white.xml new file mode 100644 index 00000000..8dfff14a --- /dev/null +++ b/demo/src/main/res/drawable/white.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/demo/src/main/res/layout/listview_item.xml b/demo/src/main/res/layout/listview_item.xml index 89620277..4b2c5074 100644 --- a/demo/src/main/res/layout/listview_item.xml +++ b/demo/src/main/res/layout/listview_item.xml @@ -36,7 +36,7 @@ android:layout_width="0dp" android:layout_height="40dp" android:layout_weight="4" - android:background="#ffffff" + android:background="@drawable/white" android:text="Yes,Delete" android:textColor="#FF5534" /> diff --git a/demo/src/main/res/layout/main.xml b/demo/src/main/res/layout/main.xml index 759c1c98..cf05988e 100644 --- a/demo/src/main/res/layout/main.xml +++ b/demo/src/main/res/layout/main.xml @@ -1,12 +1,17 @@ - + android:layout_width="match_parent" + android:layout_height="match_parent"> + diff --git a/demo/src/main/res/layout/sample1.xml b/demo/src/main/res/layout/sample1.xml index 1dab32d8..350bdb0f 100644 --- a/demo/src/main/res/layout/sample1.xml +++ b/demo/src/main/res/layout/sample1.xml @@ -1,9 +1,11 @@ - + android:layout_height="80dp" + app:clickToClose="true"> @@ -61,7 +64,7 @@ android:id="@+id/trash2" android:src="@drawable/trash" android:layout_width="70dp" - android:background="#FF3B30" + android:background="@drawable/red" android:paddingLeft="25dp" android:paddingRight="25dp" android:layout_height="match_parent" /> @@ -74,7 +77,8 @@ android:layout_height="match_parent"> - - - - + android:layout_height="match_parent" /> diff --git a/demo/src/main/res/layout/sample2.xml b/demo/src/main/res/layout/sample2.xml index 539e5fa9..08da313e 100644 --- a/demo/src/main/res/layout/sample2.xml +++ b/demo/src/main/res/layout/sample2.xml @@ -26,7 +26,7 @@ android:id="@+id/trash" android:src="@drawable/trash" android:layout_width="70dp" - android:background="#FF3B30" + android:background="@drawable/red" android:paddingLeft="25dp" android:paddingRight="25dp" android:layout_height="match_parent" /> @@ -35,7 +35,7 @@ - - - + android:layout_height="match_parent" /> \ No newline at end of file diff --git a/demo/src/main/res/values/colors.xml b/demo/src/main/res/values/colors.xml index 3768db71..35111398 100644 --- a/demo/src/main/res/values/colors.xml +++ b/demo/src/main/res/values/colors.xml @@ -2,4 +2,8 @@ #E8E8E0 #DBDBD3 + #FF3B00 + #990000 + #4C535B + #ff7e8a97 \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 17eac851..beab8970 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,11 +18,11 @@ # org.gradle.parallel=true -VERSION_NAME=1.1.8 -VERSION_CODE=20 +VERSION_NAME=1.2.0 +VERSION_CODE=22 GROUP=com.daimajia.swipelayout -ANDROID_BUILD_MIN_SDK_VERSION=8 -ANDROID_BUILD_TARGET_SDK_VERSION=21 -ANDROID_BUILD_SDK_VERSION=21 -ANDROID_BUILD_TOOLS_VERSION=21.0.0 +ANDROID_BUILD_MIN_SDK_VERSION=9 +ANDROID_BUILD_TARGET_SDK_VERSION=25 +ANDROID_BUILD_SDK_VERSION=25 +ANDROID_BUILD_TOOLS_VERSION=25.0.2 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index af3deba8..776d2a5a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Thu Mar 09 16:07:03 CST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-2.2.1-all.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/library/build.gradle b/library/build.gradle index b2a64c19..906272e1 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -5,13 +5,22 @@ android { buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION defaultConfig { - minSdkVersion 8 + minSdkVersion 9 targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) } } dependencies { - compile 'com.android.support:recyclerview-v7:21.0.0' - compile 'com.android.support:support-v4:21.0.3' + compile 'com.android.support:recyclerview-v7:25.2.0' + compile 'com.android.support:support-v4:25.2.0' +} +apply from: './gradle-mvn-push.gradle' + +// build a jar with source files +task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' +} +artifacts { + archives sourcesJar } -apply from: './gradle-mvn-push.gradle' \ No newline at end of file diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml index d481b7ff..aebf83d9 100644 --- a/library/src/main/AndroidManifest.xml +++ b/library/src/main/AndroidManifest.xml @@ -1,2 +1,3 @@ - - + + + diff --git a/library/src/main/java/com/daimajia/swipe/SwipeLayout.java b/library/src/main/java/com/daimajia/swipe/SwipeLayout.java index 8568aad9..6703123c 100644 --- a/library/src/main/java/com/daimajia/swipe/SwipeLayout.java +++ b/library/src/main/java/com/daimajia/swipe/SwipeLayout.java @@ -3,80 +3,72 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; +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.Adapter; +import android.widget.AbsListView; import android.widget.AdapterView; -import android.widget.BaseAdapter; import android.widget.FrameLayout; -import android.widget.ListAdapter; +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 { - + @Deprecated 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 static final DragEdge DefaultDragEdge = DragEdge.Right; private int mTouchSlop; - private int mLeftIndex; - private int mRightIndex; - private int mTopIndex; - private int mBottomIndex; - - private int mCurrentDirectionIndex = 0; + private DragEdge mCurrentDragEdge = DefaultDragEdge; private ViewDragHelper mDragHelper; private int mDragDistance = 0; - private List mDragEdges; + private LinkedHashMap mDragEdges = new LinkedHashMap<>(); private ShowMode mShowMode; - private float mLeftEdgeSwipeOffset; - private float mRightEdgeSwipeOffset; - private float mTopEdgeSwipeOffset; - private float mBottomEdgeSwipeOffset; + private float[] mEdgeSwipesOffset = new float[4]; - private Map mBottomViewIdMap = new HashMap(); - private boolean mBottomViewIdsSet = false; - - private List mSwipeListeners = new ArrayList(); - private List mSwipeDeniers = new ArrayList(); - private Map> mRevealListeners = new HashMap>(); - private Map mShowEntirely = new HashMap(); + private List mSwipeListeners = new ArrayList<>(); + private List mSwipeDeniers = new ArrayList<>(); + private Map> mRevealListeners = new HashMap<>(); + private Map mShowEntirely = new HashMap<>(); + private Map mViewBoundCache = new HashMap<>();//save all children's bound, restore in onLayout private DoubleClickListener mDoubleClickListener; private boolean mSwipeEnabled = true; - private boolean mLeftSwipeEnabled = true; - private boolean mRightSwipeEnabled = true; - private boolean mTopSwipeEnabled = true; - private boolean mBottomSwipeEnabled = 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 static enum DragEdge { + public enum DragEdge { Left, - Right, Top, - Bottom; + Right, + Bottom } - ; - - public static enum ShowMode { + public enum ShowMode { LayDown, PullOut } @@ -96,42 +88,42 @@ public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeLayout); 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); + 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)); - mDragEdges = new ArrayList(); if ((dragEdgeChoices & DRAG_LEFT) == DRAG_LEFT) { - mDragEdges.add(DragEdge.Left); - } - if ((dragEdgeChoices & DRAG_RIGHT) == DRAG_RIGHT) { - mDragEdges.add(DragEdge.Right); + mDragEdges.put(DragEdge.Left, null); } if ((dragEdgeChoices & DRAG_TOP) == DRAG_TOP) { - mDragEdges.add(DragEdge.Top); + mDragEdges.put(DragEdge.Top, null); + } + if ((dragEdgeChoices & DRAG_RIGHT) == DRAG_RIGHT) { + mDragEdges.put(DragEdge.Right, null); } if ((dragEdgeChoices & DRAG_BOTTOM) == DRAG_BOTTOM) { - mDragEdges.add(DragEdge.Bottom); + mDragEdges.put(DragEdge.Bottom, null); } - populateIndexes(); int ordinal = a.getInt(R.styleable.SwipeLayout_show_mode, ShowMode.PullOut.ordinal()); mShowMode = ShowMode.values()[ordinal]; a.recycle(); + } public interface SwipeListener { - public void onStartOpen(SwipeLayout layout); + void onStartOpen(SwipeLayout layout); - public void onOpen(SwipeLayout layout); + void onOpen(SwipeLayout layout); - public void onStartClose(SwipeLayout layout); + void onStartClose(SwipeLayout layout); - public void onClose(SwipeLayout layout); + void onClose(SwipeLayout layout); - public void onUpdate(SwipeLayout layout, int leftOffset, int topOffset); + void onUpdate(SwipeLayout layout, int leftOffset, int topOffset); - public void onHandRelease(SwipeLayout layout, float xvel, float yvel); + void onHandRelease(SwipeLayout layout, float xvel, float yvel); } public void addSwipeListener(SwipeListener l) { @@ -142,7 +134,11 @@ public void removeSwipeListener(SwipeListener l) { mSwipeListeners.remove(l); } - public static interface SwipeDenier { + 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 @@ -150,7 +146,7 @@ public static interface SwipeDenier { * * @return true deny false allow */ - public boolean shouldDenySwipe(MotionEvent ev); + boolean shouldDenySwipe(MotionEvent ev); } public void addSwipeDenier(SwipeDenier denier) { @@ -166,7 +162,7 @@ public void removeAllSwipeDeniers() { } public interface OnRevealListener { - public void onReveal(View child, DragEdge edge, float fraction, int distance); + void onReveal(View child, DragEdge edge, float fraction, int distance); } /** @@ -226,7 +222,7 @@ public void removeAllRevealListeners(int childId) { @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (child == getSurfaceView()) { - switch (mDragEdges.get(mCurrentDirectionIndex)) { + switch (mCurrentDragEdge) { case Top: case Bottom: return getPaddingLeft(); @@ -241,9 +237,9 @@ public int clampViewPositionHorizontal(View child, int left, int dx) { return getPaddingLeft() - mDragDistance; break; } - } else if (getBottomViews().get(mCurrentDirectionIndex) == child) { + } else if (getCurrentBottomView() == child) { - switch (mDragEdges.get(mCurrentDirectionIndex)) { + switch (mCurrentDragEdge) { case Top: case Bottom: return getPaddingLeft(); @@ -267,7 +263,7 @@ public int clampViewPositionHorizontal(View child, int left, int dx) { @Override public int clampViewPositionVertical(View child, int top, int dy) { if (child == getSurfaceView()) { - switch (mDragEdges.get(mCurrentDirectionIndex)) { + switch (mCurrentDragEdge) { case Left: case Right: return getPaddingTop(); @@ -285,7 +281,9 @@ public int clampViewPositionVertical(View child, int top, int dy) { } } } else { - switch (mDragEdges.get(mCurrentDirectionIndex)) { + View surfaceView = getSurfaceView(); + int surfaceViewTop = surfaceView == null ? 0 : surfaceView.getTop(); + switch (mCurrentDragEdge) { case Left: case Right: return getPaddingTop(); @@ -293,9 +291,9 @@ public int clampViewPositionVertical(View child, int top, int dy) { if (mShowMode == ShowMode.PullOut) { if (top > getPaddingTop()) return getPaddingTop(); } else { - if (getSurfaceView().getTop() + dy < getPaddingTop()) + if (surfaceViewTop + dy < getPaddingTop()) return getPaddingTop(); - if (getSurfaceView().getTop() + dy > getPaddingTop() + mDragDistance) + if (surfaceViewTop + dy > getPaddingTop() + mDragDistance) return getPaddingTop() + mDragDistance; } break; @@ -304,9 +302,9 @@ public int clampViewPositionVertical(View child, int top, int dy) { if (top < getMeasuredHeight() - mDragDistance) return getMeasuredHeight() - mDragDistance; } else { - if (getSurfaceView().getTop() + dy >= getPaddingTop()) + if (surfaceViewTop + dy >= getPaddingTop()) return getPaddingTop(); - if (getSurfaceView().getTop() + dy <= getPaddingTop() - mDragDistance) + if (surfaceViewTop + dy <= getPaddingTop() - mDragDistance) return getPaddingTop() - mDragDistance; } } @@ -316,7 +314,11 @@ public int clampViewPositionVertical(View child, int top, int dy) { @Override public boolean tryCaptureView(View child, int pointerId) { - return child == getSurfaceView() || getBottomViews().contains(child); + boolean result = child == getSurfaceView() || getBottomViews().contains(child); + if (result) { + isCloseBeforeDrag = getOpenStatus() == Status.Close; + } + return result; } @Override @@ -329,19 +331,14 @@ public int getViewVerticalDragRange(View child) { return mDragDistance; } + boolean isCloseBeforeDrag = true; + @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); - for (SwipeListener l : mSwipeListeners) + processHandRelease(xvel, yvel, isCloseBeforeDrag); + for (SwipeListener l : mSwipeListeners) { l.onHandRelease(SwipeLayout.this, xvel, yvel); - if (releasedChild == getSurfaceView()) { - processSurfaceRelease(xvel, yvel); - } else if (getBottomViews().contains(releasedChild)) { - if (getShowMode() == ShowMode.PullOut) { - processBottomPullOutRelease(xvel, yvel); - } else if (getShowMode() == ShowMode.LayDown) { - processBottomLayDownMode(xvel, yvel); - } } invalidate(); @@ -349,39 +346,46 @@ public void onViewReleased(View releasedChild, float xvel, float yvel) { @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()) { - - 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); + 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) { - getSurfaceView().offsetLeftAndRight(dx); - getSurfaceView().offsetTopAndBottom(dy); + surfaceView.offsetLeftAndRight(dx); + surfaceView.offsetTopAndBottom(dy); } else { - Rect rect = computeBottomLayDown(mDragEdges.get(mCurrentDirectionIndex)); - getBottomViews().get(mCurrentDirectionIndex).layout(rect.left, rect.top, rect.right, rect.bottom); + Rect rect = computeBottomLayDown(mCurrentDragEdge); + if (currentBottomView != null) { + currentBottomView.layout(rect.left, rect.top, rect.right, rect.bottom); + } - int newLeft = getSurfaceView().getLeft() + dx, newTop = getSurfaceView().getTop() + dy; + int newLeft = surfaceView.getLeft() + dx, newTop = surfaceView.getTop() + dy; - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left && newLeft < getPaddingLeft()) + if (mCurrentDragEdge == DragEdge.Left && newLeft < getPaddingLeft()) newLeft = getPaddingLeft(); - else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right && newLeft > getPaddingLeft()) + else if (mCurrentDragEdge == DragEdge.Right && newLeft > getPaddingLeft()) newLeft = getPaddingLeft(); - else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top && newTop < getPaddingTop()) + else if (mCurrentDragEdge == DragEdge.Top && newTop < getPaddingTop()) newTop = getPaddingTop(); - else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Bottom && newTop > getPaddingTop()) + else if (mCurrentDragEdge == DragEdge.Bottom && newTop > getPaddingTop()) newTop = getPaddingTop(); - getSurfaceView() - .layout(newLeft, newTop, newLeft + getMeasuredWidth(), newTop + getMeasuredHeight()); + surfaceView.layout(newLeft, newTop, newLeft + getMeasuredWidth(), newTop + getMeasuredHeight()); } } @@ -390,22 +394,39 @@ else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Bottom && newTop > g 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. - * - * @param child - * @param relativePosition - * @param edge - * @param surfaceLeft - * @param surfaceTop - * @param surfaceRight - * @param surfaceBottom - * @return */ protected boolean isViewTotallyFirstShowed(View child, Rect relativePosition, DragEdge edge, int surfaceLeft, int surfaceTop, int surfaceRight, int surfaceBottom) { @@ -534,7 +555,10 @@ protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, boolean open) } if (status == Status.Open) { - getBottomViews().get(mCurrentDirectionIndex).setEnabled(true); + View currentBottomView = getCurrentBottomView(); + if (currentBottomView != null) { + currentBottomView.setEnabled(true); + } for (SwipeListener l : mSwipeListeners) { l.onOpen(SwipeLayout.this); } @@ -548,15 +572,19 @@ protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, boolean open) */ private void safeBottomView() { Status status = getOpenStatus(); - List bottoms = getBottomViews(); + List bottoms = getBottomViews(); if (status == Status.Close) { - for (ViewGroup bottom : bottoms) { - if (bottom.getVisibility() != INVISIBLE) bottom.setVisibility(INVISIBLE); + for (View bottom : bottoms) { + if (bottom != null && bottom.getVisibility() != INVISIBLE) { + bottom.setVisibility(INVISIBLE); + } } } else { - if (bottoms.get(mCurrentDirectionIndex).getVisibility() != VISIBLE) - bottoms.get(mCurrentDirectionIndex).setVisibility(VISIBLE); + View currentBottomView = getCurrentBottomView(); + if (currentBottomView != null && currentBottomView.getVisibility() != VISIBLE) { + currentBottomView.setVisibility(VISIBLE); + } } } @@ -566,13 +594,13 @@ protected void dispatchRevealEvent(final int surfaceLeft, final int surfaceTop, for (Map.Entry> entry : mRevealListeners.entrySet()) { View child = entry.getKey(); Rect rect = getRelativePosition(child); - if (isViewShowing(child, rect, mDragEdges.get(mCurrentDirectionIndex), surfaceLeft, surfaceTop, + if (isViewShowing(child, rect, mCurrentDragEdge, surfaceLeft, surfaceTop, surfaceRight, surfaceBottom)) { mShowEntirely.put(child, false); int distance = 0; float fraction = 0f; if (getShowMode() == ShowMode.LayDown) { - switch (mDragEdges.get(mCurrentDirectionIndex)) { + switch (mCurrentDragEdge) { case Left: distance = rect.left - surfaceLeft; fraction = distance / (float) child.getWidth(); @@ -591,7 +619,7 @@ protected void dispatchRevealEvent(final int surfaceLeft, final int surfaceTop, break; } } else if (getShowMode() == ShowMode.PullOut) { - switch (mDragEdges.get(mCurrentDirectionIndex)) { + switch (mCurrentDragEdge) { case Left: distance = rect.right - getPaddingLeft(); fraction = distance / (float) child.getWidth(); @@ -612,22 +640,22 @@ protected void dispatchRevealEvent(final int surfaceLeft, final int surfaceTop, } for (OnRevealListener l : entry.getValue()) { - l.onReveal(child, mDragEdges.get(mCurrentDirectionIndex), Math.abs(fraction), distance); + l.onReveal(child, mCurrentDragEdge, Math.abs(fraction), distance); if (Math.abs(fraction) == 1) { mShowEntirely.put(child, true); } } } - if (isViewTotallyFirstShowed(child, rect, mDragEdges.get(mCurrentDirectionIndex), surfaceLeft, surfaceTop, + if (isViewTotallyFirstShowed(child, rect, mCurrentDragEdge, surfaceLeft, surfaceTop, surfaceRight, surfaceBottom)) { mShowEntirely.put(child, true); 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()); + if (mCurrentDragEdge == DragEdge.Left + || mCurrentDragEdge == DragEdge.Right) + l.onReveal(child, mCurrentDragEdge, 1, child.getWidth()); else - l.onReveal(child, mDragEdges.get(mCurrentDirectionIndex), 1, child.getHeight()); + l.onReveal(child, mCurrentDragEdge, 1, child.getHeight()); } } @@ -647,7 +675,7 @@ public void computeScroll() { * to support it from API 8. */ public interface OnLayout { - public void onLayout(SwipeLayout v); + void onLayout(SwipeLayout v); } private List mOnLayoutListeners; @@ -661,299 +689,312 @@ 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 FrameLayout.LayoutParams) { + ((LayoutParams) params).gravity = gravity; + } + addView(child, 0, params); + } + @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - int childCount = getChildCount(); - if (childCount != 1 + mDragEdges.size()) { - throw new IllegalStateException("You need to have one surface view plus one view for each of your drag edges"); + public 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(); } - 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 (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 entry : mDragEdges.entrySet()) { + if (entry.getValue() == null) { + //means used the drag_edge attr, the no gravity child should be use set + mDragEdges.put(entry.getKey(), child); + break; + } } } + if (child.getParent() == this) { + return; + } + super.addView(child, index, params); + } - if (mShowMode == ShowMode.PullOut) - layoutPullOut(); - else if (mShowMode == ShowMode.LayDown) layoutLayDown(); - - safeBottomView(); + @Override + protected 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() { - Rect rect = computeSurfaceLayoutArea(false); - getSurfaceView().layout(rect.left, rect.top, rect.right, rect.bottom); - rect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, rect); - getBottomViews().get(mCurrentDirectionIndex).layout(rect.left, rect.top, rect.right, rect.bottom); - bringChildToFront(getSurfaceView()); + 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() { - Rect rect = computeSurfaceLayoutArea(false); - getSurfaceView().layout(rect.left, rect.top, rect.right, rect.bottom); - rect = computeBottomLayoutAreaViaSurface(ShowMode.LayDown, rect); - getBottomViews().get(mCurrentDirectionIndex).layout(rect.left, rect.top, rect.right, rect.bottom); - bringChildToFront(getSurfaceView()); + 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); + } } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); + private boolean mIsBeingDragged; - 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 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; - private boolean mTouchConsumedByChild = false; + } else { + if (distanceY > 0 && isTopSwipeEnabled()) { + dragEdge = DragEdge.Top; + } else if (distanceY < 0 && isBottomSwipeEnabled()) { + dragEdge = DragEdge.Bottom; + } else return; + } + setCurrentDragEdge(dragEdge); + } - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { + 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 (!isEnabled() || !isEnabledInAdapterView()) { - return true; + if (angle > 30 || !suitable) { + doNothing = true; + } } - if (!isSwipeEnabled()) { - return false; - } + if (mCurrentDragEdge == DragEdge.Left) { + boolean suitable = (status == Status.Open && distanceX < -mTouchSlop) + || (status == Status.Close && distanceX > mTouchSlop); + suitable = suitable || status == Status.Middle; - for (SwipeDenier denier : mSwipeDeniers) { - if (denier != null && denier.shouldDenySwipe(ev)) { - return false; + if (angle > 30 || !suitable) { + doNothing = true; } } - // - // if a child wants to handle the touch event, - // then let it do it. - // - int action = ev.getActionMasked(); - switch (action) { - case MotionEvent.ACTION_DOWN: - Status status = getOpenStatus(); - if (status == Status.Close) { - mTouchConsumedByChild = childNeedHandleTouchEvent(getSurfaceView(), ev) != null; - } else if (status == Status.Open) { - mTouchConsumedByChild = childNeedHandleTouchEvent(getBottomViews().get(mCurrentDirectionIndex), ev) != null; - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - mTouchConsumedByChild = false; + + 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 (mTouchConsumedByChild) return false; - return mDragHelper.shouldInterceptTouchEvent(ev); - } + if (mCurrentDragEdge == DragEdge.Bottom) { + boolean suitable = (status == Status.Open && distanceY > mTouchSlop) + || (status == Status.Close && distanceY < -mTouchSlop); + suitable = suitable || status == Status.Middle; - /** - * 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; - - int childCount = v.getChildCount(); - for (int i = childCount - 1; i >= 0; i--) { - View child = v.getChildAt(i); - 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 (angle < 60 || !suitable) { + doNothing = true; } } - return null; + mIsBeingDragged = !doNothing; } - /** - * 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; + @Override + public 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; + } + } - int[] loc = new int[2]; - v.getLocationOnScreen(loc); - int left = loc[0], top = loc[1]; + 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 touch + if (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 layout + return false; + } + break; - if (event.getRawX() > left && event.getRawX() < left + v.getWidth() && event.getRawY() > top - && event.getRawY() < top + v.getHeight()) { - return v.onTouchEvent(event); + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + mIsBeingDragged = false; + mDragHelper.processTouchEvent(ev); + break; + default://handle other action, such as ACTION_POINTER_DOWN/UP + mDragHelper.processTouchEvent(ev); } - - return false; + return mIsBeingDragged; } 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 (!isSwipeEnabled()) return super.onTouchEvent(event); int action = event.getActionMasked(); - ViewParent parent = getParent(); - gestureDetector.onTouchEvent(event); - Status status = getOpenStatus(); - ViewGroup touching = null; - if (status == Status.Close) { - touching = getSurfaceView(); - } else if (status == Status.Open) { - touching = getBottomViews().get(mCurrentDirectionIndex); - } switch (action) { case MotionEvent.ACTION_DOWN: mDragHelper.processTouchEvent(event); - parent.requestDisallowInterceptTouchEvent(true); - sX = event.getRawX(); sY = event.getRawY(); - if (touching != null) touching.setPressed(true); - return true; - 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)); - 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 (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) { - doNothing = true; - } - } - 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) { - doNothing = true; - } - } - - 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) { - doNothing = true; - } - } - - 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) { - doNothing = true; - } - } - - if (doNothing) { - parent.requestDisallowInterceptTouchEvent(false); - return false; - } else { - if (touching != null) { - touching.setPressed(false); - } - parent.requestDisallowInterceptTouchEvent(true); + case MotionEvent.ACTION_MOVE: { + //the drag state and the direction are already judged at onInterceptTouchEvent + checkCanDrag(event); + if (mIsBeingDragged) { + getParent().requestDisallowInterceptTouchEvent(true); mDragHelper.processTouchEvent(event); } break; } case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: { - sX = -1; - sY = -1; - if (touching != null) { - touching.setPressed(false); - } - } - default: - parent.requestDisallowInterceptTouchEvent(true); + case MotionEvent.ACTION_CANCEL: + mIsBeingDragged = false; + mDragHelper.processTouchEvent(event); + break; + + default://handle other action, such as ACTION_POINTER_DOWN/UP mDragHelper.processTouchEvent(event); } - return true; + return super.onTouchEvent(event) || mIsBeingDragged || action == MotionEvent.ACTION_DOWN; } - /** - * 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() { - AdapterView adapterView = getAdapterView(); - boolean enable = true; - if (adapterView != null) { - Adapter adapter = adapterView.getAdapter(); - if (adapter != null) { - int p = adapterView.getPositionForView(SwipeLayout.this); - if (adapter instanceof BaseAdapter) { - enable = ((BaseAdapter) adapter).isEnabled(p); - } else if (adapter instanceof ListAdapter) { - enable = ((ListAdapter) adapter).isEnabled(p); - } - } - } - return enable; + public boolean isClickToClose() { + return mClickToClose; + } + + public void setClickToClose(boolean mClickToClose) { + this.mClickToClose = mClickToClose; } public void setSwipeEnabled(boolean enabled) { @@ -965,35 +1006,83 @@ public boolean isSwipeEnabled() { } public boolean isLeftSwipeEnabled() { - return mLeftSwipeEnabled; + View bottomView = mDragEdges.get(DragEdge.Left); + return bottomView != null && bottomView.getParent() == this + && bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Left.ordinal()]; } public void setLeftSwipeEnabled(boolean leftSwipeEnabled) { - this.mLeftSwipeEnabled = leftSwipeEnabled; + this.mSwipesEnabled[DragEdge.Left.ordinal()] = leftSwipeEnabled; } public boolean isRightSwipeEnabled() { - return mRightSwipeEnabled; + View bottomView = mDragEdges.get(DragEdge.Right); + return bottomView != null && bottomView.getParent() == this + && bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Right.ordinal()]; } public void setRightSwipeEnabled(boolean rightSwipeEnabled) { - this.mRightSwipeEnabled = rightSwipeEnabled; + this.mSwipesEnabled[DragEdge.Right.ordinal()] = rightSwipeEnabled; } public boolean isTopSwipeEnabled() { - return mTopSwipeEnabled; + View bottomView = mDragEdges.get(DragEdge.Top); + return bottomView != null && bottomView.getParent() == this + && bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Top.ordinal()]; } public void setTopSwipeEnabled(boolean topSwipeEnabled) { - this.mTopSwipeEnabled = topSwipeEnabled; + this.mSwipesEnabled[DragEdge.Top.ordinal()] = topSwipeEnabled; } public boolean isBottomSwipeEnabled() { - return mBottomSwipeEnabled; + View bottomView = mDragEdges.get(DragEdge.Bottom); + return bottomView != null && bottomView.getParent() == this + && bottomView != getSurfaceView() && mSwipesEnabled[DragEdge.Bottom.ordinal()]; } public void setBottomSwipeEnabled(boolean bottomSwipeEnabled) { - this.mBottomSwipeEnabled = 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() { @@ -1002,78 +1091,127 @@ private boolean insideAdapterView() { private AdapterView getAdapterView() { ViewParent t = getParent(); - while (t != null) { - if (t instanceof AdapterView) { - return (AdapterView) t; - } - t = t.getParent(); + if (t instanceof AdapterView) { + return (AdapterView) t; } return null; } - private void performAdapterViewItemClick(MotionEvent e) { + private void performAdapterViewItemClick() { + if (getOpenStatus() != Status.Close) return; ViewParent t = getParent(); - 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 (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)); } - t = t.getParent(); } } - private GestureDetector gestureDetector = new GestureDetector(getContext(), new SwipeDetector()); - - class SwipeDetector extends GestureDetector.SimpleOnGestureListener { - @Override - public boolean onDown(MotionEvent e) { - return true; + 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; + } - /** - * 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) { - performAdapterViewItemClick(e); + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (insideAdapterView()) { + if (clickListener == null) { + setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + performAdapterViewItemClick(); + } + }); + } + if (longClickListener == null) { + setOnLongClickListener(new OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + performAdapterViewItemLongClick(); + return true; + } + }); } - return true; } + } - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - if (mDoubleClickListener != null) { - performAdapterViewItemClick(e); - } - return true; + OnClickListener clickListener; + + @Override + public void setOnClickListener(OnClickListener l) { + super.setOnClickListener(l); + clickListener = l; + } + + OnLongClickListener longClickListener; + + @Override + public 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 { @Override - public void onLongPress(MotionEvent e) { - performLongClick(); + public boolean onSingleTapUp(MotionEvent e) { + if (mClickToClose && isTouchOnSurface(e)) { + close(); + } + return super.onSingleTapUp(e); } @Override public boolean onDoubleTap(MotionEvent e) { if (mDoubleClickListener != null) { View target; - 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()) { + 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; @@ -1084,23 +1222,14 @@ public boolean onDoubleTap(MotionEvent e) { } } - 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. * - * @param max + * @param max max distance in dp unit */ public void setDragDistance(int max) { - if (max < 0) throw new IllegalArgumentException("Drag distance can not be < 0"); + if (max < 0) max = 0; mDragDistance = dp2px(max); requestLayout(); } @@ -1118,7 +1247,7 @@ public void setShowMode(ShowMode mode) { } public DragEdge getDragEdge() { - return mDragEdges.get(mCurrentDirectionIndex); + return mCurrentDragEdge; } public int getDragDistance() { @@ -1129,71 +1258,34 @@ public ShowMode getShowMode() { return mShowMode; } - public ViewGroup getSurfaceView() { - return (ViewGroup) getChildAt(getChildCount() - 1); + /** + * return null if there is no surface view(no children) + */ + public View getSurfaceView() { + if (getChildCount() == 0) return null; + return getChildAt(getChildCount() - 1); } - 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 null if there is no bottom view + */ + public View getCurrentBottomView() { + List bottoms = getBottomViews(); + if (mCurrentDragEdge.ordinal() < bottoms.size()) { + return bottoms.get(mCurrentDragEdge.ordinal()); } - return lvg; + return null; } - // 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; - } + /** + * @return all bottomViews: left, top, right, bottom (may null if the edge is not set) + */ + public List getBottomViews() { + ArrayList bottoms = new ArrayList(); + for (DragEdge dragEdge : DragEdge.values()) { + bottoms.add(mDragEdges.get(dragEdge)); } + return bottoms; } public enum Status { @@ -1209,8 +1301,12 @@ public enum Status { * Middle. */ public Status getOpenStatus() { - int surfaceLeft = getSurfaceView().getLeft(); - int surfaceTop = getSurfaceView().getTop(); + 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) @@ -1220,102 +1316,57 @@ public Status getOpenStatus() { return Status.Middle; } + /** * Process the surface release event. * - * @param xvel - * @param yvel + * @param xvel xVelocity + * @param yvel yVelocity + * @param isCloseBeforeDragged the open state before drag */ - private void processSurfaceRelease(float xvel, float yvel) { - if (xvel == 0 && getOpenStatus() == Status.Middle) close(); - - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left - || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) { - if (xvel > 0) { - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) - open(); + 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(); } - if (xvel < 0) { - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) - close(); - else open(); - } - } else { - if (yvel > 0) { - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) - open(); + } 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(); } - if (yvel < 0) { - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) - close(); - else open(); - } - } - } - - /** - * process bottom (PullOut mode) hand release event. - * - * @param xvel - * @param yvel - */ - private void processBottomPullOutRelease(float xvel, float yvel) { - - if (xvel == 0 && getOpenStatus() == Status.Middle) close(); - - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left - || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) { - if (xvel > 0) { - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) - open(); + } 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(); } - if (xvel < 0) { - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) - close(); - else open(); - } - } else { - if (yvel > 0) { - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) - open(); + } 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(); } - - 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) { - - if (xvel == 0 && getOpenStatus() == Status.Middle) close(); - - int l = getPaddingLeft(), t = getPaddingTop(); - - if (xvel < 0 && mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) - l -= mDragDistance; - if (xvel > 0 && mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) l += 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(); - } - /** * smoothly open surface. */ @@ -1328,18 +1379,23 @@ public void open(boolean smooth) { } public void open(boolean smooth, boolean notify) { - ViewGroup surface = getSurfaceView(), bottom = getBottomViews().get(mCurrentDirectionIndex); + View surface = getSurfaceView(), bottom = getCurrentBottomView(); + if (surface == null) { + return; + } int dx, dy; Rect rect = computeSurfaceLayoutArea(true); if (smooth) { - mDragHelper.smoothSlideViewTo(getSurfaceView(), rect.left, rect.top); + 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); - bottom.layout(bRect.left, bRect.top, bRect.right, bRect.bottom); + if (bottom != null) { + bottom.layout(bRect.left, bRect.top, bRect.right, bRect.bottom); + } } if (notify) { dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom); @@ -1352,44 +1408,17 @@ public void open(boolean smooth, boolean notify) { } public void open(DragEdge edge) { - switch (edge) { - case Left: - mCurrentDirectionIndex = mLeftIndex; - case Right: - mCurrentDirectionIndex = mRightIndex; - case Top: - mCurrentDirectionIndex = mTopIndex; - case Bottom: - mCurrentDirectionIndex = mBottomIndex; - } + setCurrentDragEdge(edge); 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; - } + setCurrentDragEdge(edge); 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; - } + setCurrentDragEdge(edge); open(smooth, notify); } @@ -1411,7 +1440,10 @@ public void close(boolean smooth) { * @param notify if notify all the listeners. */ public void close(boolean smooth, boolean notify) { - ViewGroup surface = getSurfaceView(); + View surface = getSurfaceView(); + if (surface == null) { + return; + } int dx, dy; if (smooth) mDragHelper.smoothSlideViewTo(getSurfaceView(), getPaddingLeft(), getPaddingTop()); @@ -1440,20 +1472,20 @@ public void toggle(boolean 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) { int l = getPaddingLeft(), t = getPaddingTop(); if (open) { - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) + if (mCurrentDragEdge == DragEdge.Left) l = getPaddingLeft() + mDragDistance; - else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + else if (mCurrentDragEdge == DragEdge.Right) l = getPaddingLeft() - mDragDistance; - else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) + else if (mCurrentDragEdge == DragEdge.Top) t = getPaddingTop() + mDragDistance; else t = getPaddingTop() - mDragDistance; } @@ -1462,30 +1494,31 @@ else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) 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 (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) + if (mCurrentDragEdge == DragEdge.Left) bl = rect.left - mDragDistance; - else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + else if (mCurrentDragEdge == DragEdge.Right) bl = rect.right; - else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) + else if (mCurrentDragEdge == DragEdge.Top) bt = rect.top - mDragDistance; else bt = rect.bottom; - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) { + if (mCurrentDragEdge == DragEdge.Left || mCurrentDragEdge == DragEdge.Right) { bb = rect.bottom; - br = bl + getBottomViews().get(mCurrentDirectionIndex).getMeasuredWidth(); + br = bl + (bottomView == null ? 0 : bottomView.getMeasuredWidth()); } else { - bb = bt + getBottomViews().get(mCurrentDirectionIndex).getMeasuredHeight(); + bb = bt + (bottomView == null ? 0 : bottomView.getMeasuredHeight()); br = rect.right; } } else if (mode == ShowMode.LayDown) { - if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) + if (mCurrentDragEdge == DragEdge.Left) br = bl + mDragDistance; - else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) + else if (mCurrentDragEdge == DragEdge.Right) bl = br - mDragDistance; - else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) + else if (mCurrentDragEdge == DragEdge.Top) bb = bt + mDragDistance; else bt = bb - mDragDistance; @@ -1517,63 +1550,111 @@ public void setOnDoubleClickListener(DoubleClickListener doubleClickListener) { } public interface DoubleClickListener { - public void onDoubleClick(SwipeLayout layout, boolean surface); + void onDoubleClick(SwipeLayout layout, boolean surface); } private int dp2px(float dp) { return (int) (dp * getContext().getResources().getDisplayMetrics().density + 0.5f); } - public List getDragEdges() { + + /** + * Deprecated, use {@link #setDrag(DragEdge, View)} + */ + @Deprecated + public void setDragEdge(DragEdge dragEdge) { + clearDragEdge(); + if (getChildCount() >= 2) { + mDragEdges.put(dragEdge, getChildAt(getChildCount() - 2)); + } + setCurrentDragEdge(dragEdge); + } + + public void onViewRemoved(View child) { + for (Map.Entry entry : new HashMap(mDragEdges).entrySet()) { + if (entry.getValue() == child) { + mDragEdges.remove(entry.getKey()); + } + } + } + + public Map getDragEdgeMap() { return mDragEdges; } - public void setDragEdges(List mDragEdges) { - this.mDragEdges = mDragEdges; - mCurrentDirectionIndex = 0; - populateIndexes(); - updateBottomViews(); + /** + * Deprecated, use {@link #getDragEdgeMap()} + */ + @Deprecated + public List getDragEdges() { + return new ArrayList(mDragEdges.keySet()); } - public void setDragEdges(DragEdge... mDragEdges) { - this.mDragEdges = new ArrayList(); - for (DragEdge e : mDragEdges) { - this.mDragEdges.add(e); + /** + * Deprecated, use {@link #setDrag(DragEdge, View)} + */ + @Deprecated + public void setDragEdges(List 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)); } - mCurrentDirectionIndex = 0; - populateIndexes(); - updateBottomViews(); + if (dragEdges.size() == 0 || dragEdges.contains(DefaultDragEdge)) { + setCurrentDragEdge(DefaultDragEdge); + } else { + setCurrentDragEdge(dragEdges.get(0)); + } + } + + /** + * Deprecated, use {@link #addDrag(DragEdge, View)} + */ + @Deprecated + public void setDragEdges(DragEdge... mDragEdges) { + clearDragEdge(); + setDragEdges(Arrays.asList(mDragEdges)); } - 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); + /** + * 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) + */ + @Deprecated + public 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 (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; + if (mCurrentDragEdge == null) return 0; + return mEdgeSwipesOffset[mCurrentDragEdge.ordinal()]; + } + + private void setCurrentDragEdge(DragEdge dragEdge) { + mCurrentDragEdge = dragEdge; + updateBottomViews(); } private void updateBottomViews() { -// removeAllViews(); -// addView(getBottomViews().get(mCurrentDirectionIndex)); -// addView(getSurfaceView()); -// getBottomViews().get(mCurrentDirectionIndex).bringToFront(); -// getSurfaceView().bringToFront(); - if (mShowMode == ShowMode.PullOut) + 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(); + } 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/java/com/daimajia/swipe/adapters/ArraySwipeAdapter.java b/library/src/main/java/com/daimajia/swipe/adapters/ArraySwipeAdapter.java index 3912e724..9475ff59 100644 --- a/library/src/main/java/com/daimajia/swipe/adapters/ArraySwipeAdapter.java +++ b/library/src/main/java/com/daimajia/swipe/adapters/ArraySwipeAdapter.java @@ -6,7 +6,6 @@ import android.widget.ArrayAdapter; import com.daimajia.swipe.SwipeLayout; -import com.daimajia.swipe.implments.SwipeItemAdapterMangerImpl; import com.daimajia.swipe.implments.SwipeItemMangerImpl; import com.daimajia.swipe.interfaces.SwipeAdapterInterface; import com.daimajia.swipe.interfaces.SwipeItemMangerInterface; @@ -14,9 +13,9 @@ import java.util.List; -public abstract class ArraySwipeAdapter extends ArrayAdapter implements SwipeItemMangerInterface,SwipeAdapterInterface { +public abstract class ArraySwipeAdapter extends ArrayAdapter implements SwipeItemMangerInterface, SwipeAdapterInterface { - private SwipeItemAdapterMangerImpl mItemManger = new SwipeItemAdapterMangerImpl(this); + private SwipeItemMangerImpl mItemManger = new SwipeItemMangerImpl(this); {} public ArraySwipeAdapter(Context context, int resource) { super(context, resource); @@ -42,15 +41,15 @@ public ArraySwipeAdapter(Context context, int resource, int textViewResourceId, super(context, resource, textViewResourceId, objects); } + @Override + public void notifyDatasetChanged() { + super.notifyDataSetChanged(); + } + @Override public View getView(int position, View convertView, ViewGroup parent) { - boolean convertViewIsNull = convertView == null; View v = super.getView(position, convertView, parent); - if(convertViewIsNull){ - mItemManger.initialize(v, position); - }else{ - mItemManger.updateConvertView(v, position); - } + mItemManger.bind(v, position); return v; } diff --git a/library/src/main/java/com/daimajia/swipe/adapters/BaseSwipeAdapter.java b/library/src/main/java/com/daimajia/swipe/adapters/BaseSwipeAdapter.java index b7fb1aeb..bf72c9a9 100644 --- a/library/src/main/java/com/daimajia/swipe/adapters/BaseSwipeAdapter.java +++ b/library/src/main/java/com/daimajia/swipe/adapters/BaseSwipeAdapter.java @@ -5,9 +5,8 @@ import android.widget.BaseAdapter; import com.daimajia.swipe.SwipeLayout; -import com.daimajia.swipe.implments.SwipeItemAdapterMangerImpl; -import com.daimajia.swipe.interfaces.SwipeAdapterInterface; import com.daimajia.swipe.implments.SwipeItemMangerImpl; +import com.daimajia.swipe.interfaces.SwipeAdapterInterface; import com.daimajia.swipe.interfaces.SwipeItemMangerInterface; import com.daimajia.swipe.util.Attributes; @@ -15,7 +14,7 @@ public abstract class BaseSwipeAdapter extends BaseAdapter implements SwipeItemMangerInterface, SwipeAdapterInterface { - protected SwipeItemAdapterMangerImpl mItemManger = new SwipeItemAdapterMangerImpl(this); + protected SwipeItemMangerImpl mItemManger = new SwipeItemMangerImpl(this); /** * return the {@link com.daimajia.swipe.SwipeLayout} resource id, int the view item. @@ -42,16 +41,19 @@ public abstract class BaseSwipeAdapter extends BaseAdapter implements SwipeItemM */ public abstract void fillValues(int position, View convertView); + @Override + public void notifyDatasetChanged() { + super.notifyDataSetChanged(); + } + @Override public final View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if(v == null){ v = generateView(position, parent); - mItemManger.initialize(v, position); - }else{ - mItemManger.updateConvertView(v, position); } + mItemManger.bind(v, position); fillValues(position, v); return v; } diff --git a/library/src/main/java/com/daimajia/swipe/adapters/CursorSwipeAdapter.java b/library/src/main/java/com/daimajia/swipe/adapters/CursorSwipeAdapter.java index 0bde0e8c..3e6a62c7 100644 --- a/library/src/main/java/com/daimajia/swipe/adapters/CursorSwipeAdapter.java +++ b/library/src/main/java/com/daimajia/swipe/adapters/CursorSwipeAdapter.java @@ -7,9 +7,8 @@ import android.view.ViewGroup; import com.daimajia.swipe.SwipeLayout; -import com.daimajia.swipe.implments.SwipeItemAdapterMangerImpl; -import com.daimajia.swipe.interfaces.SwipeAdapterInterface; import com.daimajia.swipe.implments.SwipeItemMangerImpl; +import com.daimajia.swipe.interfaces.SwipeAdapterInterface; import com.daimajia.swipe.interfaces.SwipeItemMangerInterface; import com.daimajia.swipe.util.Attributes; @@ -17,7 +16,7 @@ public abstract class CursorSwipeAdapter extends CursorAdapter implements SwipeItemMangerInterface, SwipeAdapterInterface { - private SwipeItemAdapterMangerImpl mItemManger = new SwipeItemAdapterMangerImpl(this); + private SwipeItemMangerImpl mItemManger = new SwipeItemMangerImpl(this); protected CursorSwipeAdapter(Context context, Cursor c, boolean autoRequery) { super(context, c, autoRequery); @@ -29,13 +28,8 @@ protected CursorSwipeAdapter(Context context, Cursor c, int flags) { @Override public View getView(int position, View convertView, ViewGroup parent) { - boolean convertViewIsNull = convertView == null; View v = super.getView(position, convertView, parent); - if(convertViewIsNull){ - mItemManger.initialize(v, position); - }else{ - mItemManger.updateConvertView(v, position); - } + mItemManger.bind(v, position); return v; } @@ -54,6 +48,11 @@ public void closeAllExcept(SwipeLayout layout) { mItemManger.closeAllExcept(layout); } + @Override + public void closeAllItems() { + mItemManger.closeAllItems(); + } + @Override public List getOpenItems() { return mItemManger.getOpenItems(); diff --git a/library/src/main/java/com/daimajia/swipe/adapters/RecyclerSwipeAdapter.java b/library/src/main/java/com/daimajia/swipe/adapters/RecyclerSwipeAdapter.java index e68de7f9..f6e9aed3 100644 --- a/library/src/main/java/com/daimajia/swipe/adapters/RecyclerSwipeAdapter.java +++ b/library/src/main/java/com/daimajia/swipe/adapters/RecyclerSwipeAdapter.java @@ -4,7 +4,7 @@ import android.view.ViewGroup; import com.daimajia.swipe.SwipeLayout; -import com.daimajia.swipe.implments.SwipeItemRecyclerMangerImpl; +import com.daimajia.swipe.implments.SwipeItemMangerImpl; import com.daimajia.swipe.interfaces.SwipeAdapterInterface; import com.daimajia.swipe.interfaces.SwipeItemMangerInterface; import com.daimajia.swipe.util.Attributes; @@ -13,7 +13,7 @@ public abstract class RecyclerSwipeAdapter extends RecyclerView.Adapter implements SwipeItemMangerInterface, SwipeAdapterInterface { - public SwipeItemRecyclerMangerImpl mItemManger = new SwipeItemRecyclerMangerImpl(this); + public SwipeItemMangerImpl mItemManger = new SwipeItemMangerImpl(this); @Override public abstract VH onCreateViewHolder(ViewGroup parent, int viewType); @@ -21,6 +21,11 @@ public abstract class RecyclerSwipeAdapter e @Override public abstract void onBindViewHolder(VH viewHolder, final int position); + @Override + public void notifyDatasetChanged() { + super.notifyDataSetChanged(); + } + @Override public void openItem(int position) { mItemManger.openItem(position); diff --git a/library/src/main/java/com/daimajia/swipe/adapters/SimpleCursorSwipeAdapter.java b/library/src/main/java/com/daimajia/swipe/adapters/SimpleCursorSwipeAdapter.java index 75fbe0c7..19b04ad2 100644 --- a/library/src/main/java/com/daimajia/swipe/adapters/SimpleCursorSwipeAdapter.java +++ b/library/src/main/java/com/daimajia/swipe/adapters/SimpleCursorSwipeAdapter.java @@ -7,7 +7,6 @@ import android.view.ViewGroup; import com.daimajia.swipe.SwipeLayout; -import com.daimajia.swipe.implments.SwipeItemAdapterMangerImpl; import com.daimajia.swipe.implments.SwipeItemMangerImpl; import com.daimajia.swipe.interfaces.SwipeAdapterInterface; import com.daimajia.swipe.interfaces.SwipeItemMangerInterface; @@ -17,7 +16,7 @@ public abstract class SimpleCursorSwipeAdapter extends SimpleCursorAdapter implements SwipeItemMangerInterface, SwipeAdapterInterface { - private SwipeItemAdapterMangerImpl mItemManger = new SwipeItemAdapterMangerImpl(this); + private SwipeItemMangerImpl mItemManger = new SwipeItemMangerImpl(this); protected SimpleCursorSwipeAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) { super(context, layout, c, from, to, flags); @@ -29,13 +28,8 @@ protected SimpleCursorSwipeAdapter(Context context, int layout, Cursor c, String @Override public View getView(int position, View convertView, ViewGroup parent) { - boolean convertViewIsNull = convertView == null; View v = super.getView(position, convertView, parent); - if(convertViewIsNull){ - mItemManger.initialize(v, position); - }else{ - mItemManger.updateConvertView(v, position); - } + mItemManger.bind(v, position); return v; } diff --git a/library/src/main/java/com/daimajia/swipe/implments/SwipeItemAdapterMangerImpl.java b/library/src/main/java/com/daimajia/swipe/implments/SwipeItemAdapterMangerImpl.java deleted file mode 100644 index de3a570f..00000000 --- a/library/src/main/java/com/daimajia/swipe/implments/SwipeItemAdapterMangerImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.daimajia.swipe.implments; - -import android.view.View; -import android.widget.BaseAdapter; - -import com.daimajia.swipe.SimpleSwipeListener; -import com.daimajia.swipe.SwipeLayout; -import com.daimajia.swipe.interfaces.SwipeAdapterInterface; -import com.daimajia.swipe.interfaces.SwipeItemMangerInterface; -import com.daimajia.swipe.util.Attributes; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * SwipeItemMangerImpl is a helper class to help all the adapters to maintain open status. - */ -public class SwipeItemAdapterMangerImpl extends SwipeItemMangerImpl{ - - protected BaseAdapter mAdapter; - - public SwipeItemAdapterMangerImpl(BaseAdapter adapter) { - super(adapter); - this.mAdapter = adapter; - } - - @Override - public void initialize(View target, int position) { - int resId = getSwipeLayoutId(position); - - OnLayoutListener onLayoutListener = new OnLayoutListener(position); - SwipeLayout swipeLayout = (SwipeLayout) target.findViewById(resId); - if (swipeLayout == null) - throw new IllegalStateException("can not find SwipeLayout in target view"); - - SwipeMemory swipeMemory = new SwipeMemory(position); - swipeLayout.addSwipeListener(swipeMemory); - swipeLayout.addOnLayoutListener(onLayoutListener); - swipeLayout.setTag(resId, new ValueBox(position, swipeMemory, onLayoutListener)); - - mShownLayouts.add(swipeLayout); - } - - @Override - public void updateConvertView(View target, int position) { - int resId = getSwipeLayoutId(position); - - SwipeLayout swipeLayout = (SwipeLayout) target.findViewById(resId); - if (swipeLayout == null) - throw new IllegalStateException("can not find SwipeLayout in target view"); - - ValueBox valueBox = (ValueBox) swipeLayout.getTag(resId); - valueBox.swipeMemory.setPosition(position); - valueBox.onLayoutListener.setPosition(position); - valueBox.position = position; - } - - @Override - public void bindView(View target, int position){ - - } - -} diff --git a/library/src/main/java/com/daimajia/swipe/implments/SwipeItemMangerImpl.java b/library/src/main/java/com/daimajia/swipe/implments/SwipeItemMangerImpl.java index e4a330e5..989849c1 100644 --- a/library/src/main/java/com/daimajia/swipe/implments/SwipeItemMangerImpl.java +++ b/library/src/main/java/com/daimajia/swipe/implments/SwipeItemMangerImpl.java @@ -1,8 +1,6 @@ package com.daimajia.swipe.implments; -import android.support.v7.widget.RecyclerView; import android.view.View; -import android.widget.BaseAdapter; import com.daimajia.swipe.SimpleSwipeListener; import com.daimajia.swipe.SwipeLayout; @@ -11,7 +9,7 @@ import com.daimajia.swipe.util.Attributes; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -19,7 +17,7 @@ /** * SwipeItemMangerImpl is a helper class to help all the adapters to maintain open status. */ -public abstract class SwipeItemMangerImpl implements SwipeItemMangerInterface { +public class SwipeItemMangerImpl implements SwipeItemMangerInterface { private Attributes.Mode mode = Attributes.Mode.Single; public final int INVALID_POSITION = -1; @@ -29,27 +27,13 @@ public abstract class SwipeItemMangerImpl implements SwipeItemMangerInterface { protected Set mOpenPositions = new HashSet(); protected Set mShownLayouts = new HashSet(); - protected BaseAdapter mBaseAdapter; - protected RecyclerView.Adapter mRecyclerAdapter; + protected SwipeAdapterInterface swipeAdapterInterface; - public SwipeItemMangerImpl(BaseAdapter adapter) { - if (adapter == null) - throw new IllegalArgumentException("Adapter can not be null"); + public SwipeItemMangerImpl(SwipeAdapterInterface swipeAdapterInterface) { + if (swipeAdapterInterface == null) + throw new IllegalArgumentException("SwipeAdapterInterface can not be null"); - if (!(adapter instanceof SwipeItemMangerInterface)) - throw new IllegalArgumentException("adapter should implement the SwipeAdapterInterface"); - - this.mBaseAdapter = adapter; - } - - public SwipeItemMangerImpl(RecyclerView.Adapter adapter) { - if (adapter == null) - throw new IllegalArgumentException("Adapter can not be null"); - - if (!(adapter instanceof SwipeItemMangerInterface)) - throw new IllegalArgumentException("adapter should implement the SwipeAdapterInterface"); - - this.mRecyclerAdapter = adapter; + this.swipeAdapterInterface = swipeAdapterInterface; } public Attributes.Mode getMode() { @@ -63,21 +47,24 @@ public void setMode(Attributes.Mode mode) { mOpenPosition = INVALID_POSITION; } - /* initialize and updateConvertView used for AdapterManagerImpl */ - public abstract void initialize(View target, int position); + public void bind(View view, int position) { + int resId = swipeAdapterInterface.getSwipeLayoutResourceId(position); + SwipeLayout swipeLayout = (SwipeLayout) view.findViewById(resId); + if (swipeLayout == null) + throw new IllegalStateException("can not find SwipeLayout in target view"); - public abstract void updateConvertView(View target, int position); - - /* bindView used for RecyclerViewManagerImpl */ - public abstract void bindView(View target, int position); - - public int getSwipeLayoutId(int position) { - if (mBaseAdapter != null) { - return ((SwipeAdapterInterface) (mBaseAdapter)).getSwipeLayoutResourceId(position); - } else if (mRecyclerAdapter != null) { - return ((SwipeAdapterInterface) (mRecyclerAdapter)).getSwipeLayoutResourceId(position); + if (swipeLayout.getTag(resId) == null) { + OnLayoutListener onLayoutListener = new OnLayoutListener(position); + SwipeMemory swipeMemory = new SwipeMemory(position); + swipeLayout.addSwipeListener(swipeMemory); + swipeLayout.addOnLayoutListener(onLayoutListener); + swipeLayout.setTag(resId, new ValueBox(position, swipeMemory, onLayoutListener)); + mShownLayouts.add(swipeLayout); } else { - return -1; + ValueBox valueBox = (ValueBox) swipeLayout.getTag(resId); + valueBox.swipeMemory.setPosition(position); + valueBox.onLayoutListener.setPosition(position); + valueBox.position = position; } } @@ -89,11 +76,7 @@ public void openItem(int position) { } else { mOpenPosition = position; } - if (mBaseAdapter != null) { - mBaseAdapter.notifyDataSetChanged(); - } else if (mRecyclerAdapter != null) { - mRecyclerAdapter.notifyDataSetChanged(); - } + swipeAdapterInterface.notifyDatasetChanged(); } @Override @@ -104,11 +87,7 @@ public void closeItem(int position) { if (mOpenPosition == position) mOpenPosition = INVALID_POSITION; } - if (mBaseAdapter != null) { - mBaseAdapter.notifyDataSetChanged(); - } else if (mRecyclerAdapter != null) { - mRecyclerAdapter.notifyDataSetChanged(); - } + swipeAdapterInterface.notifyDatasetChanged(); } @Override @@ -141,7 +120,7 @@ public List getOpenItems() { if (mode == Attributes.Mode.Multiple) { return new ArrayList(mOpenPositions); } else { - return Arrays.asList(mOpenPosition); + return Collections.singletonList(mOpenPosition); } } diff --git a/library/src/main/java/com/daimajia/swipe/implments/SwipeItemRecyclerMangerImpl.java b/library/src/main/java/com/daimajia/swipe/implments/SwipeItemRecyclerMangerImpl.java deleted file mode 100644 index 97cd7257..00000000 --- a/library/src/main/java/com/daimajia/swipe/implments/SwipeItemRecyclerMangerImpl.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.daimajia.swipe.implments; - -import android.support.v7.widget.RecyclerView; -import android.view.View; - -import com.daimajia.swipe.SimpleSwipeListener; -import com.daimajia.swipe.SwipeLayout; -import com.daimajia.swipe.interfaces.SwipeAdapterInterface; -import com.daimajia.swipe.interfaces.SwipeItemMangerInterface; -import com.daimajia.swipe.util.Attributes; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * SwipeItemRecyclerMangerImpl is a helper class to help the RecyclerView to maintain open status. - */ -public class SwipeItemRecyclerMangerImpl extends SwipeItemMangerImpl{ - - protected RecyclerView.Adapter mAdapter; - - public SwipeItemRecyclerMangerImpl(RecyclerView.Adapter adapter) { - super(adapter); - this.mAdapter = adapter; - } - - @Override - public void bindView(View target, int position) { - int resId = getSwipeLayoutId(position); - - OnLayoutListener onLayoutListener = new OnLayoutListener(position); - SwipeLayout swipeLayout = (SwipeLayout) target.findViewById(resId); - if (swipeLayout == null) - throw new IllegalStateException("can not find SwipeLayout in target view"); - - if (swipeLayout.getTag(resId) == null) { - SwipeMemory swipeMemory = new SwipeMemory(position); - swipeLayout.addSwipeListener(swipeMemory); - swipeLayout.addOnLayoutListener(onLayoutListener); - swipeLayout.setTag(resId, new ValueBox(position, swipeMemory, onLayoutListener)); - mShownLayouts.add(swipeLayout); - } else { - ValueBox valueBox = (ValueBox) swipeLayout.getTag(resId); - valueBox.swipeMemory.setPosition(position); - valueBox.onLayoutListener.setPosition(position); - valueBox.position = position; - } - } - - @Override - public void initialize(View target, int position) { - - } - - @Override - public void updateConvertView(View target, int position) { - - } - -} diff --git a/library/src/main/java/com/daimajia/swipe/interfaces/SwipeAdapterInterface.java b/library/src/main/java/com/daimajia/swipe/interfaces/SwipeAdapterInterface.java index 4b47fa20..9d0a7701 100644 --- a/library/src/main/java/com/daimajia/swipe/interfaces/SwipeAdapterInterface.java +++ b/library/src/main/java/com/daimajia/swipe/interfaces/SwipeAdapterInterface.java @@ -1,5 +1,9 @@ package com.daimajia.swipe.interfaces; public interface SwipeAdapterInterface { - public int getSwipeLayoutResourceId(int position); + + int getSwipeLayoutResourceId(int position); + + void notifyDatasetChanged(); + } diff --git a/library/src/main/java/com/daimajia/swipe/interfaces/SwipeItemMangerInterface.java b/library/src/main/java/com/daimajia/swipe/interfaces/SwipeItemMangerInterface.java index b03f4a38..b9dd337b 100644 --- a/library/src/main/java/com/daimajia/swipe/interfaces/SwipeItemMangerInterface.java +++ b/library/src/main/java/com/daimajia/swipe/interfaces/SwipeItemMangerInterface.java @@ -1,30 +1,29 @@ package com.daimajia.swipe.interfaces; import com.daimajia.swipe.SwipeLayout; -import com.daimajia.swipe.implments.SwipeItemMangerImpl; import com.daimajia.swipe.util.Attributes; import java.util.List; public interface SwipeItemMangerInterface { - public void openItem(int position); + void openItem(int position); - public void closeItem(int position); + void closeItem(int position); - public void closeAllExcept(SwipeLayout layout); + void closeAllExcept(SwipeLayout layout); - public void closeAllItems(); + void closeAllItems(); - public List getOpenItems(); + List getOpenItems(); - public List getOpenLayouts(); + List getOpenLayouts(); - public void removeShownLayouts(SwipeLayout layout); + void removeShownLayouts(SwipeLayout layout); - public boolean isOpen(int position); + boolean isOpen(int position); - public Attributes.Mode getMode(); + Attributes.Mode getMode(); - public void setMode(Attributes.Mode mode); + void setMode(Attributes.Mode mode); } diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index 249b944e..a671fc5f 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -15,5 +15,6 @@ + \ No newline at end of file