├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── dimens.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── layout
│ │ │ │ ├── item_content.xml
│ │ │ │ ├── item_options.xml
│ │ │ │ └── activity_main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── duke
│ │ │ └── slidelayout_demo
│ │ │ └── MainActivity.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── duke
│ │ │ └── slidelayout_demo
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── duke
│ │ └── slidelayout_demo
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── SlideLayout
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ ├── strings.xml
│ │ │ │ └── attrs.xml
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── duke
│ │ │ └── slidelayout
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── duke
│ │ └── slidelayout
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── demo
├── SlideLayout_listview
│ ├── app
│ │ ├── .gitignore
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── values
│ │ │ │ │ │ ├── strings.xml
│ │ │ │ │ │ ├── colors.xml
│ │ │ │ │ │ ├── dimens.xml
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── layout
│ │ │ │ │ │ ├── item_content.xml
│ │ │ │ │ │ ├── activity_list_view.xml
│ │ │ │ │ │ ├── item_root.xml
│ │ │ │ │ │ └── item_options.xml
│ │ │ │ │ └── values-w820dp
│ │ │ │ │ │ └── dimens.xml
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── duke
│ │ │ │ │ └── slidelayout_listview
│ │ │ │ │ ├── ListViewActivity.java
│ │ │ │ │ └── ListViewAdapter.java
│ │ │ ├── test
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── duke
│ │ │ │ │ └── slidelayout_listview
│ │ │ │ │ └── ExampleUnitTest.java
│ │ │ └── androidTest
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── duke
│ │ │ │ └── slidelayout_listview
│ │ │ │ └── ExampleInstrumentedTest.java
│ │ ├── proguard-rules.pro
│ │ └── build.gradle
│ ├── SlideLayout
│ │ ├── .gitignore
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ └── values
│ │ │ │ │ │ ├── strings.xml
│ │ │ │ │ │ └── attrs.xml
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── duke
│ │ │ │ │ └── slidelayout
│ │ │ │ │ └── SlideLayout.java
│ │ │ ├── test
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── duke
│ │ │ │ │ └── slidelayout
│ │ │ │ │ └── ExampleUnitTest.java
│ │ │ └── androidTest
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── duke
│ │ │ │ └── slidelayout
│ │ │ │ └── ExampleInstrumentedTest.java
│ │ ├── proguard-rules.pro
│ │ └── build.gradle
│ ├── settings.gradle
│ ├── .idea
│ │ ├── copyright
│ │ │ └── profiles_settings.xml
│ │ ├── encodings.xml
│ │ ├── modules.xml
│ │ ├── runConfigurations.xml
│ │ ├── gradle.xml
│ │ ├── compiler.xml
│ │ └── misc.xml
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradlew.bat
│ └── gradlew
└── SlideLayout_recyclerview
│ ├── app
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ ├── dimens.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── layout
│ │ │ │ │ ├── item_content.xml
│ │ │ │ │ ├── item_root.xml
│ │ │ │ │ ├── activity_recycler_view.xml
│ │ │ │ │ └── item_options.xml
│ │ │ │ └── values-w820dp
│ │ │ │ │ └── dimens.xml
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── duke
│ │ │ │ └── slidelayout_recyclerview
│ │ │ │ ├── RecyclerViewAdapter.java
│ │ │ │ ├── RecyclerViewActivity.java
│ │ │ │ └── RecycleViewLineDivider.java
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── duke
│ │ │ │ └── slidelayout_recyclerview
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── duke
│ │ │ └── slidelayout_recyclerview
│ │ │ └── ExampleInstrumentedTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
│ ├── SlideLayout
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ └── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ └── attrs.xml
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── duke
│ │ │ │ └── slidelayout
│ │ │ │ └── SlideLayout.java
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── duke
│ │ │ │ └── slidelayout
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── duke
│ │ │ └── slidelayout
│ │ │ └── ExampleInstrumentedTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
│ ├── settings.gradle
│ ├── .idea
│ ├── copyright
│ │ └── profiles_settings.xml
│ ├── encodings.xml
│ ├── modules.xml
│ ├── runConfigurations.xml
│ ├── gradle.xml
│ ├── compiler.xml
│ └── misc.xml
│ ├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradlew.bat
│ └── gradlew
├── settings.gradle
├── demo.gif
├── listview.gif
├── recyclerview.gif
├── .idea
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── vcs.xml
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
├── compiler.xml
└── misc.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── gradlew
└── README.md
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/SlideLayout/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':SlideLayout'
2 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/SlideLayout/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/SlideLayout/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo.gif
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app',':SlideLayout'
2 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app',':SlideLayout'
2 |
--------------------------------------------------------------------------------
/listview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/listview.gif
--------------------------------------------------------------------------------
/recyclerview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/recyclerview.gif
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SlideLayout_demo
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/SlideLayout/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SlideLayout
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/SlideLayout/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SlideLayout
3 |
4 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SlideLayout_listview
3 |
4 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/SlideLayout/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SlideLayout
3 |
4 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SlideLayout_recyclerview
3 |
4 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_listview/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_recyclerview/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_listview/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_listview/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/.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 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_listview/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_listview/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_listview/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/.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 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_recyclerview/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_recyclerview/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_recyclerview/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_recyclerview/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/SlideLayout/HEAD/demo/SlideLayout_recyclerview/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
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-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/SlideLayout/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
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-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
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-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/SlideLayout/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/SlideLayout/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/layout/item_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/layout/item_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/layout/activity_list_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/layout/item_root.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/layout/item_root.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/SlideLayout/src/test/java/com/duke/slidelayout/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/test/java/com/duke/slidelayout_demo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_demo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/SlideLayout/src/test/java/com/duke/slidelayout/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/SlideLayout/src/test/java/com/duke/slidelayout/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/layout/activity_recycler_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/test/java/com/duke/slidelayout_listview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_listview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/test/java/com/duke/slidelayout_recyclerview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_recyclerview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in F:\Android_SDK_Windows/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/SlideLayout/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in F:\Android_SDK_Windows/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in F:\Android_SDK_Windows/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in F:\Android_SDK_Windows/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/SlideLayout/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in F:\Android_SDK_Windows/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/SlideLayout/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in F:\Android_SDK_Windows/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/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 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/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 |
--------------------------------------------------------------------------------
/SlideLayout/src/androidTest/java/com/duke/slidelayout/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.duke.slidelayout.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/duke/slidelayout_demo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_demo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.duke.slidelayout_demo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/SlideLayout/src/androidTest/java/com/duke/slidelayout/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.duke.slidelayout.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/SlideLayout/src/androidTest/java/com/duke/slidelayout/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.duke.slidelayout.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SlideLayout/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 15
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | compile 'com.android.support:appcompat-v7:25.1.1'
30 | testCompile 'junit:junit:4.12'
31 | }
32 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/androidTest/java/com/duke/slidelayout_listview/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_listview;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.duke.slidelayout_listview", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/androidTest/java/com/duke/slidelayout_recyclerview/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_recyclerview;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.duke.slidelayout_recyclerview", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/SlideLayout/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 15
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | compile 'com.android.support:appcompat-v7:25.1.1'
30 | testCompile 'junit:junit:4.12'
31 | }
32 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/SlideLayout/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 15
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | compile 'com.android.support:appcompat-v7:25.1.1'
30 | testCompile 'junit:junit:4.12'
31 | }
32 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 | defaultConfig {
7 | applicationId "com.duke.slidelayout_listview"
8 | minSdkVersion 15
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.1.1'
28 | testCompile 'junit:junit:4.12'
29 | compile project(':SlideLayout')
30 | }
31 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 | defaultConfig {
7 | applicationId "com.duke.slidelayout_demo"
8 | minSdkVersion 15
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.1.1'
28 | testCompile 'junit:junit:4.12'
29 | compile 'com.android.support:recyclerview-v7:25.1.1'
30 | compile project(':SlideLayout')
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
28 |
--------------------------------------------------------------------------------
/SlideLayout/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 | defaultConfig {
7 | applicationId "com.duke.slidelayout_recyclerview"
8 | minSdkVersion 15
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.1.1'
28 | testCompile 'junit:junit:4.12'
29 | compile 'com.android.support:recyclerview-v7:25.1.1'
30 | compile project(':SlideLayout')
31 | }
32 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/res/layout/item_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
28 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/res/layout/item_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
28 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/SlideLayout/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/SlideLayout/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/java/com/duke/slidelayout_listview/ListViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_listview;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.view.View;
6 | import android.widget.ListView;
7 | import android.widget.TextView;
8 | import android.widget.Toast;
9 |
10 | import java.util.ArrayList;
11 |
12 | public class ListViewActivity extends AppCompatActivity {
13 | private ListView listView;
14 | private ListViewAdapter adapter;
15 | private ArrayList list = new ArrayList<>();
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | setContentView(R.layout.activity_list_view);
21 | initData();
22 | listView = (ListView) findViewById(R.id.list_view);
23 | adapter = new ListViewAdapter(list);
24 | listView.setAdapter(adapter);
25 | listView.setOverScrollMode(View.OVER_SCROLL_NEVER);
26 |
27 | adapter.setOnMyClickListener(new ListViewAdapter.OnMyClickListener() {
28 | @Override
29 | public void onChildClick(View view) {
30 | String string = "";
31 | if (view.getId() == R.id.recycler_view_item_content) {
32 | TextView textView = (TextView) view;
33 | string = textView.getText().toString();
34 | } else if (view.getId() == R.id.options_root) {
35 | string = "操作菜单点击";
36 | } else if (view.getId() == R.id.tv_open) {
37 | TextView textView = (TextView) view;
38 | string = textView.getText().toString();
39 | } else if (view.getId() == R.id.tv_delete) {
40 | TextView textView = (TextView) view;
41 | string = textView.getText().toString();
42 | }
43 | Toast.makeText(ListViewActivity.this, string, Toast.LENGTH_SHORT).show();
44 | }
45 | });
46 | }
47 |
48 | private void initData() {
49 | for (int i = 0; i < 30; i++) {
50 | list.add("老老老老老" + i);
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
22 |
27 |
32 |
33 |
34 |
37 |
42 |
47 |
48 |
49 |
54 |
55 |
60 |
61 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/java/com/duke/slidelayout_recyclerview/RecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_recyclerview;
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.TextView;
8 | import com.duke.slidelayout.SlideLayout;
9 | import java.util.ArrayList;
10 |
11 | /**
12 | * @Author: duke
13 | * @DateTime: 2017-01-03 22:24
14 | * @Description:
15 | */
16 | public class RecyclerViewAdapter extends RecyclerView.Adapter {
17 | private ArrayList lists = new ArrayList<>();
18 | private OnMyClickListener onMyClickListener;
19 |
20 | public void setOnMyClickListener(OnMyClickListener l) {
21 | this.onMyClickListener = l;
22 | }
23 |
24 | public RecyclerViewAdapter(ArrayList lists) {
25 | this.lists.clear();
26 | this.lists.addAll(lists);
27 | }
28 |
29 | @Override
30 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
31 | /**
32 | * 加载滑动布局item_root,其中已经包含了content和optinos布局
33 | */
34 | return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_root, parent, false));
35 | }
36 |
37 | @Override
38 | public void onBindViewHolder(ViewHolder holder, int position) {
39 | holder.content.setText(lists.get(position));
40 | }
41 |
42 | @Override
43 | public int getItemCount() {
44 | return lists.size();
45 | }
46 |
47 | class ViewHolder extends RecyclerView.ViewHolder {
48 | private SlideLayout slideLayout;
49 | private TextView content;
50 |
51 | public ViewHolder(View itemView) {
52 | super(itemView);
53 | slideLayout = (SlideLayout) itemView;
54 | content = (TextView) itemView.findViewById(R.id.recycler_view_item_content);
55 |
56 | slideLayout.setOnChildClickListener(new SlideLayout.OnChildClickListener() {
57 | @Override
58 | public void onChildClick(View view) {
59 | if (onMyClickListener != null) {
60 | onMyClickListener.onChildClick(view);
61 | }
62 | }
63 | });
64 | }
65 | }
66 |
67 | public interface OnMyClickListener {
68 | void onChildClick(View view);
69 | }
70 | }
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/app/src/main/java/com/duke/slidelayout_listview/ListViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_listview;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.BaseAdapter;
7 | import android.widget.TextView;
8 | import com.duke.slidelayout.SlideLayout;
9 | import java.util.ArrayList;
10 |
11 | /**
12 | * @Author: duke
13 | * @DateTime: 2017-01-03 22:24
14 | * @Description:
15 | */
16 | public class ListViewAdapter extends BaseAdapter{
17 | private ArrayList list = new ArrayList<>();
18 | private OnMyClickListener onMyClickListener;
19 |
20 | public void setOnMyClickListener(OnMyClickListener l) {
21 | this.onMyClickListener = l;
22 | }
23 |
24 | public ListViewAdapter(ArrayList lists) {
25 | this.list.clear();
26 | this.list.addAll(lists);
27 | }
28 |
29 | @Override
30 | public int getCount() {
31 | return list ==null?0: list.size();
32 | }
33 |
34 | @Override
35 | public Object getItem(int position) {
36 | return list.get(position);
37 | }
38 |
39 | @Override
40 | public long getItemId(int position) {
41 | return position;
42 | }
43 |
44 | @Override
45 | public View getView(int position, View convertView, ViewGroup parent) {
46 | ViewHolder holder;
47 | if(convertView==null){
48 | holder = new ViewHolder();
49 | convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_root, parent, false);
50 | holder.slideLayout = (SlideLayout) convertView;
51 | holder.content = (TextView) convertView.findViewById(R.id.recycler_view_item_content);
52 | convertView.setTag(holder);
53 | }else{
54 | holder = (ViewHolder) convertView.getTag();
55 | }
56 | holder.content.setText(list.get(position));
57 | holder.slideLayout.setOnChildClickListener(new SlideLayout.OnChildClickListener() {
58 | @Override
59 | public void onChildClick(View view) {
60 | if (onMyClickListener != null) {
61 | onMyClickListener.onChildClick(view);
62 | }
63 | }
64 | });
65 | return convertView;
66 | }
67 |
68 | static class ViewHolder{
69 | private SlideLayout slideLayout;
70 | private TextView content;
71 | }
72 |
73 | public interface OnMyClickListener {
74 | void onChildClick(View view);
75 | }
76 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/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 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/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 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/java/com/duke/slidelayout_recyclerview/RecyclerViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_recyclerview;
2 |
3 | import android.graphics.Color;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.support.v7.widget.LinearLayoutManager;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.view.View;
9 | import android.widget.TextView;
10 | import android.widget.Toast;
11 |
12 | import java.util.ArrayList;
13 |
14 | public class RecyclerViewActivity extends AppCompatActivity {
15 | private RecyclerView recyclerView;
16 | private RecyclerViewAdapter adapter;
17 | private ArrayList list = new ArrayList<>();
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_recycler_view);
23 | initData();
24 | recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
25 | adapter = new RecyclerViewAdapter(list);
26 | recyclerView.setAdapter(adapter);
27 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
28 | linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
29 | recyclerView.setLayoutManager(linearLayoutManager);
30 | recyclerView.addItemDecoration(new RecycleViewLineDivider(LinearLayoutManager.VERTICAL, 4, Color.WHITE));
31 | recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
32 | /**
33 | * 传递出slidelayout中content和options两个布局所有view的点击事件,根据需要做判断
34 | */
35 | adapter.setOnMyClickListener(new RecyclerViewAdapter.OnMyClickListener() {
36 | @Override
37 | public void onChildClick(View view) {
38 | String string = "";
39 | if (view.getId() == R.id.recycler_view_item_content) {
40 | TextView textView = (TextView) view;
41 | string = textView.getText().toString();
42 | } else if (view.getId() == R.id.options_root) {
43 | string = "操作菜单点击";
44 | } else if (view.getId() == R.id.tv_open) {
45 | TextView textView = (TextView) view;
46 | string = textView.getText().toString();
47 | } else if (view.getId() == R.id.tv_delete) {
48 | TextView textView = (TextView) view;
49 | string = textView.getText().toString();
50 | }
51 | Toast.makeText(RecyclerViewActivity.this, string, Toast.LENGTH_SHORT).show();
52 | }
53 | });
54 | }
55 |
56 | private void initData() {
57 | for (int i = 0; i < 30; i++) {
58 | list.add("老老老老老" + i);
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/duke/slidelayout_demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.view.View;
6 | import android.widget.Button;
7 | import android.widget.TextView;
8 | import android.widget.Toast;
9 |
10 | import com.duke.slidelayout.SlideLayout;
11 |
12 | public class MainActivity extends AppCompatActivity implements View.OnClickListener,
13 | SlideLayout.OnOptionsStateChangeListener, SlideLayout.OnChildClickListener {
14 | private SlideLayout slideLayout;
15 | private Button setSlideDirection1, setSlideDirection2, setOptionsLayoutPosition1,
16 | setOptionsLayoutPosition2, setOpenedfalse, setOpenedtrue;
17 |
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_main);
22 | slideLayout = (SlideLayout) findViewById(R.id.slideLayout);
23 | slideLayout.setOnOptionsStateChangeListener(this);
24 | slideLayout.setOnChildClickListener(this);
25 |
26 | setSlideDirection1 = (Button) findViewById(R.id.setSlideDirection1);
27 | setSlideDirection2 = (Button) findViewById(R.id.setSlideDirection2);
28 | setOptionsLayoutPosition1 = (Button) findViewById(R.id.setOptionsLayoutPosition1);
29 | setOptionsLayoutPosition2 = (Button) findViewById(R.id.setOptionsLayoutPosition2);
30 | setOpenedfalse = (Button) findViewById(R.id.setOpenedfalse);
31 | setOpenedtrue = (Button) findViewById(R.id.setOpenedtrue);
32 | setSlideDirection1.setOnClickListener(this);
33 | setSlideDirection2.setOnClickListener(this);
34 | setOptionsLayoutPosition1.setOnClickListener(this);
35 | setOptionsLayoutPosition2.setOnClickListener(this);
36 | setOpenedfalse.setOnClickListener(this);
37 | setOpenedtrue.setOnClickListener(this);
38 | }
39 |
40 | @Override
41 | public void onClick(View v) {
42 | switch (v.getId()) {
43 | case R.id.setSlideDirection1:
44 | slideLayout.setSlideDirection(SlideLayout.SlideDirection.LEFT);
45 | break;
46 | case R.id.setSlideDirection2:
47 | slideLayout.setSlideDirection(SlideLayout.SlideDirection.RIGHT);
48 | break;
49 | case R.id.setOptionsLayoutPosition1:
50 | slideLayout.setOptionsLayoutPosition(SlideLayout.OptionsLayoutPosition.FIXED);
51 | break;
52 | case R.id.setOptionsLayoutPosition2:
53 | slideLayout.setOptionsLayoutPosition(SlideLayout.OptionsLayoutPosition.FOLLOW);
54 | break;
55 | case R.id.setOpenedfalse:
56 | slideLayout.setOpened(false);
57 | break;
58 | case R.id.setOpenedtrue:
59 | slideLayout.setOpened(true);
60 | break;
61 | }
62 | }
63 |
64 | @Override
65 | public void onOptionsViewChange(boolean isOpened) {
66 | Toast.makeText(this, isOpened ? "菜单打开" : "菜单关闭", Toast.LENGTH_SHORT).show();
67 | }
68 |
69 | @Override
70 | public void onChildClick(View view) {
71 | String string = "";
72 | if (view.getId() == R.id.content_root) {
73 | string = "内容点击";
74 | } else if (view.getId() == R.id.content_text) {
75 | TextView textView = (TextView) view;
76 | string = textView.getText().toString();
77 | } else if (view.getId() == R.id.options_root) {
78 | string = "操作菜单点击";
79 | } else if (view.getId() == R.id.tv_open) {
80 | TextView textView = (TextView) view;
81 | string = textView.getText().toString();
82 | } else if (view.getId() == R.id.tv_delete) {
83 | TextView textView = (TextView) view;
84 | string = textView.getText().toString();
85 | }
86 | Toast.makeText(MainActivity.this, string, Toast.LENGTH_SHORT).show();
87 | }
88 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/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 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SlideLayout
2 | a simple slide layout library,just one java class file.
3 | 一个侧滑删除的库和demo,仅仅只是一个自定义控件搞定,提供了普通用法和listview,recyclerview用法实例。
4 | 关于滑动或touch功能,onTouchEvent方法可以搞定。但是本例没有这么复杂,借助ViewDragHelper工具类处理。
5 | 本例提供4种滑动效果:
6 | * options隐藏菜单跟随content布局滑动
7 | * options隐藏菜单固定在content底部,仅由content布局滑动
8 | * 从左侧滑出
9 | * 从右侧滑出
10 | 仅仅以上4种效果,代码逻辑就开始有点复杂,故没有考虑options和content布局从上下两侧滑动。
11 |
12 | ==============
13 | #效果图
14 | 
15 | #部分代码:
16 | ##activity_main.xml:
17 |
18 |
19 |
25 |
26 |
35 | ...
36 |
37 |
38 | -
39 |
40 | slide:contentResId="@layout/item_content" 内容布局,即上层布局
41 | slide:optionsResId="@layout/item_options" 操作菜单布局,即下层布局
42 |
43 | =
44 |
45 | ##MainActivity.java:
46 |
47 |
48 |
49 | public class MainActivity extends AppCompatActivity implements View.OnClickListener,
50 | SlideLayout.OnOptionsStateChangeListener, SlideLayout.OnChildClickListener {
51 | private SlideLayout slideLayout;
52 | private Button setSlideDirection1, setSlideDirection2, setOptionsLayoutPosition1,
53 | setOptionsLayoutPosition2, setOpenedfalse, setOpenedtrue;
54 |
55 | @Override
56 | protected void onCreate(Bundle savedInstanceState) {
57 | super.onCreate(savedInstanceState);
58 | setContentView(R.layout.activity_main);
59 | slideLayout = (SlideLayout) findViewById(R.id.slideLayout);
60 | slideLayout.setOnOptionsStateChangeListener(this);
61 | slideLayout.setOnChildClickListener(this);
62 |
63 | setSlideDirection1 = (Button) findViewById(R.id.setSlideDirection1);
64 | setSlideDirection2 = (Button) findViewById(R.id.setSlideDirection2);
65 | setOptionsLayoutPosition1 = (Button) findViewById(R.id.setOptionsLayoutPosition1);
66 | setOptionsLayoutPosition2 = (Button) findViewById(R.id.setOptionsLayoutPosition2);
67 | setOpenedfalse = (Button) findViewById(R.id.setOpenedfalse);
68 | setOpenedtrue = (Button) findViewById(R.id.setOpenedtrue);
69 | setSlideDirection1.setOnClickListener(this);
70 | setSlideDirection2.setOnClickListener(this);
71 | setOptionsLayoutPosition1.setOnClickListener(this);
72 | setOptionsLayoutPosition2.setOnClickListener(this);
73 | setOpenedfalse.setOnClickListener(this);
74 | setOpenedtrue.setOnClickListener(this);
75 | }
76 |
77 | @Override
78 | public void onClick(View v) {
79 | switch (v.getId()) {
80 | case R.id.setSlideDirection1:
81 | slideLayout.setSlideDirection(SlideLayout.SlideDirection.LEFT);
82 | break;
83 | case R.id.setSlideDirection2:
84 | slideLayout.setSlideDirection(SlideLayout.SlideDirection.RIGHT);
85 | break;
86 | case R.id.setOptionsLayoutPosition1:
87 | slideLayout.setOptionsLayoutPosition(SlideLayout.OptionsLayoutPosition.FIXED);
88 | break;
89 | case R.id.setOptionsLayoutPosition2:
90 | slideLayout.setOptionsLayoutPosition(SlideLayout.OptionsLayoutPosition.FOLLOW);
91 | break;
92 | case R.id.setOpenedfalse:
93 | slideLayout.setOpened(false);
94 | break;
95 | case R.id.setOpenedtrue:
96 | slideLayout.setOpened(true);
97 | break;
98 | }
99 | }
100 |
101 | @Override
102 | public void onOptionsViewChange(boolean isOpened) {
103 | Toast.makeText(this, isOpened ? "菜单打开" : "菜单关闭", Toast.LENGTH_SHORT).show();
104 | }
105 |
106 | @Override
107 | public void onChildClick(View view) {
108 | String string = "";
109 | if (view.getId() == R.id.content_root) {
110 | string = "内容点击";
111 | } else if (view.getId() == R.id.content_text) {
112 | TextView textView = (TextView) view;
113 | string = textView.getText().toString();
114 | } else if (view.getId() == R.id.options_root) {
115 | string = "操作菜单点击";
116 | } else if (view.getId() == R.id.tv_open) {
117 | TextView textView = (TextView) view;
118 | string = textView.getText().toString();
119 | } else if (view.getId() == R.id.tv_delete) {
120 | TextView textView = (TextView) view;
121 | string = textView.getText().toString();
122 | }
123 | Toast.makeText(MainActivity.this, string, Toast.LENGTH_SHORT).show();
124 | }
125 | }
126 |
127 | -
128 |
129 | 无论是content布局控件还是options布局控件的点击事件,我不清楚各自的id。
130 | 我统一都用SlideLayout.OnChildClickListener接口提供给您,具体是哪个点击了,请在回调中判断id,再做处理。
131 | 参考public void onChildClick(View view) 方法;
132 |
133 | =====
134 |
135 | 至于在listview和recyclerview中的用法,请参考github库中的demo:
136 | ./demo/SlideLayout_listview
137 | ./demo/SlideLayout_recyclerview
138 | ###下面贴出效果图:
139 | 
140 |
141 | -
142 |
143 | 
144 |
145 |
146 | 更多资料请关注[我的博客](http://blog.csdn.net/fesdgasdgasdg?viewmode=contents)
147 |
148 |
149 |
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/app/src/main/java/com/duke/slidelayout_recyclerview/RecycleViewLineDivider.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout_recyclerview;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.graphics.Rect;
8 | import android.graphics.drawable.Drawable;
9 | import android.support.v4.content.ContextCompat;
10 | import android.support.v7.widget.LinearLayoutManager;
11 | import android.support.v7.widget.RecyclerView;
12 | import android.view.View;
13 |
14 | /**
15 | * @DateTime: 2016-07-21 17:55
16 | * @Author: duke
17 | * @Deacription: recyclerview万能分割线
18 | */
19 | public class RecycleViewLineDivider extends RecyclerView.ItemDecoration {
20 |
21 | private Paint mPaint;//如果需要用画笔手绘
22 | private Drawable mDrawableDivider;//如果需要绘制给定的drawable
23 | private int mPaintDividerLength = 2;//分割线宽度或高度
24 | private DrawType drawType;//用画笔绘制颜色,还是绘制特定的drawable
25 | /**
26 | * 注意:列表的方向
27 | * LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL
28 | */
29 | private int mOrientation;
30 | //系统默认的分割线
31 | private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
32 |
33 | /**
34 | * 自定义分割线
35 | *
36 | * @param context
37 | * @param orientation 列表方向
38 | * @param drawableId 分割线图片
39 | */
40 | public RecycleViewLineDivider(Context context, int orientation, int drawableId) {
41 | if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
42 | throw new IllegalArgumentException("请输入正确的参数!");
43 | }
44 | mOrientation = orientation;
45 | if (drawableId == -100) {
46 | //获取系统的样式
47 | final TypedArray a = context.obtainStyledAttributes(ATTRS);
48 | mDrawableDivider = a.getDrawable(0);
49 | a.recycle();
50 | } else {
51 | mDrawableDivider = ContextCompat.getDrawable(context, drawableId);
52 | }
53 | //表明绘制drawable
54 | drawType = DrawType.USEDRAWABLE;
55 | }
56 |
57 | /**
58 | * @param context 上下文
59 | * @param orientation 列表方向
60 | */
61 | public RecycleViewLineDivider(Context context, int orientation) {
62 | this(context, orientation, -100);
63 | }
64 |
65 | /**
66 | * 自定义分割线
67 | *
68 | * @param orientation 列表方向
69 | * @param dividerHeight 分割线高度
70 | * @param dividerColor 分割线颜色
71 | */
72 | public RecycleViewLineDivider(int orientation, int dividerHeight, int dividerColor) {
73 | if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
74 | throw new IllegalArgumentException("请输入正确的参数!");
75 | }
76 | mOrientation = orientation;
77 | if (dividerHeight != -100) {
78 | //分割线高度
79 | mPaintDividerLength = dividerHeight;
80 | }
81 | //创建特定画笔
82 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
83 | mPaint.setColor(dividerColor);
84 | mPaint.setStyle(Paint.Style.FILL);
85 | //表明绘制用paint
86 | drawType = DrawType.USEPAINT;
87 | }
88 |
89 | /**
90 | * 自定义分割线
91 | *
92 | * @param orientation 列表方向
93 | * @param dividerColor 分割线颜色
94 | */
95 | public RecycleViewLineDivider(int orientation, int dividerColor) {
96 | this(orientation, -100, dividerColor);
97 | }
98 |
99 |
100 | /**
101 | * 看图说话:get Item Offsets,获得item的偏移量。此方法用来控制item的偏移
102 | *
103 | * @param outRect
104 | * @param view
105 | * @param parent
106 | * @param state
107 | */
108 | @Override
109 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
110 | super.getItemOffsets(outRect, view, parent, state);
111 | /**
112 | * 列表的方向为横向,画分割线就是纵向的,需要确定的是child的右边偏移值
113 | * 留出空间画分割线
114 | */
115 | if (this.mOrientation == LinearLayoutManager.HORIZONTAL)
116 | switch (drawType) {
117 | case USEPAINT:
118 | outRect.set(0, 0, mPaintDividerLength, 0);
119 | break;
120 | case USEDRAWABLE:
121 | outRect.set(0, 0, mDrawableDivider.getIntrinsicWidth(), 0);
122 | break;
123 | }
124 | /**
125 | * 列表的方向为纵向,画分割线就是横向的,需要确定的是child的下边偏移值
126 | * 留出空间画分割线
127 | */
128 | else if (this.mOrientation == LinearLayoutManager.VERTICAL)
129 | switch (drawType) {
130 | case USEPAINT:
131 | outRect.set(0, 0, 0, mPaintDividerLength);
132 | break;
133 | case USEDRAWABLE:
134 | outRect.set(0, 0, 0, mDrawableDivider.getIntrinsicHeight());
135 | break;
136 | }
137 | }
138 |
139 | /**
140 | * 绘制分割线
141 | *
142 | * @param c
143 | * @param parent
144 | * @param state
145 | */
146 | @Override
147 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
148 | super.onDraw(c, parent, state);
149 | if (mOrientation == LinearLayoutManager.VERTICAL) {
150 | //列表是纵向的,需要绘制横向的分割线
151 | drawHorizontal(c, parent);
152 | } else {
153 | //列表是横向的,需要绘制纵向的分割线
154 | drawVertical(c, parent);
155 | }
156 | }
157 |
158 | /**
159 | * 绘制横向 item 分割线。左、上、右都是可计算的,下需要获取给定的高度值
160 | *
161 | * @param canvas
162 | * @param parent
163 | */
164 | private void drawHorizontal(Canvas canvas, RecyclerView parent) {
165 | //左边:到父容器的left内间距位置值
166 | final int left = parent.getPaddingLeft();
167 | //右边:到父容器的right内间距位置值
168 | final int right = parent.getMeasuredWidth() - parent.getPaddingRight();
169 | final int childSize = parent.getChildCount();
170 | //循环绘制每条分割线
171 | for (int i = 0; i < childSize - 1; i++) {
172 | final View child = parent.getChildAt(i);
173 | RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
174 | //上边:具体的某条分割线的左边以child的(bottom+bottomMargin)位置值
175 | final int top = child.getBottom() + layoutParams.bottomMargin;
176 | //下边:根据类型判断
177 | int bottom;
178 | switch (drawType) {
179 | case USEPAINT://构造方法声明使用画笔绘制
180 | //下边:top加上指定的高度
181 | bottom = top + mPaintDividerLength;
182 | if (mPaint != null) {
183 | canvas.drawRect(left, top, right, bottom, mPaint);
184 | }
185 | break;
186 | case USEDRAWABLE://构造方法声明使用drawable
187 | if (mDrawableDivider != null) {
188 | //下边:top加上指定的高度
189 | bottom = top + mDrawableDivider.getIntrinsicHeight();
190 | mDrawableDivider.setBounds(left, top, right, bottom);
191 | mDrawableDivider.draw(canvas);
192 | }
193 | break;
194 | }
195 | }
196 | }
197 |
198 | /**
199 | * 绘制纵向 item 分割线。上、下、左都是可计算的,右侧需要获取给定的宽度值
200 | *
201 | * @param canvas
202 | * @param parent
203 | */
204 | private void drawVertical(Canvas canvas, RecyclerView parent) {
205 | //上边:到父容器的top内间距位置值
206 | final int top = parent.getPaddingTop();
207 | //下边:到父容器的bottom内间距位置值
208 | final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();
209 | final int childSize = parent.getChildCount();
210 | //循环绘制每条分割线
211 | for (int i = 0; i < childSize - 1; i++) {
212 | final View child = parent.getChildAt(i);
213 | RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
214 | //左边:具体的某条分割线的左边以child的(right+rightMargin)位置值
215 | final int left = child.getRight() + layoutParams.rightMargin;
216 | //右边:根据类型判断
217 | int right;
218 | switch (drawType) {
219 | case USEPAINT://构造方法声明使用画笔绘制
220 | //右边:left加上指定的宽度
221 | right = left + mPaintDividerLength;
222 | if (mPaint != null) {
223 | canvas.drawRect(left, top, right, bottom, mPaint);
224 | }
225 | break;
226 | case USEDRAWABLE://构造方法声明使用drawable
227 | if (mDrawableDivider != null) {
228 | //右边:left加上指定的宽度
229 | right = left + mDrawableDivider.getIntrinsicWidth();
230 | mDrawableDivider.setBounds(left, top, right, bottom);
231 | mDrawableDivider.draw(canvas);
232 | }
233 | break;
234 | }
235 | }
236 |
237 | }
238 |
239 | public static enum DrawType {
240 | USEPAINT(1),//用画笔画
241 | USEDRAWABLE(2); //画特定的drawable
242 |
243 | private final int type;
244 |
245 | DrawType(int type) {
246 | this.type = type;
247 | }
248 |
249 | public int getType() {
250 | return type;
251 | }
252 | }
253 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 | -60dp
7 | -30dp
8 | -20dp
9 | -10dp
10 | -5dp
11 | -2dp
12 | -1dp
13 | 0.1dp
14 | 0.5dp
15 | 1dp
16 | 2dp
17 | 2.5dp
18 | 3dp
19 | 4dp
20 | 4.5dp
21 | 5dp
22 | 6dp
23 | 7dp
24 | 7.5dp
25 | 8dp
26 | 9dp
27 | 10dp
28 | 11dp
29 | 12dp
30 | 13dp
31 | 14dp
32 | 15dp
33 | 16dp
34 | 17dp
35 | 18dp
36 | 19dp
37 | 20dp
38 | 21dp
39 | 22dp
40 | 23dp
41 | 24dp
42 | 25dp
43 | 26dp
44 | 27dp
45 | 28dp
46 | 29dp
47 | 30dp
48 | 31dp
49 | 32dp
50 | 33dp
51 | 34dp
52 | 35dp
53 | 36dp
54 | 37dp
55 | 38dp
56 | 39dp
57 | 40dp
58 | 41dp
59 | 42dp
60 | 43dp
61 | 44dp
62 | 45dp
63 | 46dp
64 | 47dp
65 | 48dp
66 | 49dp
67 | 50dp
68 | 51dp
69 | 52dp
70 | 53dp
71 | 54dp
72 | 55dp
73 | 56dp
74 | 57dp
75 | 58dp
76 | 59dp
77 | 60dp
78 | 61dp
79 | 62dp
80 | 63dp
81 | 64dp
82 | 65dp
83 | 66dp
84 | 67dp
85 | 68dp
86 | 69dp
87 | 70dp
88 | 71dp
89 | 72dp
90 | 73dp
91 | 74dp
92 | 75dp
93 | 76dp
94 | 77dp
95 | 78dp
96 | 79dp
97 | 80dp
98 | 81dp
99 | 82dp
100 | 83dp
101 | 84dp
102 | 85dp
103 | 86dp
104 | 87dp
105 | 88dp
106 | 89dp
107 | 90dp
108 | 91dp
109 | 92dp
110 | 93dp
111 | 94dp
112 | 95dp
113 | 96dp
114 | 97dp
115 | 98dp
116 | 99dp
117 | 100dp
118 | 101dp
119 | 102dp
120 | 103dp
121 | 104dp
122 | 105dp
123 | 106dp
124 | 107dp
125 | 108dp
126 | 109dp
127 | 110dp
128 | 111dp
129 | 112dp
130 | 113dp
131 | 114dp
132 | 115dp
133 | 116dp
134 | 117dp
135 | 118dp
136 | 119dp
137 | 120dp
138 | 121dp
139 | 122dp
140 | 123dp
141 | 124dp
142 | 125dp
143 | 126dp
144 | 127dp
145 | 128dp
146 | 129dp
147 | 130dp
148 | 131dp
149 | 132dp
150 | 133dp
151 | 134dp
152 | 135dp
153 | 136dp
154 | 137dp
155 | 138dp
156 | 139dp
157 | 140dp
158 | 141dp
159 | 142dp
160 | 143dp
161 | 144dp
162 | 145dp
163 | 146dp
164 | 147dp
165 | 148dp
166 | 149dp
167 | 150dp
168 | 155dp
169 | 159dp
170 | 160dp
171 | 162dp
172 | 165dp
173 | 170dp
174 | 175dp
175 | 177dp
176 | 179dp
177 | 180dp
178 | 185dp
179 | 190dp
180 | 194dp
181 | 196dp
182 | 200dp
183 | 202dp
184 | 210dp
185 | 216dp
186 | 219dp
187 | 220dp
188 | 225dp
189 | 230dp
190 | 235dp
191 | 238dp
192 | 240dp
193 | 245dp
194 | 250dp
195 | 267dp
196 | 270dp
197 | 275dp
198 | 277dp
199 | 280dp
200 | 285dp
201 | 289dp
202 | 293dp
203 | 300dp
204 | 301dp
205 | 302dp
206 | 306dp
207 | 320dp
208 | 325dp
209 | 338dp
210 | 350dp
211 | 355dp
212 | 360dp
213 | 365dp
214 | 370dp
215 | 402dp
216 | 410dp
217 | 422dp
218 | 472dp
219 | 500dp
220 | 600dp
221 | 640dp
222 |
223 | 6sp
224 | 7sp
225 | 8sp
226 | 9sp
227 | 10sp
228 | 11sp
229 | 12sp
230 | 13sp
231 | 14sp
232 | 15sp
233 | 16sp
234 | 17sp
235 | 18sp
236 | 19sp
237 | 20sp
238 | 21sp
239 | 22sp
240 | 24sp
241 | 28sp
242 | 38sp
243 | 40sp
244 | 41sp
245 | 48sp
246 |
--------------------------------------------------------------------------------
/demo/SlideLayout_listview/SlideLayout/src/main/java/com/duke/slidelayout/SlideLayout.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Color;
6 | import android.support.v4.view.MotionEventCompat;
7 | import android.support.v4.view.ViewCompat;
8 | import android.support.v4.widget.ViewDragHelper;
9 | import android.util.AttributeSet;
10 | import android.view.LayoutInflater;
11 | import android.view.MotionEvent;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 |
15 | /**
16 | * @Author: duke
17 | * @DateTime: 2016-12-25 20:50
18 | * @Description: 侧滑操作布局
19 | */
20 | public class SlideLayout extends ViewGroup {
21 | private View optionsView;//item的滑动操作选项view
22 | private int optionsResId;
23 | private View contentView;//item的内容view
24 | private int contentResId;
25 |
26 | //记录滑动view上次的left值,以便根据此次的left判断滑动方向
27 | private int movedLengthTemp;
28 | private boolean slideDirectionRight;//记录滑动方向
29 | //滑动阀值
30 | private static final int THRESHOLD_MOVED_VALUE = 25;//px
31 | private int thresholdMoved = THRESHOLD_MOVED_VALUE;//px
32 |
33 | private int contentBgColor = Color.WHITE;//内容部分背景颜色
34 | private int contentBgResId;//内容部分背景资源id
35 | private boolean hasContentBgColor;//是否设置了content背景颜色
36 |
37 | //滑动方向:【从左侧、从右侧】
38 | private int slideDirection = SlideDirection.RIGHT.getIntValue();
39 | //操作菜单view摆放方式:【固定,跟随】
40 | private int optionsLayoutPosition = OptionsLayoutPosition.FIXED.getIntValue();
41 |
42 | private boolean isOpened = false;//是否有滑动出来的item
43 | private boolean canDrag = true;//是否可以拖拽
44 | private ViewDragHelper helper;//拖拽辅助类
45 | private OnOptionsStateChangeListener onOptionsStateChangeListener;
46 | private OnChildClickListener onChildClickListener;
47 |
48 | public void setOnChildClickListener(OnChildClickListener l) {
49 | this.onChildClickListener = l;
50 | }
51 |
52 | public void setOnOptionsStateChangeListener(OnOptionsStateChangeListener l) {
53 | this.onOptionsStateChangeListener = l;
54 | }
55 |
56 | public View getOptionsView() {
57 | return optionsView;
58 | }
59 |
60 | public View getContentView() {
61 | return contentView;
62 | }
63 |
64 | public int getThresholdMoved() {
65 | return thresholdMoved;
66 | }
67 |
68 | /**
69 | * 设置滑动阀值
70 | *
71 | * @param thresholdMovedDP dp or dp of dimens
72 | */
73 | public void setThresholdMoved(int thresholdMovedDP) {
74 | this.thresholdMoved = getContext().getResources().getDimensionPixelSize(thresholdMoved);
75 | }
76 |
77 | public int getSlideDirection() {
78 | return slideDirection;
79 | }
80 |
81 | public int getOptionsLayoutPosition() {
82 | return optionsLayoutPosition;
83 | }
84 |
85 | public boolean isCanDrag() {
86 | return canDrag;
87 | }
88 |
89 | public void setCanDrag(boolean canDrag) {
90 | this.canDrag = canDrag;
91 | setOpened(false);
92 | }
93 |
94 | public boolean isOpened() {
95 | return isOpened;
96 | }
97 |
98 | public void setOptionsView(View optionsView) {
99 | this.optionsView = optionsView;
100 | addChildren();
101 | requestLayout();
102 | }
103 |
104 | public void setOptionsResId(int optionsResId) {
105 | this.optionsResId = optionsResId;
106 | try {
107 | this.optionsView = inflateChild(optionsResId);
108 | setOptionsView(this.optionsView);
109 | } catch (Exception e) {
110 | e.printStackTrace();
111 | }
112 | }
113 |
114 | public void setContentView(View contentView) {
115 | this.contentView = contentView;
116 | addChildren();
117 | requestLayout();
118 | }
119 |
120 | public void setContentResId(int contentResId) {
121 | this.contentResId = contentResId;
122 | try {
123 | this.contentView = inflateChild(contentResId);
124 | setContentView(this.contentView);
125 | } catch (Exception e) {
126 | e.printStackTrace();
127 | }
128 | }
129 |
130 | public void setContentBgColor(int contentBgColor) {
131 | this.contentBgColor = contentBgColor;
132 | hasContentBgColor = true;
133 | if (contentView != null) {
134 | contentView.setBackgroundColor(contentBgColor);
135 | }
136 | }
137 |
138 | public void setContentBgResId(int contentBgResId) {
139 | this.contentBgResId = contentBgResId;
140 | if (this.contentBgResId > 0) {
141 | contentView.setBackgroundResource(this.contentBgResId);
142 | }
143 | }
144 |
145 | public void setSlideDirection(SlideDirection slideDirection) {
146 | this.slideDirection = slideDirection.getIntValue();
147 | requestLayout();
148 | }
149 |
150 | public void setOptionsLayoutPosition(OptionsLayoutPosition optionsLayoutPosition) {
151 | this.optionsLayoutPosition = optionsLayoutPosition.getIntValue();
152 | requestLayout();
153 | }
154 |
155 | public void setOpened(boolean opened) {
156 | if (!canDrag) {
157 | opened = false;
158 | }
159 | if (isOpened != opened) {
160 | isOpened = opened;
161 | int optionsViewLeft = 0;
162 | int contentViewLeft = 0;
163 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
164 | //操作布局跟随在item的内容布局后面
165 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
166 | if (isOpened) {
167 | optionsViewLeft = 0;
168 | contentViewLeft = optionsView.getMeasuredWidth();
169 | } else {
170 | optionsViewLeft = -optionsView.getMeasuredWidth();
171 | contentViewLeft = 0;
172 | }
173 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
174 | if (isOpened) {
175 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
176 | contentViewLeft = -optionsView.getMeasuredWidth();
177 | } else {
178 | optionsViewLeft = contentView.getMeasuredWidth();
179 | contentViewLeft = 0;
180 | }
181 | }
182 | } else if (optionsLayoutPosition == OptionsLayoutPosition.FIXED.getIntValue()) {
183 | //固定操作布局
184 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
185 | optionsViewLeft = 0;
186 | if (isOpened) {
187 | contentViewLeft = optionsView.getMeasuredWidth();
188 | } else {
189 | contentViewLeft = 0;
190 | }
191 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
192 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
193 | if (isOpened) {
194 | contentViewLeft = -optionsView.getMeasuredWidth();
195 | } else {
196 | contentViewLeft = 0;
197 | }
198 | }
199 | }
200 | //注意下两行代码先后顺序
201 | helper.smoothSlideViewTo(optionsView, optionsViewLeft, 0);
202 | helper.smoothSlideViewTo(contentView, contentViewLeft, 0);
203 | //重绘,在view的onDraw里面会调用computeScroll()方法
204 | invalidate();
205 | if (onOptionsStateChangeListener != null) {
206 | onOptionsStateChangeListener.onOptionsViewChange(isOpened);
207 | }
208 | }
209 | }
210 |
211 | public SlideLayout(Context context) {
212 | this(context, null, 0);
213 | }
214 |
215 | public SlideLayout(Context context, AttributeSet attrs) {
216 | this(context, attrs, 0);
217 | }
218 |
219 | public SlideLayout(Context context, AttributeSet attrs, int defStyleAttr) {
220 | super(context, attrs, defStyleAttr);
221 | //初始化
222 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SlideLayout, defStyleAttr, 0);
223 | int size = array.getIndexCount();
224 | for (int i = 0; i < size; i++) {
225 | int attr = array.getIndex(i);
226 | if (attr == R.styleable.SlideLayout_contentResId) {//获取内容布局
227 | contentResId = array.getResourceId(attr, -1);
228 | } else if (attr == R.styleable.SlideLayout_optionsResId) {//获取操作布局
229 | optionsResId = array.getResourceId(attr, -1);
230 | } else if (attr == R.styleable.SlideLayout_slideDirection) {//获取item布局的滑动方向
231 | slideDirection = array.getInt(attr, SlideDirection.RIGHT.getIntValue());
232 | } else if (attr == R.styleable.SlideLayout_optionsLayoutPosition) {//获取item的操作布局摆放位置
233 | optionsLayoutPosition = array.getInt(attr, OptionsLayoutPosition.FOLLOW.getIntValue());
234 | } else if (attr == R.styleable.SlideLayout_contentBgColor) {//内容部分背景颜色
235 | contentBgColor = array.getColor(attr, Color.WHITE);
236 | hasContentBgColor = true;
237 | } else if (attr == R.styleable.SlideLayout_contentBgResId) {//内容部分背景资源id
238 | contentBgResId = array.getResourceId(attr, -1);
239 | } else if (attr == R.styleable.SlideLayout_canDrag) {//是否可以拖拽
240 | canDrag = array.getBoolean(attr, true);
241 | } else if (attr == R.styleable.SlideLayout_thresholdMoved) {//滑动最小阀值
242 | thresholdMoved = array.getDimensionPixelSize(attr, THRESHOLD_MOVED_VALUE);
243 | }
244 | }
245 | array.recycle();
246 | //构建dragHelper对象,监听当前容器的onTouchEvent事件
247 | helper = ViewDragHelper.create(this, new MyCallBack());
248 | }
249 |
250 | @Override
251 | protected void onFinishInflate() {
252 | try {
253 | optionsView = inflateChild(optionsResId);
254 | contentView = inflateChild(contentResId);
255 | } catch (Exception e) {
256 | e.printStackTrace();
257 | }
258 | addChildren();
259 | }
260 |
261 | private void addChildren() {
262 | if (getChildCount() > 0)
263 | removeAllViews();
264 | if (optionsView != null) {
265 | setRecursionClick(optionsView);
266 | //添加滑动操作选项view
267 | addView(optionsView);
268 | } else {
269 | throw new NullPointerException("view is null");
270 | }
271 | if (contentView != null) {
272 | if (contentBgResId > 0) {
273 | contentView.setBackgroundResource(contentBgResId);
274 | }
275 | if (hasContentBgColor) {
276 | contentView.setBackgroundColor(contentBgColor);
277 | }
278 | setRecursionClick(contentView);
279 | //添加内容view
280 | addView(contentView);
281 | } else {
282 | throw new NullPointerException("view is null");
283 | }
284 | }
285 |
286 | //递归设置点击事件
287 | private void setRecursionClick(View view) {
288 | if (view instanceof ViewGroup) {
289 | ViewGroup group = (ViewGroup) view;
290 | group.setOnClickListener(new OnClickListener() {
291 | @Override
292 | public void onClick(View v) {
293 | if (onChildClickListener != null) {
294 | onChildClickListener.onChildClick(v);
295 | }
296 | }
297 | });
298 | for (int i = 0; i < group.getChildCount(); i++) {
299 | setRecursionClick(group.getChildAt(i));
300 | }
301 | } else {
302 | view.setOnClickListener(new OnClickListener() {
303 | @Override
304 | public void onClick(View v) {
305 | if (onChildClickListener != null) {
306 | onChildClickListener.onChildClick(v);
307 | }
308 | }
309 | });
310 | }
311 | }
312 |
313 | //加载资源布局
314 | private View inflateChild(int resId) throws Exception {
315 | if (resId <= 0) {
316 | throw new IllegalArgumentException("resId is invalid!");
317 | }
318 | return LayoutInflater.from(this.getContext()).inflate(resId, this, false);
319 | }
320 |
321 | @Override
322 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
323 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
324 | //测量children的宽高属性
325 | measureChildren(widthMeasureSpec, heightMeasureSpec);
326 | }
327 |
328 | @Override
329 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
330 | //内容布局view
331 | contentView.layout(0, 0, contentView.getMeasuredWidth(), contentView.getMeasuredHeight());
332 | //操作布局view
333 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
334 | //操作布局跟随在item的内容布局后面
335 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
336 | optionsView.layout(-optionsView.getMeasuredWidth(), 0, 0, optionsView.getMeasuredHeight());
337 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
338 | optionsView.layout(contentView.getMeasuredWidth(), 0, contentView.getMeasuredWidth() + optionsView.getMeasuredWidth(), optionsView.getMeasuredHeight());
339 | }
340 | } else if (optionsLayoutPosition == OptionsLayoutPosition.FIXED.getIntValue()) {
341 | //固定操作布局
342 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
343 | optionsView.layout(0, 0, optionsView.getMeasuredWidth(), optionsView.getMeasuredHeight());
344 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
345 | optionsView.layout(contentView.getMeasuredWidth() - optionsView.getMeasuredWidth(), 0, contentView.getMeasuredWidth(), optionsView.getMeasuredHeight());
346 | }
347 | }
348 | }
349 |
350 | @Override
351 | public boolean onInterceptTouchEvent(MotionEvent ev) {
352 | if (!canDrag) {
353 | return false;
354 | }
355 | final int action = MotionEventCompat.getActionMasked(ev);
356 | if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
357 | if (helper != null)
358 | helper.cancel();
359 | return false;
360 | }
361 | if (helper != null) {
362 | return helper.shouldInterceptTouchEvent(ev);
363 | }
364 | return false;
365 | }
366 |
367 | @Override
368 | public boolean onTouchEvent(MotionEvent event) {
369 | if (!canDrag) {
370 | return false;
371 | }
372 | if (helper != null) {
373 | //helper接管onTouchEvent所有的事件
374 | helper.processTouchEvent(event);
375 | return true;
376 | }
377 | return false;
378 | }
379 |
380 | private class MyCallBack extends ViewDragHelper.Callback {
381 | /**
382 | * 尝试捕获需要drag的childView(ACTION_DOWN)
383 | *
384 | * @return : ViewDragHelper是否继续分析处理child的相关drag事件
385 | * @child : 需要drag的childView
386 | * @pointerId : 指针标识,多点触控的第几个手指按下
387 | */
388 | @Override
389 | public boolean tryCaptureView(View child, int pointerId) {
390 | //通过判断决定哪些childView需要处理拖动
391 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
392 | return contentView == child || optionsView == child;
393 | } else if (optionsLayoutPosition == OptionsLayoutPosition.FIXED.getIntValue()) {
394 | return contentView == child;
395 | }
396 | return false;
397 | }
398 |
399 | /**
400 | * child在某方向上被拖动时会调用对应方法,返回值是child移动过后的坐标位置
401 | *
402 | * @param child 移动的孩子View
403 | * @param left 父容器的左上角到孩子View的距离
404 | * @param dx 增量值,其实就是移动的孩子View的左上角距离控件(父亲)的距离,包含正负
405 | * @return 横向拖动的坐标位置
406 | */
407 | @Override
408 | public int clampViewPositionHorizontal(View child, int left, int dx) {
409 | //处理横向的拖动,left参数即为childView的left,为了防止越界,故需要判断left的范围。
410 | if (child == contentView) { // 解决内容部分左右拖动的越界问题
411 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
412 | if (left < 0) {
413 | left = 0;
414 | }
415 | if (left > optionsView.getMeasuredWidth()) {
416 | left = optionsView.getMeasuredWidth();
417 | }
418 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
419 | if (left > 0) {
420 | left = 0;
421 | }
422 | if (-left > optionsView.getMeasuredWidth()) {
423 | left = -optionsView.getMeasuredWidth();
424 | }
425 | }
426 | }
427 | if (child == optionsView && optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) { // 解决删除部分左右拖动的越界问题
428 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
429 | if (left > 0) {
430 | left = 0;
431 | }
432 | if (-left > optionsView.getMeasuredWidth()) {
433 | left = -optionsView.getMeasuredWidth();
434 | }
435 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
436 | if (left < contentView.getMeasuredWidth() - optionsView.getMeasuredWidth()) {
437 | left = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
438 | }
439 | if (left > contentView.getMeasuredWidth()) {
440 | left = contentView.getMeasuredWidth();
441 | }
442 | }
443 | }
444 | return left;
445 | }
446 |
447 | /**
448 | * child在某方向上被拖动时会调用对应方法,返回值是child移动过后的坐标位置
449 | *
450 | * @param child 要拖拽的子View实例
451 | * @param top 期望的移动后位置子View的top值
452 | * @param dy 移动的距离
453 | * @return 返回值为子View在最终位置时的top值,一般直接返回第二个参数即可
454 | */
455 | @Override
456 | public int clampViewPositionVertical(View child, int top, int dy) {
457 | return super.clampViewPositionVertical(child, top, dy);
458 | }
459 |
460 | /**
461 | * 如果ViewGroup的子控件会消耗点击事件,例如按钮,在触摸屏幕的时候就会先走onInterceptTouchEvent方法,
462 | * 判断是否可以捕获,而在判断的过程中会去判断另外两个回调的方法:getViewHorizontalDragRange
463 | * 和getViewVerticalDragRange,只有这两个方法返回大于0的值才能正常的捕获。
464 | *
465 | * @param child Child view to check
466 | * @return 返回给定的child在相应的方向上可以被拖动的最远距离,默认返回0
467 | */
468 | @Override
469 | public int getViewHorizontalDragRange(View child) {
470 | if (child == contentView) {
471 | return optionsView.getMeasuredWidth();
472 | } else if (child == optionsView) {
473 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
474 | return optionsView.getMeasuredWidth();
475 | }
476 | }
477 | return super.getViewHorizontalDragRange(child);
478 | }
479 |
480 | //返回给定的child在相应的方向上可以被拖动的最远距离,默认返回0
481 | @Override
482 | public int getViewVerticalDragRange(View child) {
483 | return super.getViewVerticalDragRange(child);
484 | }
485 |
486 | /**
487 | * 当View的位置改变时的回调
488 | *
489 | * @param changedView touch改变的view
490 | * @param left changedView的left
491 | * @param top changedView的top
492 | * @param dx x方向的上的增量值
493 | * @param dy y方向上的增量值
494 | */
495 | @Override
496 | public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
497 | if (movedLengthTemp < left) {
498 | slideDirectionRight = true;
499 | } else {
500 | slideDirectionRight = false;
501 | }
502 | movedLengthTemp = left;
503 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
504 | int tempLeft = 0;
505 | int tempRight = 0;
506 | if (changedView == contentView) {
507 | //如果移动的是contentView,根据contentView移动时的left和top重新布局optionsView
508 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
509 | tempLeft = left - optionsView.getMeasuredWidth();
510 | }
511 | if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
512 | tempLeft = left + contentView.getMeasuredWidth();
513 | }
514 | tempRight = tempLeft + optionsView.getMeasuredWidth();
515 | optionsView.layout(tempLeft, 0, tempRight, optionsView.getMeasuredHeight());
516 | }
517 | if (changedView == optionsView) {
518 | //如果移动的是optionsView,则需要手动给contentView布局定位
519 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
520 | tempLeft = left + optionsView.getMeasuredWidth();
521 | tempRight = tempLeft + contentView.getMeasuredWidth();
522 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
523 | tempLeft = left - contentView.getMeasuredWidth();
524 | tempRight = left;
525 | }
526 | contentView.layout(tempLeft, 0, tempRight, contentView.getMeasuredHeight());
527 | }
528 | }
529 | }
530 |
531 | /**
532 | * 相当于Touch的up的事件会回调onViewReleased这个方法
533 | *
534 | * @param releasedChild
535 | * @param xvel x方向的速率
536 | * @param yvel y方向的速率
537 | */
538 | @Override
539 | public void onViewReleased(View releasedChild, float xvel, float yvel) {
540 | //在ViewDragHelper.Callback的onViewReleased()方法里调用settleCapturedViewAt()、flingCapturedView(),
541 | //或在任意地方调用smoothSlideViewTo()方法
542 | int optionsViewLeft = 0;
543 | int contentViewLeft = 0;
544 | boolean isChange = false;
545 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
546 | //操作布局跟随在item的内容布局后面
547 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
548 | if (releasedChild == contentView) {
549 | if (slideDirectionRight) {//向右
550 | if (releasedChild.getLeft() > thresholdMoved) {
551 | isChange = true;
552 | optionsViewLeft = 0;
553 | contentViewLeft = optionsView.getMeasuredWidth();
554 | } else {
555 | isChange = false;
556 | optionsViewLeft = -optionsView.getMeasuredWidth();
557 | contentViewLeft = 0;
558 | }
559 | } else {//向左
560 | if (releasedChild.getLeft() < (optionsView.getMeasuredWidth() - thresholdMoved)) {
561 | isChange = true;
562 | optionsViewLeft = -optionsView.getMeasuredWidth();
563 | contentViewLeft = 0;
564 | } else {
565 | isChange = false;
566 | optionsViewLeft = 0;
567 | contentViewLeft = optionsView.getMeasuredWidth();
568 | }
569 | }
570 | } else if (releasedChild == optionsView) {
571 | if (slideDirectionRight) {//向右
572 | if (Math.abs(releasedChild.getLeft()) < optionsView.getMeasuredWidth() - thresholdMoved) {
573 | isChange = true;
574 | optionsViewLeft = 0;
575 | contentViewLeft = optionsView.getMeasuredWidth();
576 | } else {
577 | isChange = false;
578 | optionsViewLeft = -optionsView.getMeasuredWidth();
579 | contentViewLeft = 0;
580 | }
581 | } else {//向左
582 | if (Math.abs(releasedChild.getLeft()) > thresholdMoved) {
583 | isChange = true;
584 | optionsViewLeft = -optionsView.getMeasuredWidth();
585 | contentViewLeft = 0;
586 | } else {
587 | isChange = false;
588 | optionsViewLeft = 0;
589 | contentViewLeft = optionsView.getMeasuredWidth();
590 | }
591 | }
592 | }
593 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
594 | if (releasedChild == contentView) {
595 | if (slideDirectionRight) {//向右
596 | if (Math.abs(releasedChild.getLeft()) < optionsView.getMeasuredWidth() - thresholdMoved) {
597 | isChange = true;
598 | optionsViewLeft = contentView.getMeasuredWidth();
599 | contentViewLeft = 0;
600 | } else {
601 | isChange = false;
602 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
603 | contentViewLeft = -optionsView.getMeasuredWidth();
604 | }
605 | } else {//向左
606 | if (Math.abs(releasedChild.getLeft()) > thresholdMoved) {
607 | isChange = true;
608 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
609 | contentViewLeft = -optionsView.getMeasuredWidth();
610 | } else {
611 | isChange = false;
612 | optionsViewLeft = contentView.getMeasuredWidth();
613 | contentViewLeft = 0;
614 | }
615 | }
616 | } else if (releasedChild == optionsView) {
617 | if (slideDirectionRight) {//向右
618 | if (Math.abs(releasedChild.getLeft()) > contentView.getMeasuredWidth() - optionsView.getMeasuredWidth() + thresholdMoved) {
619 | isChange = true;
620 | optionsViewLeft = contentView.getMeasuredWidth();
621 | contentViewLeft = 0;
622 | } else {
623 | isChange = false;
624 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
625 | contentViewLeft = -optionsView.getMeasuredWidth();
626 | }
627 | } else {//向左
628 | if (Math.abs(releasedChild.getLeft()) < contentView.getMeasuredWidth() - thresholdMoved) {
629 | isChange = true;
630 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
631 | contentViewLeft = -optionsView.getMeasuredWidth();
632 | } else {
633 | isChange = false;
634 | optionsViewLeft = contentView.getMeasuredWidth();
635 | contentViewLeft = 0;
636 | }
637 | }
638 | }
639 | }
640 | } else if (optionsLayoutPosition == OptionsLayoutPosition.FIXED.getIntValue()) {
641 | //固定操作布局
642 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
643 | optionsViewLeft = 0;
644 | if (releasedChild == contentView) {
645 | if (slideDirectionRight) {//向右
646 | if (Math.abs(releasedChild.getLeft()) > thresholdMoved) {
647 | isChange = true;
648 | contentViewLeft = optionsView.getMeasuredWidth();
649 | } else {
650 | isChange = false;
651 | contentViewLeft = 0;
652 | }
653 | } else {//向左
654 | if (Math.abs(releasedChild.getLeft()) < optionsView.getMeasuredWidth() - thresholdMoved) {
655 | isChange = true;
656 | contentViewLeft = 0;
657 | } else {
658 | isChange = false;
659 | contentViewLeft = optionsView.getMeasuredWidth();
660 | }
661 | }
662 | }
663 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
664 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
665 | if (releasedChild == contentView) {
666 | if (slideDirectionRight) {//向右
667 | if (Math.abs(releasedChild.getLeft()) < optionsView.getMeasuredWidth() - thresholdMoved) {
668 | isChange = true;
669 | contentViewLeft = 0;
670 | } else {
671 | isChange = false;
672 | contentViewLeft = -optionsView.getMeasuredWidth();
673 | }
674 | } else {//向左
675 | if (Math.abs(releasedChild.getLeft()) > thresholdMoved) {
676 | isChange = true;
677 | contentViewLeft = -optionsView.getMeasuredWidth();
678 | } else {
679 | isChange = false;
680 | contentViewLeft = 0;
681 | }
682 | }
683 | }
684 | }
685 | }
686 | //注意下两行代码先后顺序
687 | helper.smoothSlideViewTo(optionsView, optionsViewLeft, 0);
688 | helper.smoothSlideViewTo(contentView, contentViewLeft, 0);
689 | //重绘,在view的onDraw里面会调用computeScroll()方法
690 | invalidate();
691 | if (onOptionsStateChangeListener != null && isChange != isOpened) {
692 | isOpened = isChange;
693 | onOptionsStateChangeListener.onOptionsViewChange(isOpened);
694 | }
695 | //方向判断标记重置
696 | movedLengthTemp = 0;
697 | }
698 | }
699 |
700 | @Override
701 | public void computeScroll() {
702 | if (helper != null && helper.continueSettling(true)) {
703 | //获取对应的left和top,继续重绘
704 | ViewCompat.postInvalidateOnAnimation(this);
705 | }
706 | }
707 |
708 | public interface OnOptionsStateChangeListener {
709 | void onOptionsViewChange(boolean isOpened);
710 | }
711 |
712 | public interface OnChildClickListener {
713 | void onChildClick(View view);
714 | }
715 |
716 | //滑动布局滑出的方向
717 | public enum SlideDirection {
718 | RIGHT(0), LEFT(1);
719 |
720 | SlideDirection(int intValue) {
721 | this.intValue = intValue;
722 | }
723 |
724 | private int intValue;
725 |
726 | public int getIntValue() {
727 | return intValue;
728 | }
729 | }
730 |
731 | //滑动布局的布局方式
732 | public enum OptionsLayoutPosition {
733 | FOLLOW(0), FIXED(1);
734 |
735 | OptionsLayoutPosition(int intValue) {
736 | this.intValue = intValue;
737 | }
738 |
739 | private int intValue;
740 |
741 | public int getIntValue() {
742 | return intValue;
743 | }
744 | }
745 | }
--------------------------------------------------------------------------------
/demo/SlideLayout_recyclerview/SlideLayout/src/main/java/com/duke/slidelayout/SlideLayout.java:
--------------------------------------------------------------------------------
1 | package com.duke.slidelayout;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Color;
6 | import android.support.v4.view.MotionEventCompat;
7 | import android.support.v4.view.ViewCompat;
8 | import android.support.v4.widget.ViewDragHelper;
9 | import android.util.AttributeSet;
10 | import android.view.LayoutInflater;
11 | import android.view.MotionEvent;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 |
15 | /**
16 | * @Author: duke
17 | * @DateTime: 2016-12-25 20:50
18 | * @Description: 侧滑操作布局
19 | */
20 | public class SlideLayout extends ViewGroup {
21 | private View optionsView;//item的滑动操作选项view
22 | private int optionsResId;
23 | private View contentView;//item的内容view
24 | private int contentResId;
25 |
26 | //记录滑动view上次的left值,以便根据此次的left判断滑动方向
27 | private int movedLengthTemp;
28 | private boolean slideDirectionRight;//记录滑动方向
29 | //滑动阀值
30 | private static final int THRESHOLD_MOVED_VALUE = 25;//px
31 | private int thresholdMoved = THRESHOLD_MOVED_VALUE;//px
32 |
33 | private int contentBgColor = Color.WHITE;//内容部分背景颜色
34 | private int contentBgResId;//内容部分背景资源id
35 | private boolean hasContentBgColor;//是否设置了content背景颜色
36 |
37 | //滑动方向:【从左侧、从右侧】
38 | private int slideDirection = SlideDirection.RIGHT.getIntValue();
39 | //操作菜单view摆放方式:【固定,跟随】
40 | private int optionsLayoutPosition = OptionsLayoutPosition.FIXED.getIntValue();
41 |
42 | private boolean isOpened = false;//是否有滑动出来的item
43 | private boolean canDrag = true;//是否可以拖拽
44 | private ViewDragHelper helper;//拖拽辅助类
45 | private OnOptionsStateChangeListener onOptionsStateChangeListener;
46 | private OnChildClickListener onChildClickListener;
47 |
48 | public void setOnChildClickListener(OnChildClickListener l) {
49 | this.onChildClickListener = l;
50 | }
51 |
52 | public void setOnOptionsStateChangeListener(OnOptionsStateChangeListener l) {
53 | this.onOptionsStateChangeListener = l;
54 | }
55 |
56 | public View getOptionsView() {
57 | return optionsView;
58 | }
59 |
60 | public View getContentView() {
61 | return contentView;
62 | }
63 |
64 | public int getThresholdMoved() {
65 | return thresholdMoved;
66 | }
67 |
68 | /**
69 | * 设置滑动阀值
70 | *
71 | * @param thresholdMovedDP dp or dp of dimens
72 | */
73 | public void setThresholdMoved(int thresholdMovedDP) {
74 | this.thresholdMoved = getContext().getResources().getDimensionPixelSize(thresholdMoved);
75 | }
76 |
77 | public int getSlideDirection() {
78 | return slideDirection;
79 | }
80 |
81 | public int getOptionsLayoutPosition() {
82 | return optionsLayoutPosition;
83 | }
84 |
85 | public boolean isCanDrag() {
86 | return canDrag;
87 | }
88 |
89 | public void setCanDrag(boolean canDrag) {
90 | this.canDrag = canDrag;
91 | setOpened(false);
92 | }
93 |
94 | public boolean isOpened() {
95 | return isOpened;
96 | }
97 |
98 | public void setOptionsView(View optionsView) {
99 | this.optionsView = optionsView;
100 | addChildren();
101 | requestLayout();
102 | }
103 |
104 | public void setOptionsResId(int optionsResId) {
105 | this.optionsResId = optionsResId;
106 | try {
107 | this.optionsView = inflateChild(optionsResId);
108 | setOptionsView(this.optionsView);
109 | } catch (Exception e) {
110 | e.printStackTrace();
111 | }
112 | }
113 |
114 | public void setContentView(View contentView) {
115 | this.contentView = contentView;
116 | addChildren();
117 | requestLayout();
118 | }
119 |
120 | public void setContentResId(int contentResId) {
121 | this.contentResId = contentResId;
122 | try {
123 | this.contentView = inflateChild(contentResId);
124 | setContentView(this.contentView);
125 | } catch (Exception e) {
126 | e.printStackTrace();
127 | }
128 | }
129 |
130 | public void setContentBgColor(int contentBgColor) {
131 | this.contentBgColor = contentBgColor;
132 | hasContentBgColor = true;
133 | if (contentView != null) {
134 | contentView.setBackgroundColor(contentBgColor);
135 | }
136 | }
137 |
138 | public void setContentBgResId(int contentBgResId) {
139 | this.contentBgResId = contentBgResId;
140 | if (this.contentBgResId > 0) {
141 | contentView.setBackgroundResource(this.contentBgResId);
142 | }
143 | }
144 |
145 | public void setSlideDirection(SlideDirection slideDirection) {
146 | this.slideDirection = slideDirection.getIntValue();
147 | requestLayout();
148 | }
149 |
150 | public void setOptionsLayoutPosition(OptionsLayoutPosition optionsLayoutPosition) {
151 | this.optionsLayoutPosition = optionsLayoutPosition.getIntValue();
152 | requestLayout();
153 | }
154 |
155 | public void setOpened(boolean opened) {
156 | if (!canDrag) {
157 | opened = false;
158 | }
159 | if (isOpened != opened) {
160 | isOpened = opened;
161 | int optionsViewLeft = 0;
162 | int contentViewLeft = 0;
163 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
164 | //操作布局跟随在item的内容布局后面
165 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
166 | if (isOpened) {
167 | optionsViewLeft = 0;
168 | contentViewLeft = optionsView.getMeasuredWidth();
169 | } else {
170 | optionsViewLeft = -optionsView.getMeasuredWidth();
171 | contentViewLeft = 0;
172 | }
173 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
174 | if (isOpened) {
175 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
176 | contentViewLeft = -optionsView.getMeasuredWidth();
177 | } else {
178 | optionsViewLeft = contentView.getMeasuredWidth();
179 | contentViewLeft = 0;
180 | }
181 | }
182 | } else if (optionsLayoutPosition == OptionsLayoutPosition.FIXED.getIntValue()) {
183 | //固定操作布局
184 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
185 | optionsViewLeft = 0;
186 | if (isOpened) {
187 | contentViewLeft = optionsView.getMeasuredWidth();
188 | } else {
189 | contentViewLeft = 0;
190 | }
191 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
192 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
193 | if (isOpened) {
194 | contentViewLeft = -optionsView.getMeasuredWidth();
195 | } else {
196 | contentViewLeft = 0;
197 | }
198 | }
199 | }
200 | //注意下两行代码先后顺序
201 | helper.smoothSlideViewTo(optionsView, optionsViewLeft, 0);
202 | helper.smoothSlideViewTo(contentView, contentViewLeft, 0);
203 | //重绘,在view的onDraw里面会调用computeScroll()方法
204 | invalidate();
205 | if (onOptionsStateChangeListener != null) {
206 | onOptionsStateChangeListener.onOptionsViewChange(isOpened);
207 | }
208 | }
209 | }
210 |
211 | public SlideLayout(Context context) {
212 | this(context, null, 0);
213 | }
214 |
215 | public SlideLayout(Context context, AttributeSet attrs) {
216 | this(context, attrs, 0);
217 | }
218 |
219 | public SlideLayout(Context context, AttributeSet attrs, int defStyleAttr) {
220 | super(context, attrs, defStyleAttr);
221 | //初始化
222 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SlideLayout, defStyleAttr, 0);
223 | int size = array.getIndexCount();
224 | for (int i = 0; i < size; i++) {
225 | int attr = array.getIndex(i);
226 | if (attr == R.styleable.SlideLayout_contentResId) {//获取内容布局
227 | contentResId = array.getResourceId(attr, -1);
228 | } else if (attr == R.styleable.SlideLayout_optionsResId) {//获取操作布局
229 | optionsResId = array.getResourceId(attr, -1);
230 | } else if (attr == R.styleable.SlideLayout_slideDirection) {//获取item布局的滑动方向
231 | slideDirection = array.getInt(attr, SlideDirection.RIGHT.getIntValue());
232 | } else if (attr == R.styleable.SlideLayout_optionsLayoutPosition) {//获取item的操作布局摆放位置
233 | optionsLayoutPosition = array.getInt(attr, OptionsLayoutPosition.FOLLOW.getIntValue());
234 | } else if (attr == R.styleable.SlideLayout_contentBgColor) {//内容部分背景颜色
235 | contentBgColor = array.getColor(attr, Color.WHITE);
236 | hasContentBgColor = true;
237 | } else if (attr == R.styleable.SlideLayout_contentBgResId) {//内容部分背景资源id
238 | contentBgResId = array.getResourceId(attr, -1);
239 | } else if (attr == R.styleable.SlideLayout_canDrag) {//是否可以拖拽
240 | canDrag = array.getBoolean(attr, true);
241 | } else if (attr == R.styleable.SlideLayout_thresholdMoved) {//滑动最小阀值
242 | thresholdMoved = array.getDimensionPixelSize(attr, THRESHOLD_MOVED_VALUE);
243 | }
244 | }
245 | array.recycle();
246 | //构建dragHelper对象,监听当前容器的onTouchEvent事件
247 | helper = ViewDragHelper.create(this, new MyCallBack());
248 | }
249 |
250 | @Override
251 | protected void onFinishInflate() {
252 | try {
253 | optionsView = inflateChild(optionsResId);
254 | contentView = inflateChild(contentResId);
255 | } catch (Exception e) {
256 | e.printStackTrace();
257 | }
258 | addChildren();
259 | }
260 |
261 | private void addChildren() {
262 | if (getChildCount() > 0)
263 | removeAllViews();
264 | if (optionsView != null) {
265 | setRecursionClick(optionsView);
266 | //添加滑动操作选项view
267 | addView(optionsView);
268 | } else {
269 | throw new NullPointerException("view is null");
270 | }
271 | if (contentView != null) {
272 | if (contentBgResId > 0) {
273 | contentView.setBackgroundResource(contentBgResId);
274 | }
275 | if (hasContentBgColor) {
276 | contentView.setBackgroundColor(contentBgColor);
277 | }
278 | setRecursionClick(contentView);
279 | //添加内容view
280 | addView(contentView);
281 | } else {
282 | throw new NullPointerException("view is null");
283 | }
284 | }
285 |
286 | //递归设置点击事件
287 | private void setRecursionClick(View view) {
288 | if (view instanceof ViewGroup) {
289 | ViewGroup group = (ViewGroup) view;
290 | group.setOnClickListener(new OnClickListener() {
291 | @Override
292 | public void onClick(View v) {
293 | if (onChildClickListener != null) {
294 | onChildClickListener.onChildClick(v);
295 | }
296 | }
297 | });
298 | for (int i = 0; i < group.getChildCount(); i++) {
299 | setRecursionClick(group.getChildAt(i));
300 | }
301 | } else {
302 | view.setOnClickListener(new OnClickListener() {
303 | @Override
304 | public void onClick(View v) {
305 | if (onChildClickListener != null) {
306 | onChildClickListener.onChildClick(v);
307 | }
308 | }
309 | });
310 | }
311 | }
312 |
313 | //加载资源布局
314 | private View inflateChild(int resId) throws Exception {
315 | if (resId <= 0) {
316 | throw new IllegalArgumentException("resId is invalid!");
317 | }
318 | return LayoutInflater.from(this.getContext()).inflate(resId, this, false);
319 | }
320 |
321 | @Override
322 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
323 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
324 | //测量children的宽高属性
325 | measureChildren(widthMeasureSpec, heightMeasureSpec);
326 | }
327 |
328 | @Override
329 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
330 | //内容布局view
331 | contentView.layout(0, 0, contentView.getMeasuredWidth(), contentView.getMeasuredHeight());
332 | //操作布局view
333 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
334 | //操作布局跟随在item的内容布局后面
335 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
336 | optionsView.layout(-optionsView.getMeasuredWidth(), 0, 0, optionsView.getMeasuredHeight());
337 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
338 | optionsView.layout(contentView.getMeasuredWidth(), 0, contentView.getMeasuredWidth() + optionsView.getMeasuredWidth(), optionsView.getMeasuredHeight());
339 | }
340 | } else if (optionsLayoutPosition == OptionsLayoutPosition.FIXED.getIntValue()) {
341 | //固定操作布局
342 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
343 | optionsView.layout(0, 0, optionsView.getMeasuredWidth(), optionsView.getMeasuredHeight());
344 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
345 | optionsView.layout(contentView.getMeasuredWidth() - optionsView.getMeasuredWidth(), 0, contentView.getMeasuredWidth(), optionsView.getMeasuredHeight());
346 | }
347 | }
348 | }
349 |
350 | @Override
351 | public boolean onInterceptTouchEvent(MotionEvent ev) {
352 | if (!canDrag) {
353 | return false;
354 | }
355 | final int action = MotionEventCompat.getActionMasked(ev);
356 | if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
357 | if (helper != null)
358 | helper.cancel();
359 | return false;
360 | }
361 | if (helper != null) {
362 | return helper.shouldInterceptTouchEvent(ev);
363 | }
364 | return false;
365 | }
366 |
367 | @Override
368 | public boolean onTouchEvent(MotionEvent event) {
369 | if (!canDrag) {
370 | return false;
371 | }
372 | if (helper != null) {
373 | //helper接管onTouchEvent所有的事件
374 | helper.processTouchEvent(event);
375 | return true;
376 | }
377 | return false;
378 | }
379 |
380 | private class MyCallBack extends ViewDragHelper.Callback {
381 | /**
382 | * 尝试捕获需要drag的childView(ACTION_DOWN)
383 | *
384 | * @return : ViewDragHelper是否继续分析处理child的相关drag事件
385 | * @child : 需要drag的childView
386 | * @pointerId : 指针标识,多点触控的第几个手指按下
387 | */
388 | @Override
389 | public boolean tryCaptureView(View child, int pointerId) {
390 | //通过判断决定哪些childView需要处理拖动
391 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
392 | return contentView == child || optionsView == child;
393 | } else if (optionsLayoutPosition == OptionsLayoutPosition.FIXED.getIntValue()) {
394 | return contentView == child;
395 | }
396 | return false;
397 | }
398 |
399 | /**
400 | * child在某方向上被拖动时会调用对应方法,返回值是child移动过后的坐标位置
401 | *
402 | * @param child 移动的孩子View
403 | * @param left 父容器的左上角到孩子View的距离
404 | * @param dx 增量值,其实就是移动的孩子View的左上角距离控件(父亲)的距离,包含正负
405 | * @return 横向拖动的坐标位置
406 | */
407 | @Override
408 | public int clampViewPositionHorizontal(View child, int left, int dx) {
409 | //处理横向的拖动,left参数即为childView的left,为了防止越界,故需要判断left的范围。
410 | if (child == contentView) { // 解决内容部分左右拖动的越界问题
411 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
412 | if (left < 0) {
413 | left = 0;
414 | }
415 | if (left > optionsView.getMeasuredWidth()) {
416 | left = optionsView.getMeasuredWidth();
417 | }
418 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
419 | if (left > 0) {
420 | left = 0;
421 | }
422 | if (-left > optionsView.getMeasuredWidth()) {
423 | left = -optionsView.getMeasuredWidth();
424 | }
425 | }
426 | }
427 | if (child == optionsView && optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) { // 解决删除部分左右拖动的越界问题
428 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
429 | if (left > 0) {
430 | left = 0;
431 | }
432 | if (-left > optionsView.getMeasuredWidth()) {
433 | left = -optionsView.getMeasuredWidth();
434 | }
435 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
436 | if (left < contentView.getMeasuredWidth() - optionsView.getMeasuredWidth()) {
437 | left = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
438 | }
439 | if (left > contentView.getMeasuredWidth()) {
440 | left = contentView.getMeasuredWidth();
441 | }
442 | }
443 | }
444 | return left;
445 | }
446 |
447 | /**
448 | * child在某方向上被拖动时会调用对应方法,返回值是child移动过后的坐标位置
449 | *
450 | * @param child 要拖拽的子View实例
451 | * @param top 期望的移动后位置子View的top值
452 | * @param dy 移动的距离
453 | * @return 返回值为子View在最终位置时的top值,一般直接返回第二个参数即可
454 | */
455 | @Override
456 | public int clampViewPositionVertical(View child, int top, int dy) {
457 | return super.clampViewPositionVertical(child, top, dy);
458 | }
459 |
460 | /**
461 | * 如果ViewGroup的子控件会消耗点击事件,例如按钮,在触摸屏幕的时候就会先走onInterceptTouchEvent方法,
462 | * 判断是否可以捕获,而在判断的过程中会去判断另外两个回调的方法:getViewHorizontalDragRange
463 | * 和getViewVerticalDragRange,只有这两个方法返回大于0的值才能正常的捕获。
464 | *
465 | * @param child Child view to check
466 | * @return 返回给定的child在相应的方向上可以被拖动的最远距离,默认返回0
467 | */
468 | @Override
469 | public int getViewHorizontalDragRange(View child) {
470 | if (child == contentView) {
471 | return optionsView.getMeasuredWidth();
472 | } else if (child == optionsView) {
473 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
474 | return optionsView.getMeasuredWidth();
475 | }
476 | }
477 | return super.getViewHorizontalDragRange(child);
478 | }
479 |
480 | //返回给定的child在相应的方向上可以被拖动的最远距离,默认返回0
481 | @Override
482 | public int getViewVerticalDragRange(View child) {
483 | return super.getViewVerticalDragRange(child);
484 | }
485 |
486 | /**
487 | * 当View的位置改变时的回调
488 | *
489 | * @param changedView touch改变的view
490 | * @param left changedView的left
491 | * @param top changedView的top
492 | * @param dx x方向的上的增量值
493 | * @param dy y方向上的增量值
494 | */
495 | @Override
496 | public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
497 | if (movedLengthTemp < left) {
498 | slideDirectionRight = true;
499 | } else {
500 | slideDirectionRight = false;
501 | }
502 | movedLengthTemp = left;
503 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
504 | int tempLeft = 0;
505 | int tempRight = 0;
506 | if (changedView == contentView) {
507 | //如果移动的是contentView,根据contentView移动时的left和top重新布局optionsView
508 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
509 | tempLeft = left - optionsView.getMeasuredWidth();
510 | }
511 | if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
512 | tempLeft = left + contentView.getMeasuredWidth();
513 | }
514 | tempRight = tempLeft + optionsView.getMeasuredWidth();
515 | optionsView.layout(tempLeft, 0, tempRight, optionsView.getMeasuredHeight());
516 | }
517 | if (changedView == optionsView) {
518 | //如果移动的是optionsView,则需要手动给contentView布局定位
519 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
520 | tempLeft = left + optionsView.getMeasuredWidth();
521 | tempRight = tempLeft + contentView.getMeasuredWidth();
522 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
523 | tempLeft = left - contentView.getMeasuredWidth();
524 | tempRight = left;
525 | }
526 | contentView.layout(tempLeft, 0, tempRight, contentView.getMeasuredHeight());
527 | }
528 | }
529 | }
530 |
531 | /**
532 | * 相当于Touch的up的事件会回调onViewReleased这个方法
533 | *
534 | * @param releasedChild
535 | * @param xvel x方向的速率
536 | * @param yvel y方向的速率
537 | */
538 | @Override
539 | public void onViewReleased(View releasedChild, float xvel, float yvel) {
540 | //在ViewDragHelper.Callback的onViewReleased()方法里调用settleCapturedViewAt()、flingCapturedView(),
541 | //或在任意地方调用smoothSlideViewTo()方法
542 | int optionsViewLeft = 0;
543 | int contentViewLeft = 0;
544 | boolean isChange = false;
545 | if (optionsLayoutPosition == OptionsLayoutPosition.FOLLOW.getIntValue()) {
546 | //操作布局跟随在item的内容布局后面
547 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
548 | if (releasedChild == contentView) {
549 | if (slideDirectionRight) {//向右
550 | if (releasedChild.getLeft() > thresholdMoved) {
551 | isChange = true;
552 | optionsViewLeft = 0;
553 | contentViewLeft = optionsView.getMeasuredWidth();
554 | } else {
555 | isChange = false;
556 | optionsViewLeft = -optionsView.getMeasuredWidth();
557 | contentViewLeft = 0;
558 | }
559 | } else {//向左
560 | if (releasedChild.getLeft() < (optionsView.getMeasuredWidth() - thresholdMoved)) {
561 | isChange = true;
562 | optionsViewLeft = -optionsView.getMeasuredWidth();
563 | contentViewLeft = 0;
564 | } else {
565 | isChange = false;
566 | optionsViewLeft = 0;
567 | contentViewLeft = optionsView.getMeasuredWidth();
568 | }
569 | }
570 | } else if (releasedChild == optionsView) {
571 | if (slideDirectionRight) {//向右
572 | if (Math.abs(releasedChild.getLeft()) < optionsView.getMeasuredWidth() - thresholdMoved) {
573 | isChange = true;
574 | optionsViewLeft = 0;
575 | contentViewLeft = optionsView.getMeasuredWidth();
576 | } else {
577 | isChange = false;
578 | optionsViewLeft = -optionsView.getMeasuredWidth();
579 | contentViewLeft = 0;
580 | }
581 | } else {//向左
582 | if (Math.abs(releasedChild.getLeft()) > thresholdMoved) {
583 | isChange = true;
584 | optionsViewLeft = -optionsView.getMeasuredWidth();
585 | contentViewLeft = 0;
586 | } else {
587 | isChange = false;
588 | optionsViewLeft = 0;
589 | contentViewLeft = optionsView.getMeasuredWidth();
590 | }
591 | }
592 | }
593 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
594 | if (releasedChild == contentView) {
595 | if (slideDirectionRight) {//向右
596 | if (Math.abs(releasedChild.getLeft()) < optionsView.getMeasuredWidth() - thresholdMoved) {
597 | isChange = true;
598 | optionsViewLeft = contentView.getMeasuredWidth();
599 | contentViewLeft = 0;
600 | } else {
601 | isChange = false;
602 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
603 | contentViewLeft = -optionsView.getMeasuredWidth();
604 | }
605 | } else {//向左
606 | if (Math.abs(releasedChild.getLeft()) > thresholdMoved) {
607 | isChange = true;
608 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
609 | contentViewLeft = -optionsView.getMeasuredWidth();
610 | } else {
611 | isChange = false;
612 | optionsViewLeft = contentView.getMeasuredWidth();
613 | contentViewLeft = 0;
614 | }
615 | }
616 | } else if (releasedChild == optionsView) {
617 | if (slideDirectionRight) {//向右
618 | if (Math.abs(releasedChild.getLeft()) > contentView.getMeasuredWidth() - optionsView.getMeasuredWidth() + thresholdMoved) {
619 | isChange = true;
620 | optionsViewLeft = contentView.getMeasuredWidth();
621 | contentViewLeft = 0;
622 | } else {
623 | isChange = false;
624 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
625 | contentViewLeft = -optionsView.getMeasuredWidth();
626 | }
627 | } else {//向左
628 | if (Math.abs(releasedChild.getLeft()) < contentView.getMeasuredWidth() - thresholdMoved) {
629 | isChange = true;
630 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
631 | contentViewLeft = -optionsView.getMeasuredWidth();
632 | } else {
633 | isChange = false;
634 | optionsViewLeft = contentView.getMeasuredWidth();
635 | contentViewLeft = 0;
636 | }
637 | }
638 | }
639 | }
640 | } else if (optionsLayoutPosition == OptionsLayoutPosition.FIXED.getIntValue()) {
641 | //固定操作布局
642 | if (slideDirection == SlideDirection.LEFT.getIntValue()) {
643 | optionsViewLeft = 0;
644 | if (releasedChild == contentView) {
645 | if (slideDirectionRight) {//向右
646 | if (Math.abs(releasedChild.getLeft()) > thresholdMoved) {
647 | isChange = true;
648 | contentViewLeft = optionsView.getMeasuredWidth();
649 | } else {
650 | isChange = false;
651 | contentViewLeft = 0;
652 | }
653 | } else {//向左
654 | if (Math.abs(releasedChild.getLeft()) < optionsView.getMeasuredWidth() - thresholdMoved) {
655 | isChange = true;
656 | contentViewLeft = 0;
657 | } else {
658 | isChange = false;
659 | contentViewLeft = optionsView.getMeasuredWidth();
660 | }
661 | }
662 | }
663 | } else if (slideDirection == SlideDirection.RIGHT.getIntValue()) {
664 | optionsViewLeft = contentView.getMeasuredWidth() - optionsView.getMeasuredWidth();
665 | if (releasedChild == contentView) {
666 | if (slideDirectionRight) {//向右
667 | if (Math.abs(releasedChild.getLeft()) < optionsView.getMeasuredWidth() - thresholdMoved) {
668 | isChange = true;
669 | contentViewLeft = 0;
670 | } else {
671 | isChange = false;
672 | contentViewLeft = -optionsView.getMeasuredWidth();
673 | }
674 | } else {//向左
675 | if (Math.abs(releasedChild.getLeft()) > thresholdMoved) {
676 | isChange = true;
677 | contentViewLeft = -optionsView.getMeasuredWidth();
678 | } else {
679 | isChange = false;
680 | contentViewLeft = 0;
681 | }
682 | }
683 | }
684 | }
685 | }
686 | //注意下两行代码先后顺序
687 | helper.smoothSlideViewTo(optionsView, optionsViewLeft, 0);
688 | helper.smoothSlideViewTo(contentView, contentViewLeft, 0);
689 | //重绘,在view的onDraw里面会调用computeScroll()方法
690 | invalidate();
691 | if (onOptionsStateChangeListener != null && isChange != isOpened) {
692 | isOpened = isChange;
693 | onOptionsStateChangeListener.onOptionsViewChange(isOpened);
694 | }
695 | //方向判断标记重置
696 | movedLengthTemp = 0;
697 | }
698 | }
699 |
700 | @Override
701 | public void computeScroll() {
702 | if (helper != null && helper.continueSettling(true)) {
703 | //获取对应的left和top,继续重绘
704 | ViewCompat.postInvalidateOnAnimation(this);
705 | }
706 | }
707 |
708 | public interface OnOptionsStateChangeListener {
709 | void onOptionsViewChange(boolean isOpened);
710 | }
711 |
712 | public interface OnChildClickListener {
713 | void onChildClick(View view);
714 | }
715 |
716 | //滑动布局滑出的方向
717 | public enum SlideDirection {
718 | RIGHT(0), LEFT(1);
719 |
720 | SlideDirection(int intValue) {
721 | this.intValue = intValue;
722 | }
723 |
724 | private int intValue;
725 |
726 | public int getIntValue() {
727 | return intValue;
728 | }
729 | }
730 |
731 | //滑动布局的布局方式
732 | public enum OptionsLayoutPosition {
733 | FOLLOW(0), FIXED(1);
734 |
735 | OptionsLayoutPosition(int intValue) {
736 | this.intValue = intValue;
737 | }
738 |
739 | private int intValue;
740 |
741 | public int getIntValue() {
742 | return intValue;
743 | }
744 | }
745 | }
--------------------------------------------------------------------------------