├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ ├── colors.xml
│ │ │ ├── attrs.xml
│ │ │ └── styles.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── drawable
│ │ │ ├── ic_edit.xml
│ │ │ ├── ic_info_outline.xml
│ │ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ │ ├── activity_main.xml
│ │ │ └── list_item_main.xml
│ │ └── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── me
│ │ └── markosullivan
│ │ └── swiperevealactionbuttons
│ │ ├── MainActivity.java
│ │ ├── MainListAdapter.java
│ │ └── SwipeRevealLayout.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── README.md
├── Contribute.md
├── gradle.properties
├── LICENSE.txt
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SwipeRevealActionButtons
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkOSullivan94/SwipeRevealLayoutExample/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 | /.idea
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SwipeRevealLayoutExample #
2 |
3 | Example of how to implement swipeable RecyclerView items in your Android app.
4 |
5 |
6 | 
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Feb 25 19:31:50 GMT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Contribute.md:
--------------------------------------------------------------------------------
1 | I have added Swipe lock enable disable feature for particular list item programmatically.
2 |
3 | Added a new method DragLock() in SwipeRevealLayout class.
4 |
5 | We can enable disable Swipe by calling above methods like this from adapter class.
6 |
7 | viewHolder.mSwipeRevealLayout.dragLock(false); or viewHolder.mSwipeRevealLayout.dragLock(true);
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_edit.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info_outline.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Mark O'Sullivan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 | applicationId "me.markosullivan.swiperevealactionbuttons"
7 | minSdkVersion 21
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | implementation 'com.android.support:appcompat-v7:27.0.2'
24 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
25 | implementation "com.android.support:recyclerview-v7:27.0.2"
26 | implementation "com.android.support:cardview-v7:27.0.2"
27 | testImplementation 'junit:junit:4.12'
28 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
29 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/me/markosullivan/swiperevealactionbuttons/MainActivity.java:
--------------------------------------------------------------------------------
1 | package me.markosullivan.swiperevealactionbuttons;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.support.v7.widget.LinearLayoutManager;
6 | import android.support.v7.widget.RecyclerView;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * Created by Mark O'Sullivan on 25th February 2018.
13 | */
14 | public class MainActivity extends AppCompatActivity {
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.activity_main);
20 | RecyclerView recyclerView = findViewById(R.id.recycler_view);
21 | RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
22 | recyclerView.setLayoutManager(layoutManager);
23 | MainListAdapter mainListAdapter = new MainListAdapter(getMealList());
24 | recyclerView.setAdapter(mainListAdapter);
25 | }
26 |
27 | public List getMealList() {
28 | List mealList = new ArrayList<>();
29 | mealList.add("Green Thai Curry");
30 | mealList.add("Granola");
31 | mealList.add("Poached Eggs");
32 | mealList.add("Spaghetti");
33 | mealList.add("Apple Pie");
34 | mealList.add("Grilled Cheese Sandwich");
35 | mealList.add("Vegetable Soup");
36 | mealList.add("Chicken Noodles");
37 | mealList.add("Fajitas");
38 | mealList.add("Chicken Pot Pie");
39 | mealList.add("Pasta and cauliflower casserole with chicken");
40 | mealList.add("Vegetable stir-fry");
41 | mealList.add("Sweet potato and orange soup");
42 | mealList.add("Vegetable Broth");
43 | return mealList;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/me/markosullivan/swiperevealactionbuttons/MainListAdapter.java:
--------------------------------------------------------------------------------
1 | package me.markosullivan.swiperevealactionbuttons;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ImageButton;
8 | import android.widget.TextView;
9 | import android.widget.Toast;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * Created by Mark O'Sullivan on 25th February 2018.
15 | */
16 |
17 | public class MainListAdapter extends RecyclerView.Adapter {
18 |
19 | private List shoppingList;
20 |
21 | public MainListAdapter(List shoppingList) {
22 | this.shoppingList = shoppingList;
23 | }
24 |
25 | @Override
26 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
27 | View view = LayoutInflater.from(parent.getContext())
28 | .inflate(R.layout.list_item_main, parent, false);
29 | return new MainListItem(view);
30 | }
31 |
32 | @Override
33 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
34 | MainListItem mainListItem = (MainListItem) holder;
35 | mainListItem.mealTV.setText(shoppingList.get(position));
36 | mainListItem.infoButton.setOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View v) {
39 | Toast.makeText(v.getContext(), "INFO CLICKED", Toast.LENGTH_SHORT).show();
40 | }
41 | });
42 | mainListItem.editButton.setOnClickListener(new View.OnClickListener() {
43 | @Override
44 | public void onClick(View v) {
45 | Toast.makeText(v.getContext(), "EDIT CLICKED", Toast.LENGTH_SHORT).show();
46 | }
47 | });
48 | }
49 |
50 | @Override
51 | public int getItemCount() {
52 | return shoppingList.size();
53 | }
54 |
55 | public static class MainListItem extends RecyclerView.ViewHolder {
56 |
57 | protected TextView mealTV;
58 | protected ImageButton infoButton;
59 | protected ImageButton editButton;
60 |
61 | protected MainListItem(View itemView) {
62 | super(itemView);
63 | mealTV = itemView.findViewById(R.id.meal_tv);
64 | infoButton = itemView.findViewById(R.id.info_button);
65 | editButton= itemView.findViewById(R.id.edit_button);
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
14 |
21 |
22 |
28 |
29 |
35 |
36 |
37 |
38 |
39 |
43 |
44 |
53 |
54 |
59 |
60 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/java/me/markosullivan/swiperevealactionbuttons/SwipeRevealLayout.java:
--------------------------------------------------------------------------------
1 | package me.markosullivan.swiperevealactionbuttons;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.res.Resources;
6 | import android.content.res.TypedArray;
7 | import android.graphics.Rect;
8 | import android.os.Bundle;
9 | import android.os.Parcelable;
10 | import android.support.annotation.Nullable;
11 | import android.support.v4.view.GestureDetectorCompat;
12 | import android.support.v4.view.ViewCompat;
13 | import android.support.v4.widget.ViewDragHelper;
14 | import android.util.AttributeSet;
15 | import android.util.DisplayMetrics;
16 | import android.view.GestureDetector;
17 | import android.view.MotionEvent;
18 | import android.view.View;
19 | import android.view.ViewGroup;
20 |
21 | /**
22 | * Created by Mark O'Sullivan on 25th February 2018.
23 | */
24 |
25 | @SuppressLint("RtlHardcoded")
26 | public class SwipeRevealLayout extends ViewGroup {
27 |
28 | private static final String SUPER_INSTANCE_STATE = "saved_instance_state_parcelable";
29 |
30 | private static final int DEFAULT_MIN_FLING_VELOCITY = 300; // dp per second
31 | private static final int DEFAULT_MIN_DIST_REQUEST_DISALLOW_PARENT = 1; // dp
32 |
33 | public static final int DRAG_EDGE_LEFT = 0x1;
34 | public static final int DRAG_EDGE_RIGHT = 0x1 << 1;
35 |
36 | /**
37 | * The secondary view will be under the main view.
38 | */
39 | public static final int MODE_NORMAL = 0;
40 |
41 | /**
42 | * The secondary view will stick the edge of the main view.
43 | */
44 | public static final int MODE_SAME_LEVEL = 1;
45 |
46 | /**
47 | * Main view is the view which is shown when the layout is closed.
48 | */
49 | private View mMainView;
50 |
51 | /**
52 | * Secondary view is the view which is shown when the layout is opened.
53 | */
54 | private View mSecondaryView;
55 |
56 | /**
57 | * The rectangle position of the main view when the layout is closed.
58 | */
59 | private Rect mRectMainClose = new Rect();
60 |
61 | /**
62 | * The rectangle position of the main view when the layout is opened.
63 | */
64 | private Rect mRectMainOpen = new Rect();
65 |
66 | /**
67 | * The rectangle position of the secondary view when the layout is closed.
68 | */
69 | private Rect mRectSecClose = new Rect();
70 |
71 | /**
72 | * The rectangle position of the secondary view when the layout is opened.
73 | */
74 | private Rect mRectSecOpen = new Rect();
75 |
76 | /**
77 | * The minimum distance (px) to the closest drag edge that the SwipeRevealLayout
78 | * will disallow the parent to intercept touch event.
79 | */
80 | private int mMinDistRequestDisallowParent = 0;
81 |
82 | private boolean mIsOpenBeforeInit = false;
83 | private volatile boolean mIsScrolling = false;
84 | private volatile boolean mLockDrag = false;
85 |
86 | private int mMinFlingVelocity = DEFAULT_MIN_FLING_VELOCITY;
87 | private int mMode = MODE_NORMAL;
88 |
89 | private int mDragEdge = DRAG_EDGE_LEFT;
90 |
91 | private float mDragDist = 0;
92 | private float mPrevX = -1;
93 |
94 | private ViewDragHelper mDragHelper;
95 | private GestureDetectorCompat mGestureDetector;
96 |
97 | public SwipeRevealLayout(Context context) {
98 | super(context);
99 | init(context, null);
100 | }
101 |
102 | public SwipeRevealLayout(Context context, AttributeSet attrs) {
103 | super(context, attrs);
104 | init(context, attrs);
105 | }
106 |
107 | public SwipeRevealLayout(Context context, AttributeSet attrs, int defStyleAttr) {
108 | super(context, attrs, defStyleAttr);
109 | }
110 |
111 | @Nullable
112 | @Override
113 | protected Parcelable onSaveInstanceState() {
114 | Bundle bundle = new Bundle();
115 | bundle.putParcelable(SUPER_INSTANCE_STATE, super.onSaveInstanceState());
116 | return super.onSaveInstanceState();
117 | }
118 |
119 | @Override
120 | protected void onRestoreInstanceState(Parcelable state) {
121 | Bundle bundle = (Bundle) state;
122 | state = bundle.getParcelable(SUPER_INSTANCE_STATE);
123 | super.onRestoreInstanceState(state);
124 | }
125 |
126 | @Override
127 | public boolean onTouchEvent(MotionEvent event) {
128 | mGestureDetector.onTouchEvent(event);
129 | mDragHelper.processTouchEvent(event);
130 | return true;
131 | }
132 |
133 | @Override
134 | public boolean onInterceptTouchEvent(MotionEvent ev) {
135 | if (isDragLocked()) {
136 | return super.onInterceptTouchEvent(ev);
137 | }
138 |
139 | mDragHelper.processTouchEvent(ev);
140 | mGestureDetector.onTouchEvent(ev);
141 | accumulateDragDist(ev);
142 |
143 | boolean couldBecomeClick = couldBecomeClick(ev);
144 | boolean settling = mDragHelper.getViewDragState() == ViewDragHelper.STATE_SETTLING;
145 | boolean idleAfterScrolled = mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE
146 | && mIsScrolling;
147 |
148 | // must be placed as the last statement
149 | mPrevX = ev.getX();
150 |
151 | // return true => intercept, cannot trigger onClick event
152 | return !couldBecomeClick && (settling || idleAfterScrolled);
153 | }
154 |
155 | @Override
156 | protected void onFinishInflate() {
157 | super.onFinishInflate();
158 |
159 | // get views
160 | if (getChildCount() >= 2) {
161 | mSecondaryView = getChildAt(0);
162 | mMainView = getChildAt(1);
163 | }
164 | else if (getChildCount() == 1) {
165 | mMainView = getChildAt(0);
166 | }
167 | }
168 |
169 | /**
170 | * {@inheritDoc}
171 | */
172 | @SuppressWarnings("ConstantConditions")
173 | @Override
174 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
175 | for (int index = 0; index < getChildCount(); index++) {
176 | final View child = getChildAt(index);
177 |
178 | int left, right, top, bottom;
179 | left = right = top = bottom = 0;
180 |
181 | final int minLeft = getPaddingLeft();
182 | final int maxRight = Math.max(r - getPaddingRight() - l, 0);
183 | final int minTop = getPaddingTop();
184 | final int maxBottom = Math.max(b - getPaddingBottom() - t, 0);
185 |
186 | int measuredChildHeight = child.getMeasuredHeight();
187 | int measuredChildWidth = child.getMeasuredWidth();
188 |
189 | // need to take account if child size is match_parent
190 | final LayoutParams childParams = child.getLayoutParams();
191 | boolean matchParentHeight = false;
192 | boolean matchParentWidth = false;
193 |
194 | if (childParams != null) {
195 | matchParentHeight = (childParams.height == LayoutParams.MATCH_PARENT) ||
196 | (childParams.height == LayoutParams.FILL_PARENT);
197 | matchParentWidth = (childParams.width == LayoutParams.MATCH_PARENT) ||
198 | (childParams.width == LayoutParams.FILL_PARENT);
199 | }
200 |
201 | if (matchParentHeight) {
202 | measuredChildHeight = maxBottom - minTop;
203 | childParams.height = measuredChildHeight;
204 | }
205 |
206 | if (matchParentWidth) {
207 | measuredChildWidth = maxRight - minLeft;
208 | childParams.width = measuredChildWidth;
209 | }
210 |
211 | switch (mDragEdge) {
212 | case DRAG_EDGE_RIGHT:
213 | left = Math.max(r - measuredChildWidth - getPaddingRight() - l, minLeft);
214 | top = Math.min(getPaddingTop(), maxBottom);
215 | right = Math.max(r - getPaddingRight() - l, minLeft);
216 | bottom = Math.min(measuredChildHeight + getPaddingTop(), maxBottom);
217 | break;
218 |
219 | case DRAG_EDGE_LEFT:
220 | left = Math.min(getPaddingLeft(), maxRight);
221 | top = Math.min(getPaddingTop(), maxBottom);
222 | right = Math.min(measuredChildWidth + getPaddingLeft(), maxRight);
223 | bottom = Math.min(measuredChildHeight + getPaddingTop(), maxBottom);
224 | break;
225 | }
226 |
227 | child.layout(left, top, right, bottom);
228 | }
229 |
230 | // taking account offset when mode is SAME_LEVEL
231 | if (mMode == MODE_SAME_LEVEL) {
232 | switch (mDragEdge) {
233 | case DRAG_EDGE_LEFT:
234 | mSecondaryView.offsetLeftAndRight(-mSecondaryView.getWidth());
235 | break;
236 |
237 | case DRAG_EDGE_RIGHT:
238 | mSecondaryView.offsetLeftAndRight(mSecondaryView.getWidth());
239 | break;
240 | }
241 | }
242 |
243 | initRects();
244 |
245 | if (mIsOpenBeforeInit) {
246 | open(false);
247 | } else {
248 | close(false);
249 | }
250 |
251 | }
252 |
253 | /**
254 | * {@inheritDoc}
255 | */
256 | @Override
257 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
258 | if (getChildCount() < 2) {
259 | throw new RuntimeException("Layout must have two children");
260 | }
261 |
262 | final LayoutParams params = getLayoutParams();
263 |
264 | final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
265 | final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
266 |
267 | int desiredWidth = 0;
268 | int desiredHeight = 0;
269 |
270 | // first find the largest child
271 | for (int i = 0; i < getChildCount(); i++) {
272 | final View child = getChildAt(i);
273 | measureChild(child, widthMeasureSpec, heightMeasureSpec);
274 | desiredWidth = Math.max(child.getMeasuredWidth(), desiredWidth);
275 | desiredHeight = Math.max(child.getMeasuredHeight(), desiredHeight);
276 | }
277 | // create new measure spec using the largest child width
278 | widthMeasureSpec = MeasureSpec.makeMeasureSpec(desiredWidth, widthMode);
279 | heightMeasureSpec = MeasureSpec.makeMeasureSpec(desiredHeight, heightMode);
280 |
281 | final int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
282 | final int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
283 |
284 | for (int i = 0; i < getChildCount(); i++) {
285 | final View child = getChildAt(i);
286 | final LayoutParams childParams = child.getLayoutParams();
287 |
288 | if (childParams != null) {
289 | if (childParams.height == LayoutParams.MATCH_PARENT) {
290 | child.setMinimumHeight(measuredHeight);
291 | }
292 |
293 | if (childParams.width == LayoutParams.MATCH_PARENT) {
294 | child.setMinimumWidth(measuredWidth);
295 | }
296 | }
297 |
298 | measureChild(child, widthMeasureSpec, heightMeasureSpec);
299 | desiredWidth = Math.max(child.getMeasuredWidth(), desiredWidth);
300 | desiredHeight = Math.max(child.getMeasuredHeight(), desiredHeight);
301 | }
302 |
303 | // taking accounts of padding
304 | desiredWidth += getPaddingLeft() + getPaddingRight();
305 | desiredHeight += getPaddingTop() + getPaddingBottom();
306 |
307 | // adjust desired width
308 | if (widthMode == MeasureSpec.EXACTLY) {
309 | desiredWidth = measuredWidth;
310 | } else {
311 | if (params.width == LayoutParams.MATCH_PARENT) {
312 | desiredWidth = measuredWidth;
313 | }
314 |
315 | if (widthMode == MeasureSpec.AT_MOST) {
316 | desiredWidth = (desiredWidth > measuredWidth)? measuredWidth : desiredWidth;
317 | }
318 | }
319 |
320 | // adjust desired height
321 | if (heightMode == MeasureSpec.EXACTLY) {
322 | desiredHeight = measuredHeight;
323 | } else {
324 | if (params.height == LayoutParams.MATCH_PARENT) {
325 | desiredHeight = measuredHeight;
326 | }
327 |
328 | if (heightMode == MeasureSpec.AT_MOST) {
329 | desiredHeight = (desiredHeight > measuredHeight)? measuredHeight : desiredHeight;
330 | }
331 | }
332 |
333 | setMeasuredDimension(desiredWidth, desiredHeight);
334 | }
335 |
336 | @Override
337 | public void computeScroll() {
338 | if (mDragHelper.continueSettling(true)) {
339 | ViewCompat.postInvalidateOnAnimation(this);
340 | }
341 | }
342 |
343 | /**
344 | * Open the panel to show the secondary view
345 | */
346 | public void open(boolean animation) {
347 | mIsOpenBeforeInit = true;
348 |
349 | if (animation) {
350 | mDragHelper.smoothSlideViewTo(mMainView, mRectMainOpen.left, mRectMainOpen.top);
351 | } else {
352 | mDragHelper.abort();
353 |
354 | mMainView.layout(
355 | mRectMainOpen.left,
356 | mRectMainOpen.top,
357 | mRectMainOpen.right,
358 | mRectMainOpen.bottom
359 | );
360 |
361 | mSecondaryView.layout(
362 | mRectSecOpen.left,
363 | mRectSecOpen.top,
364 | mRectSecOpen.right,
365 | mRectSecOpen.bottom
366 | );
367 | }
368 |
369 | ViewCompat.postInvalidateOnAnimation(this);
370 | }
371 |
372 | /**
373 | * Close the panel to hide the secondary view
374 | */
375 | public void close(boolean animation) {
376 | mIsOpenBeforeInit = false;
377 |
378 | if (animation) {
379 | mDragHelper.smoothSlideViewTo(mMainView, mRectMainClose.left, mRectMainClose.top);
380 | } else {
381 | mDragHelper.abort();
382 | mMainView.layout(
383 | mRectMainClose.left,
384 | mRectMainClose.top,
385 | mRectMainClose.right,
386 | mRectMainClose.bottom
387 | );
388 | mSecondaryView.layout(
389 | mRectSecClose.left,
390 | mRectSecClose.top,
391 | mRectSecClose.right,
392 | mRectSecClose.bottom
393 | );
394 | }
395 |
396 | ViewCompat.postInvalidateOnAnimation(this);
397 | }
398 |
399 | /**
400 | * @return true if the drag/swipe motion is currently locked.
401 | */
402 | public boolean isDragLocked() {
403 | return mLockDrag;
404 | }
405 |
406 | /**
407 | * @return Set true for lock the swipe.
408 | */
409 | public void dragLock(Boolean drag) {
410 | this.mLockDrag = drag;
411 | }
412 |
413 | private int getMainOpenLeft() {
414 | switch (mDragEdge) {
415 | case DRAG_EDGE_LEFT:
416 | return mRectMainClose.left + mSecondaryView.getWidth();
417 |
418 | case DRAG_EDGE_RIGHT:
419 | return mRectMainClose.left - mSecondaryView.getWidth();
420 |
421 |
422 | default:
423 | return 0;
424 | }
425 | }
426 |
427 | private int getMainOpenTop() {
428 | switch (mDragEdge) {
429 | case DRAG_EDGE_LEFT:
430 | return mRectMainClose.top;
431 |
432 | case DRAG_EDGE_RIGHT:
433 | return mRectMainClose.top;
434 |
435 |
436 | default:
437 | return 0;
438 | }
439 | }
440 |
441 | private int getSecOpenLeft() {
442 | return mRectSecClose.left;
443 | }
444 |
445 | private int getSecOpenTop() {
446 | return mRectSecClose.top;
447 | }
448 |
449 | private void initRects() {
450 | // close position of main view
451 | mRectMainClose.set(
452 | mMainView.getLeft(),
453 | mMainView.getTop(),
454 | mMainView.getRight(),
455 | mMainView.getBottom()
456 | );
457 |
458 | // close position of secondary view
459 | mRectSecClose.set(
460 | mSecondaryView.getLeft(),
461 | mSecondaryView.getTop(),
462 | mSecondaryView.getRight(),
463 | mSecondaryView.getBottom()
464 | );
465 |
466 | // open position of the main view
467 | mRectMainOpen.set(
468 | getMainOpenLeft(),
469 | getMainOpenTop(),
470 | getMainOpenLeft() + mMainView.getWidth(),
471 | getMainOpenTop() + mMainView.getHeight()
472 | );
473 |
474 | // open position of the secondary view
475 | mRectSecOpen.set(
476 | getSecOpenLeft(),
477 | getSecOpenTop(),
478 | getSecOpenLeft() + mSecondaryView.getWidth(),
479 | getSecOpenTop() + mSecondaryView.getHeight()
480 | );
481 | }
482 |
483 | private boolean couldBecomeClick(MotionEvent ev) {
484 | return isInMainView(ev) && !shouldInitiateADrag();
485 | }
486 |
487 | private boolean isInMainView(MotionEvent ev) {
488 | float x = ev.getX();
489 | float y = ev.getY();
490 |
491 | boolean withinVertical = mMainView.getTop() <= y && y <= mMainView.getBottom();
492 | boolean withinHorizontal = mMainView.getLeft() <= x && x <= mMainView.getRight();
493 |
494 | return withinVertical && withinHorizontal;
495 | }
496 |
497 | private boolean shouldInitiateADrag() {
498 | float minDistToInitiateDrag = mDragHelper.getTouchSlop();
499 | return mDragDist >= minDistToInitiateDrag;
500 | }
501 |
502 | private void accumulateDragDist(MotionEvent ev) {
503 | final int action = ev.getAction();
504 | if (action == MotionEvent.ACTION_DOWN) {
505 | mDragDist = 0;
506 | return;
507 | }
508 |
509 | float dragged = Math.abs(ev.getX() - mPrevX);
510 |
511 | mDragDist += dragged;
512 | }
513 |
514 | private void init(Context context, AttributeSet attrs) {
515 | if (attrs != null && context != null) {
516 | TypedArray a = context.getTheme().obtainStyledAttributes(
517 | attrs,
518 | R.styleable.SwipeRevealLayout,
519 | 0, 0
520 | );
521 |
522 | mDragEdge = a.getInteger(R.styleable.SwipeRevealLayout_dragFromEdge, DRAG_EDGE_LEFT);
523 | mMode = MODE_NORMAL;
524 | mMinFlingVelocity = DEFAULT_MIN_FLING_VELOCITY;
525 | mMinDistRequestDisallowParent = DEFAULT_MIN_DIST_REQUEST_DISALLOW_PARENT;
526 | }
527 |
528 | mDragHelper = ViewDragHelper.create(this, 1.0f, mDragHelperCallback);
529 | mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL);
530 |
531 | mGestureDetector = new GestureDetectorCompat(context, mGestureListener);
532 | }
533 |
534 | private final GestureDetector.OnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
535 | boolean hasDisallowed = false;
536 |
537 | @Override
538 | public boolean onDown(MotionEvent e) {
539 | mIsScrolling = false;
540 | hasDisallowed = false;
541 | return true;
542 | }
543 |
544 | @Override
545 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
546 | mIsScrolling = true;
547 | return false;
548 | }
549 |
550 | @Override
551 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
552 | mIsScrolling = true;
553 |
554 | if (getParent() != null) {
555 | boolean shouldDisallow;
556 |
557 | if (!hasDisallowed) {
558 | shouldDisallow = getDistToClosestEdge() >= mMinDistRequestDisallowParent;
559 | if (shouldDisallow) {
560 | hasDisallowed = true;
561 | }
562 | } else {
563 | shouldDisallow = true;
564 | }
565 |
566 | // disallow parent to intercept touch event so that the layout will work
567 | // properly on RecyclerView or view that handles scroll gesture.
568 | getParent().requestDisallowInterceptTouchEvent(shouldDisallow);
569 | }
570 |
571 | return false;
572 | }
573 | };
574 |
575 | private int getDistToClosestEdge() {
576 | switch (mDragEdge) {
577 | case DRAG_EDGE_LEFT:
578 | final int pivotRight = mRectMainClose.left + mSecondaryView.getWidth();
579 |
580 | return Math.min(
581 | mMainView.getLeft() - mRectMainClose.left,
582 | pivotRight - mMainView.getLeft()
583 | );
584 |
585 | case DRAG_EDGE_RIGHT:
586 | final int pivotLeft = mRectMainClose.right - mSecondaryView.getWidth();
587 |
588 | return Math.min(
589 | mMainView.getRight() - pivotLeft,
590 | mRectMainClose.right - mMainView.getRight()
591 | );
592 | }
593 |
594 | return 0;
595 | }
596 |
597 | private int getHalfwayPivotHorizontal() {
598 | if (mDragEdge == DRAG_EDGE_LEFT) {
599 | return mRectMainClose.left + mSecondaryView.getWidth() / 2;
600 | } else {
601 | return mRectMainClose.right - mSecondaryView.getWidth() / 2;
602 | }
603 | }
604 |
605 | private final ViewDragHelper.Callback mDragHelperCallback = new ViewDragHelper.Callback() {
606 | @Override
607 | public boolean tryCaptureView(View child, int pointerId) {
608 |
609 | if (mLockDrag)
610 | return false;
611 |
612 | mDragHelper.captureChildView(mMainView, pointerId);
613 | return false;
614 | }
615 |
616 | @Override
617 | public int clampViewPositionHorizontal(View child, int left, int dx) {
618 | switch (mDragEdge) {
619 | case DRAG_EDGE_RIGHT:
620 | return Math.max(
621 | Math.min(left, mRectMainClose.left),
622 | mRectMainClose.left - mSecondaryView.getWidth()
623 | );
624 |
625 | case DRAG_EDGE_LEFT:
626 | return Math.max(
627 | Math.min(left, mRectMainClose.left + mSecondaryView.getWidth()),
628 | mRectMainClose.left
629 | );
630 |
631 | default:
632 | return child.getLeft();
633 | }
634 | }
635 |
636 | @Override
637 | public void onViewReleased(View releasedChild, float xvel, float yvel) {
638 | final boolean velRightExceeded = pxToDp((int) xvel) >= mMinFlingVelocity;
639 | final boolean velLeftExceeded = pxToDp((int) xvel) <= -mMinFlingVelocity;
640 |
641 | final int pivotHorizontal = getHalfwayPivotHorizontal();
642 |
643 | switch (mDragEdge) {
644 | case DRAG_EDGE_RIGHT:
645 | if (velRightExceeded) {
646 | close(true);
647 | } else if (velLeftExceeded) {
648 | open(true);
649 | } else {
650 | if (mMainView.getRight() < pivotHorizontal) {
651 | open(true);
652 | } else {
653 | close(true);
654 | }
655 | }
656 | break;
657 |
658 | case DRAG_EDGE_LEFT:
659 | if (velRightExceeded) {
660 | open(true);
661 | } else if (velLeftExceeded) {
662 | close(true);
663 | } else {
664 | if (mMainView.getLeft() < pivotHorizontal) {
665 | close(true);
666 | } else {
667 | open(true);
668 | }
669 | }
670 | break;
671 | }
672 | }
673 |
674 | @Override
675 | public void onEdgeDragStarted(int edgeFlags, int pointerId) {
676 | super.onEdgeDragStarted(edgeFlags, pointerId);
677 |
678 | if (mLockDrag) {
679 | return;
680 | }
681 |
682 | boolean edgeStartLeft = (mDragEdge == DRAG_EDGE_RIGHT)
683 | && edgeFlags == ViewDragHelper.EDGE_LEFT;
684 |
685 | boolean edgeStartRight = (mDragEdge == DRAG_EDGE_LEFT)
686 | && edgeFlags == ViewDragHelper.EDGE_RIGHT;
687 |
688 | if (edgeStartLeft || edgeStartRight) {
689 | mDragHelper.captureChildView(mMainView, pointerId);
690 | }
691 | }
692 |
693 | @Override
694 | public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
695 | super.onViewPositionChanged(changedView, left, top, dx, dy);
696 | if (mMode == MODE_SAME_LEVEL) {
697 | if (mDragEdge == DRAG_EDGE_LEFT || mDragEdge == DRAG_EDGE_RIGHT) {
698 | mSecondaryView.offsetLeftAndRight(dx);
699 | } else {
700 | mSecondaryView.offsetTopAndBottom(dy);
701 | }
702 | }
703 | ViewCompat.postInvalidateOnAnimation(SwipeRevealLayout.this);
704 | }
705 | };
706 |
707 | private int pxToDp(int px) {
708 | Resources resources = getContext().getResources();
709 | DisplayMetrics metrics = resources.getDisplayMetrics();
710 | return (int) (px / ((float)metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT));
711 | }
712 | }
--------------------------------------------------------------------------------