├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── RangeSliderView.iml ├── build.gradle ├── gradle-mvn-push.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── gradle.properties ├── library.iml ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── github │ │ └── channguyen │ │ └── rsv │ │ ├── AnimateMethod.java │ │ └── RangeSliderView.java │ └── res │ └── values │ ├── attrs.xml │ └── strings.xml ├── range-slider-view.iml ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── sample.iml └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── chan │ │ └── rsv │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── chan │ │ └── rsv │ │ └── sample │ │ └── MainActivity.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── screenshots └── sc.png ├── settings.gradle └── trace.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | # Proguard folder generated by Eclipse 23 | proguard/ 24 | 25 | # Log Files 26 | *.log 27 | 28 | .idea/ 29 | .DS_Store 30 | *.iml -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | range-slider-view -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | Android API 22 Platform 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RangeSliderView 2 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.channguyen/rsv/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.channguyen/rsv) 3 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-RangeSliderView-green.svg?style=flat)](https://android-arsenal.com/details/1/2511) 4 | 5 | # Screenshots 6 | ![Main screen](/screenshots/sc.png) 7 | 8 | # Features 9 | - Ripple effect. 10 | - Option to set custom colors for slider. 11 | - Option to set custom height for slider. 12 | - Option to set custom radius for slider. 13 | 14 | # Usage 15 | Add a dependency to your `build.gradle`: 16 | ``` 17 | dependencies { 18 | compile 'com.github.channguyen:rsv:1.0.1' 19 | } 20 | ``` 21 | Add the `com.github.channguyen.rsv.RangeSliderView` to your layout XML file. 22 | ```XML 23 | 30 | 31 | 40 | 41 | 42 | 51 | 52 | 53 | ``` 54 | 55 | For more usage examples check the **sample** project. 56 | 57 | ### Changelog 58 | 59 | **Version 1.0.1** 60 | + Bug fixes for layout param 61 | 62 | 63 | **Version 1.0.0** 64 | + First release 65 | 66 | 67 | # License 68 | ``` 69 | Copyright 2015 Chan Nguyen 70 | 71 | Licensed under the Apache License, Version 2.0 (the "License"); 72 | you may not use this file except in compliance with the License. 73 | You may obtain a copy of the License at 74 | 75 | http://www.apache.org/licenses/LICENSE-2.0 76 | 77 | Unless required by applicable law or agreed to in writing, software 78 | distributed under the License is distributed on an "AS IS" BASIS, 79 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 80 | See the License for the specific language governing permissions and 81 | limitations under the License. 82 | ``` 83 | -------------------------------------------------------------------------------- /RangeSliderView.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /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:1.3.0' 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 | -------------------------------------------------------------------------------- /gradle-mvn-push.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Chris Banes 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply plugin: 'maven' 18 | apply plugin: 'signing' 19 | 20 | def isReleaseBuild() { 21 | return VERSION_NAME.contains("SNAPSHOT") == false 22 | } 23 | 24 | def getReleaseRepositoryUrl() { 25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL 26 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 27 | } 28 | 29 | def getSnapshotRepositoryUrl() { 30 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL 31 | : "https://oss.sonatype.org/content/repositories/snapshots/" 32 | } 33 | 34 | def getRepositoryUsername() { 35 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" 36 | } 37 | 38 | def getRepositoryPassword() { 39 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" 40 | } 41 | 42 | afterEvaluate { project -> 43 | uploadArchives { 44 | repositories { 45 | mavenDeployer { 46 | beforeDeployment { 47 | MavenDeployment deployment -> signing.signPom(deployment) 48 | } 49 | 50 | pom.groupId = GROUP 51 | pom.artifactId = POM_ARTIFACT_ID 52 | pom.version = VERSION_NAME 53 | 54 | repository(url: getReleaseRepositoryUrl()) { 55 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 56 | } 57 | 58 | snapshotRepository(url: getSnapshotRepositoryUrl()) { 59 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 60 | } 61 | 62 | pom.project { 63 | name POM_NAME 64 | packaging POM_PACKAGING 65 | description POM_DESCRIPTION 66 | url POM_URL 67 | 68 | scm { 69 | url POM_SCM_URL 70 | connection POM_SCM_CONNECTION 71 | developerConnection POM_SCM_DEV_CONNECTION 72 | } 73 | 74 | licenses { 75 | license { 76 | name POM_LICENCE_NAME 77 | url POM_LICENCE_URL 78 | distribution POM_LICENCE_DIST 79 | } 80 | } 81 | 82 | developers { 83 | developer { 84 | id POM_DEVELOPER_ID 85 | name POM_DEVELOPER_NAME 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | signing { 94 | required { 95 | isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") 96 | } 97 | sign configurations.archives 98 | } 99 | 100 | task androidJavadocs(type: Javadoc) { 101 | source = android.sourceSets.main.java.srcDirs 102 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 103 | } 104 | 105 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { 106 | classifier = 'javadoc' 107 | from androidJavadocs.destinationDir 108 | } 109 | 110 | task androidSourcesJar(type: Jar) { 111 | classifier = 'sources' 112 | from android.sourceSets.main.java.sourceFiles 113 | } 114 | 115 | artifacts { 116 | archives androidSourcesJar 117 | archives androidJavadocsJar 118 | } 119 | } -------------------------------------------------------------------------------- /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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | VERSION_NAME=1.0.1 21 | VERSION_CODE=10001 22 | GROUP=com.github.channguyen 23 | 24 | POM_DESCRIPTION=Range Slider View implementation for Android 25 | POM_URL=https://github.com/channguyen/range-slider-view 26 | POM_SCM_URL=https://github.com/channguyen/range-slider-view 27 | POM_SCM_CONNECTION=scm:git@github.com:range-slider-view.git 28 | POM_SCM_DEV_CONNECTION=scm:git@github.com:range-slider-view.git 29 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 30 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 31 | POM_LICENCE_DIST=repo 32 | POM_DEVELOPER_ID=chan 33 | POM_DEVELOPER_NAME=Chan Nguyen -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/c0x12c/range-slider-view/6f92c734237f9343062af20b3ea76cb3d7792bb2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Sep 14 20:33:02 PDT 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.4-all.zip 7 | -------------------------------------------------------------------------------- /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 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | } 24 | 25 | apply from: '../gradle-mvn-push.gradle' 26 | -------------------------------------------------------------------------------- /library/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Range Slider View Library 2 | POM_ARTIFACT_ID=rsv 3 | POM_PACKAGING=aar 4 | -------------------------------------------------------------------------------- /library/library.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /library/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 /Users/chan/Desktop/android/sdk/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 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/channguyen/rsv/AnimateMethod.java: -------------------------------------------------------------------------------- 1 | package com.github.channguyen.rsv; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target(ElementType.METHOD) 10 | @Retention(RetentionPolicy.SOURCE) 11 | public @interface AnimateMethod { 12 | } 13 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/channguyen/rsv/RangeSliderView.java: -------------------------------------------------------------------------------- 1 | package com.github.channguyen.rsv; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.content.Context; 6 | import android.content.res.TypedArray; 7 | import android.graphics.*; 8 | import android.os.Parcel; 9 | import android.os.Parcelable; 10 | import android.util.AttributeSet; 11 | import android.view.MotionEvent; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.view.ViewTreeObserver; 15 | import android.view.animation.AccelerateInterpolator; 16 | 17 | import java.util.concurrent.TimeUnit; 18 | 19 | public class RangeSliderView extends View { 20 | 21 | private static final String TAG = RangeSliderView.class.getSimpleName(); 22 | 23 | private static final long RIPPLE_ANIMATION_DURATION_MS = TimeUnit.MILLISECONDS.toMillis(700); 24 | 25 | private static final int DEFAULT_PAINT_STROKE_WIDTH = 5; 26 | 27 | private static final int DEFAULT_FILLED_COLOR = Color.parseColor("#FFA500"); 28 | 29 | private static final int DEFAULT_EMPTY_COLOR = Color.parseColor("#C3C3C3"); 30 | 31 | private static final float DEFAULT_BAR_HEIGHT_PERCENT = 0.10f; 32 | 33 | private static final float DEFAULT_SLOT_RADIUS_PERCENT = 0.125f; 34 | 35 | private static final float DEFAULT_SLIDER_RADIUS_PERCENT = 0.25f; 36 | 37 | private static final int DEFAULT_RANGE_COUNT = 5; 38 | 39 | private static final int DEFAULT_HEIGHT_IN_DP = 50; 40 | 41 | protected Paint paint; 42 | 43 | protected Paint ripplePaint; 44 | 45 | protected float radius; 46 | 47 | protected float slotRadius; 48 | 49 | private int currentIndex; 50 | 51 | private float currentSlidingX; 52 | 53 | private float currentSlidingY; 54 | 55 | private float selectedSlotX; 56 | 57 | private float selectedSlotY; 58 | 59 | private boolean gotSlot = false; 60 | 61 | private float[] slotPositions; 62 | 63 | private int filledColor = DEFAULT_FILLED_COLOR; 64 | 65 | private int emptyColor = DEFAULT_EMPTY_COLOR; 66 | 67 | private float barHeightPercent = DEFAULT_BAR_HEIGHT_PERCENT; 68 | 69 | private int rangeCount = DEFAULT_RANGE_COUNT; 70 | 71 | private int barHeight; 72 | 73 | private OnSlideListener listener; 74 | 75 | private float rippleRadius = 0.0f; 76 | 77 | private float downX; 78 | 79 | private float downY; 80 | 81 | private Path innerPath = new Path(); 82 | 83 | private Path outerPath = new Path(); 84 | 85 | private float slotRadiusPercent = DEFAULT_SLOT_RADIUS_PERCENT; 86 | 87 | private float sliderRadiusPercent = DEFAULT_SLIDER_RADIUS_PERCENT; 88 | 89 | private int layoutHeight; 90 | 91 | public RangeSliderView(Context context) { 92 | this(context, null); 93 | } 94 | 95 | public RangeSliderView(Context context, AttributeSet attrs) { 96 | this(context, attrs, -1); 97 | } 98 | 99 | public RangeSliderView(Context context, AttributeSet attrs, int defStyleAttr) { 100 | super(context, attrs, defStyleAttr); 101 | if (attrs != null) { 102 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RangeSliderView); 103 | TypedArray sa = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.layout_height}); 104 | try { 105 | layoutHeight = sa.getLayoutDimension( 106 | 0, ViewGroup.LayoutParams.WRAP_CONTENT); 107 | rangeCount = a.getInt( 108 | R.styleable.RangeSliderView_rangeCount, DEFAULT_RANGE_COUNT); 109 | filledColor = a.getColor( 110 | R.styleable.RangeSliderView_filledColor, DEFAULT_FILLED_COLOR); 111 | emptyColor = a.getColor( 112 | R.styleable.RangeSliderView_emptyColor, DEFAULT_EMPTY_COLOR); 113 | barHeightPercent = a.getFloat( 114 | R.styleable.RangeSliderView_barHeightPercent, DEFAULT_BAR_HEIGHT_PERCENT); 115 | barHeightPercent = a.getFloat( 116 | R.styleable.RangeSliderView_barHeightPercent, DEFAULT_BAR_HEIGHT_PERCENT); 117 | slotRadiusPercent = a.getFloat( 118 | R.styleable.RangeSliderView_slotRadiusPercent, DEFAULT_SLOT_RADIUS_PERCENT); 119 | sliderRadiusPercent = a.getFloat( 120 | R.styleable.RangeSliderView_sliderRadiusPercent, DEFAULT_SLIDER_RADIUS_PERCENT); 121 | } finally { 122 | a.recycle(); 123 | sa.recycle(); 124 | } 125 | } 126 | 127 | setBarHeightPercent(barHeightPercent); 128 | setRangeCount(rangeCount); 129 | setSlotRadiusPercent(slotRadiusPercent); 130 | setSliderRadiusPercent(sliderRadiusPercent); 131 | 132 | slotPositions = new float[rangeCount]; 133 | paint = new Paint(Paint.ANTI_ALIAS_FLAG); 134 | paint.setStrokeWidth(DEFAULT_PAINT_STROKE_WIDTH); 135 | paint.setStyle(Paint.Style.FILL_AND_STROKE); 136 | 137 | ripplePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 138 | ripplePaint.setStrokeWidth(2.0f); 139 | ripplePaint.setStyle(Paint.Style.FILL_AND_STROKE); 140 | 141 | getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 142 | @Override 143 | public boolean onPreDraw() { 144 | getViewTreeObserver().removeOnPreDrawListener(this); 145 | 146 | // Update radius after we got new height 147 | updateRadius(getHeight()); 148 | 149 | // Compute drawing position again 150 | preComputeDrawingPosition(); 151 | 152 | // Ready to draw now 153 | return true; 154 | } 155 | }); 156 | currentIndex = 0; 157 | } 158 | 159 | private void updateRadius(int height) { 160 | barHeight = (int) (height * barHeightPercent); 161 | radius = height * sliderRadiusPercent; 162 | slotRadius = height * slotRadiusPercent; 163 | } 164 | 165 | public int getRangeCount() { 166 | return rangeCount; 167 | } 168 | 169 | public void setRangeCount(int rangeCount) { 170 | if (rangeCount < 2) { 171 | throw new IllegalArgumentException("rangeCount must be >= 2"); 172 | } 173 | this.rangeCount = rangeCount; 174 | } 175 | 176 | public float getBarHeightPercent() { 177 | return barHeightPercent; 178 | } 179 | 180 | public void setBarHeightPercent(float percent) { 181 | if (percent <= 0.0 || percent > 1.0) { 182 | throw new IllegalArgumentException("Bar height percent must be in (0, 1]"); 183 | } 184 | this.barHeightPercent = percent; 185 | } 186 | 187 | public float getSlotRadiusPercent() { 188 | return slotRadiusPercent; 189 | } 190 | 191 | public void setSlotRadiusPercent(float percent) { 192 | if (percent <= 0.0 || percent > 1.0) { 193 | throw new IllegalArgumentException("Slot radius percent must be in (0, 1]"); 194 | } 195 | this.slotRadiusPercent = percent; 196 | } 197 | 198 | public float getSliderRadiusPercent() { 199 | return sliderRadiusPercent; 200 | } 201 | 202 | public void setSliderRadiusPercent(float percent) { 203 | if (percent <= 0.0 || percent > 1.0) { 204 | throw new IllegalArgumentException("Slider radius percent must be in (0, 1]"); 205 | } 206 | this.sliderRadiusPercent = percent; 207 | } 208 | 209 | @AnimateMethod 210 | public void setRadius(final float radius) { 211 | rippleRadius = radius; 212 | if (rippleRadius > 0) { 213 | RadialGradient radialGradient = new RadialGradient( 214 | downX, 215 | downY, 216 | rippleRadius * 3, 217 | Color.TRANSPARENT, 218 | Color.BLACK, 219 | Shader.TileMode.MIRROR 220 | ); 221 | ripplePaint.setShader(radialGradient); 222 | } 223 | invalidate(); 224 | } 225 | 226 | public void setOnSlideListener(OnSlideListener listener) { 227 | this.listener = listener; 228 | } 229 | 230 | /** 231 | * Perform all the calculation before drawing, should only run once 232 | */ 233 | private void preComputeDrawingPosition() { 234 | int w = getWidthWithPadding(); 235 | int h = getHeightWithPadding(); 236 | 237 | /** Space between each slot */ 238 | int spacing = w / rangeCount; 239 | 240 | /** Center vertical */ 241 | int y = getPaddingTop() + h / 2; 242 | currentSlidingY = y; 243 | selectedSlotY = y; 244 | /** 245 | * Try to center it, so start by half 246 | *
247 |      *
248 |      *  Example for 4 slots
249 |      *
250 |      *  ____o____|____o____|____o____|____o____
251 |      *  --space--
252 |      *
253 |      * 
254 | */ 255 | int x = getPaddingLeft() + (spacing / 2); 256 | 257 | /** Store the position of each slot index */ 258 | for (int i = 0; i < rangeCount; ++i) { 259 | slotPositions[i] = x; 260 | if (i == currentIndex) { 261 | currentSlidingX = x; 262 | selectedSlotX = x; 263 | } 264 | x += spacing; 265 | } 266 | } 267 | 268 | public void setInitialIndex(int index) { 269 | if (index < 0 || index >= rangeCount) { 270 | throw new IllegalArgumentException("Attempted to set index=" + index + " out of range [0," + rangeCount + "]"); 271 | } 272 | currentIndex = index; 273 | currentSlidingX = selectedSlotX = slotPositions[currentIndex]; 274 | invalidate(); 275 | } 276 | 277 | public int getFilledColor() { 278 | return filledColor; 279 | } 280 | 281 | public void setFilledColor(int filledColor) { 282 | this.filledColor = filledColor; 283 | invalidate(); 284 | } 285 | 286 | public int getEmptyColor() { 287 | return emptyColor; 288 | } 289 | 290 | public void setEmptyColor(int emptyColor) { 291 | this.emptyColor = emptyColor; 292 | invalidate(); 293 | } 294 | 295 | @Override 296 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 297 | setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); 298 | } 299 | 300 | /** 301 | * Measures height according to the passed measure spec 302 | * 303 | * @param measureSpec int measure spec to use 304 | * @return int pixel size 305 | */ 306 | private int measureHeight(int measureSpec) { 307 | int specMode = MeasureSpec.getMode(measureSpec); 308 | int specSize = MeasureSpec.getSize(measureSpec); 309 | int result; 310 | if (specMode == MeasureSpec.EXACTLY) { 311 | result = specSize; 312 | } else { 313 | final int height; 314 | if (layoutHeight == ViewGroup.LayoutParams.WRAP_CONTENT) { 315 | height = dpToPx(getContext(), DEFAULT_HEIGHT_IN_DP); 316 | } else if (layoutHeight == ViewGroup.LayoutParams.MATCH_PARENT) { 317 | height = getMeasuredHeight(); 318 | } else { 319 | height = layoutHeight; 320 | } 321 | result = height + getPaddingTop() + getPaddingBottom() + (2 * DEFAULT_PAINT_STROKE_WIDTH); 322 | if (specMode == MeasureSpec.AT_MOST) { 323 | result = Math.min(result, specSize); 324 | } 325 | } 326 | return result; 327 | } 328 | 329 | /** 330 | * Measures width according to the passed measure spec 331 | * 332 | * @param measureSpec int measure spec to use 333 | * @return int pixel size 334 | */ 335 | private int measureWidth(int measureSpec) { 336 | int specMode = MeasureSpec.getMode(measureSpec); 337 | int specSize = MeasureSpec.getSize(measureSpec); 338 | int result; 339 | if (specMode == MeasureSpec.EXACTLY) { 340 | result = specSize; 341 | } else { 342 | result = specSize + getPaddingLeft() + getPaddingRight() + (2 * DEFAULT_PAINT_STROKE_WIDTH) + (int) (2 * radius); 343 | if (specMode == MeasureSpec.AT_MOST) { 344 | result = Math.min(result, specSize); 345 | } 346 | } 347 | return result; 348 | } 349 | 350 | private void updateCurrentIndex() { 351 | float min = Float.MAX_VALUE; 352 | int j = 0; 353 | /** Find the closest to x */ 354 | for (int i = 0; i < rangeCount; ++i) { 355 | float dx = Math.abs(currentSlidingX - slotPositions[i]); 356 | if (dx < min) { 357 | min = dx; 358 | j = i; 359 | } 360 | } 361 | /** This is current index of slider */ 362 | if (j != currentIndex) { 363 | if (listener != null) { 364 | listener.onSlide(j); 365 | } 366 | } 367 | currentIndex = j; 368 | /** Correct position */ 369 | currentSlidingX = slotPositions[j]; 370 | selectedSlotX = currentSlidingX; 371 | downX = currentSlidingX; 372 | downY = currentSlidingY; 373 | animateRipple(); 374 | invalidate(); 375 | } 376 | 377 | private void animateRipple() { 378 | ObjectAnimator animator = ObjectAnimator.ofFloat(this, "radius", 0, radius); 379 | animator.setInterpolator(new AccelerateInterpolator()); 380 | animator.setDuration(RIPPLE_ANIMATION_DURATION_MS); 381 | animator.start(); 382 | animator.addListener(new Animator.AnimatorListener() { 383 | @Override 384 | public void onAnimationStart(Animator animation) { 385 | 386 | } 387 | 388 | @Override 389 | public void onAnimationEnd(Animator animation) { 390 | rippleRadius = 0; 391 | } 392 | 393 | @Override 394 | public void onAnimationCancel(Animator animation) { 395 | 396 | } 397 | 398 | @Override 399 | public void onAnimationRepeat(Animator animation) { 400 | 401 | } 402 | }); 403 | } 404 | 405 | @Override 406 | public boolean onTouchEvent(MotionEvent event) { 407 | float y = event.getY(); 408 | float x = event.getX(); 409 | final int action = event.getActionMasked(); 410 | switch (action) { 411 | case MotionEvent.ACTION_DOWN: 412 | gotSlot = isInSelectedSlot(x, y); 413 | downX = x; 414 | downY = y; 415 | break; 416 | 417 | case MotionEvent.ACTION_MOVE: 418 | if (gotSlot) { 419 | if (x >= slotPositions[0] && x <= slotPositions[rangeCount - 1]) { 420 | currentSlidingX = x; 421 | currentSlidingY = y; 422 | invalidate(); 423 | } 424 | } 425 | break; 426 | 427 | case MotionEvent.ACTION_UP: 428 | if (gotSlot) { 429 | gotSlot = false; 430 | currentSlidingX = x; 431 | currentSlidingY = y; 432 | updateCurrentIndex(); 433 | } 434 | break; 435 | } 436 | return true; 437 | } 438 | 439 | private boolean isInSelectedSlot(float x, float y) { 440 | return 441 | selectedSlotX - radius <= x && x <= selectedSlotX + radius && 442 | selectedSlotY - radius <= y && y <= selectedSlotY + radius; 443 | } 444 | 445 | private void drawEmptySlots(Canvas canvas) { 446 | paint.setColor(emptyColor); 447 | int h = getHeightWithPadding(); 448 | int y = getPaddingTop() + (h >> 1); 449 | for (int i = 0; i < rangeCount; ++i) { 450 | canvas.drawCircle(slotPositions[i], y, slotRadius, paint); 451 | } 452 | } 453 | 454 | public int getHeightWithPadding() { 455 | return getHeight() - getPaddingBottom() - getPaddingTop(); 456 | } 457 | 458 | public int getWidthWithPadding() { 459 | return getWidth() - getPaddingLeft() - getPaddingRight(); 460 | } 461 | 462 | private void drawFilledSlots(Canvas canvas) { 463 | paint.setColor(filledColor); 464 | int h = getHeightWithPadding(); 465 | int y = getPaddingTop() + (h >> 1); 466 | for (int i = 0; i < rangeCount; ++i) { 467 | if (slotPositions[i] <= currentSlidingX) { 468 | canvas.drawCircle(slotPositions[i], y, slotRadius, paint); 469 | } 470 | } 471 | } 472 | 473 | private void drawBar(Canvas canvas, int from, int to, int color) { 474 | paint.setColor(color); 475 | int h = getHeightWithPadding(); 476 | int half = (barHeight >> 1); 477 | int y = getPaddingTop() + (h >> 1); 478 | canvas.drawRect(from, y - half, to, y + half, paint); 479 | } 480 | 481 | private void drawRippleEffect(Canvas canvas) { 482 | if (rippleRadius != 0) { 483 | canvas.save(); 484 | ripplePaint.setColor(Color.GRAY); 485 | outerPath.reset(); 486 | outerPath.addCircle(downX, downY, rippleRadius, Path.Direction.CW); 487 | canvas.clipPath(outerPath); 488 | innerPath.reset(); 489 | innerPath.addCircle(downX, downY, rippleRadius / 3, Path.Direction.CW); 490 | canvas.clipPath(innerPath, Region.Op.DIFFERENCE); 491 | canvas.drawCircle(downX, downY, rippleRadius, ripplePaint); 492 | canvas.restore(); 493 | } 494 | } 495 | 496 | @Override 497 | public void onDraw(Canvas canvas) { 498 | super.onDraw(canvas); 499 | int w = getWidthWithPadding(); 500 | int h = getHeightWithPadding(); 501 | int spacing = w / rangeCount; 502 | int border = (spacing >> 1); 503 | int x0 = getPaddingLeft() + border; 504 | int y0 = getPaddingTop() + (h >> 1); 505 | drawEmptySlots(canvas); 506 | drawFilledSlots(canvas); 507 | 508 | /** Draw empty bar */ 509 | drawBar(canvas, (int) slotPositions[0], (int) slotPositions[rangeCount - 1], emptyColor); 510 | 511 | /** Draw filled bar */ 512 | drawBar(canvas, x0, (int) currentSlidingX, filledColor); 513 | 514 | /** Draw the selected range circle */ 515 | paint.setColor(filledColor); 516 | canvas.drawCircle(currentSlidingX, y0, radius, paint); 517 | drawRippleEffect(canvas); 518 | } 519 | 520 | @Override 521 | public Parcelable onSaveInstanceState() { 522 | Parcelable superState = super.onSaveInstanceState(); 523 | SavedState ss = new SavedState(superState); 524 | ss.saveIndex = this.currentIndex; 525 | return ss; 526 | } 527 | 528 | @Override 529 | public void onRestoreInstanceState(Parcelable state) { 530 | if (!(state instanceof SavedState)) { 531 | super.onRestoreInstanceState(state); 532 | return; 533 | } 534 | SavedState ss = (SavedState) state; 535 | super.onRestoreInstanceState(ss.getSuperState()); 536 | this.currentIndex = ss.saveIndex; 537 | } 538 | 539 | static class SavedState extends BaseSavedState { 540 | int saveIndex; 541 | 542 | SavedState(Parcelable superState) { 543 | super(superState); 544 | } 545 | 546 | private SavedState(Parcel in) { 547 | super(in); 548 | this.saveIndex = in.readInt(); 549 | } 550 | 551 | @Override 552 | public void writeToParcel(Parcel out, int flags) { 553 | super.writeToParcel(out, flags); 554 | out.writeInt(this.saveIndex); 555 | } 556 | 557 | //required field that makes Parcelables from a Parcel 558 | public static final Parcelable.Creator CREATOR = 559 | new Parcelable.Creator() { 560 | public SavedState createFromParcel(Parcel in) { 561 | return new SavedState(in); 562 | } 563 | 564 | public SavedState[] newArray(int size) { 565 | return new SavedState[size]; 566 | } 567 | }; 568 | } 569 | 570 | /** 571 | * Helper method to convert pixel to dp 572 | * @param context 573 | * @param px 574 | * @return 575 | */ 576 | static int pxToDp(final Context context, final float px) { 577 | return (int)(px / context.getResources().getDisplayMetrics().density); 578 | } 579 | 580 | /** 581 | * Helper method to convert dp to pixel 582 | * @param context 583 | * @param dp 584 | * @return 585 | */ 586 | static int dpToPx(final Context context, final float dp) { 587 | return (int)(dp * context.getResources().getDisplayMetrics().density); 588 | } 589 | 590 | /** 591 | * Interface to keep track sliding position 592 | */ 593 | public interface OnSlideListener { 594 | 595 | /** 596 | * Notify when slider change to new index position 597 | * 598 | * @param index The index value of range count [0, rangeCount - 1] 599 | */ 600 | void onSlide(int index); 601 | } 602 | } 603 | -------------------------------------------------------------------------------- /library/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /library/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | library 3 | 4 | -------------------------------------------------------------------------------- /range-slider-view.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.chan.rsv.sample" 9 | minSdkVersion 14 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 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(dir: 'libs', include: ['*.jar']) 24 | compile project(':library') 25 | compile 'com.android.support:appcompat-v7:23.0.1' 26 | } 27 | -------------------------------------------------------------------------------- /sample/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 /Users/chan/Desktop/android/sdk/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 | -------------------------------------------------------------------------------- /sample/sample.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /sample/src/androidTest/java/com/chan/rsv/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.chan.rsv; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /sample/src/main/java/com/chan/rsv/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.chan.rsv.sample; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.widget.Toast; 6 | import com.github.channguyen.rsv.RangeSliderView; 7 | 8 | public class MainActivity extends AppCompatActivity { 9 | 10 | private RangeSliderView smallSlider; 11 | 12 | private RangeSliderView largeSlider; 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_main); 18 | smallSlider = (RangeSliderView) findViewById( 19 | R.id.rsv_small); 20 | largeSlider = (RangeSliderView) findViewById( 21 | R.id.rsv_large); 22 | final RangeSliderView.OnSlideListener listener = new RangeSliderView.OnSlideListener() { 23 | @Override 24 | public void onSlide(int index) { 25 | Toast.makeText( 26 | getApplicationContext(), 27 | "Hi index: " + index, 28 | Toast.LENGTH_SHORT) 29 | .show(); 30 | } 31 | }; 32 | smallSlider.setOnSlideListener(listener); 33 | largeSlider.setOnSlideListener(listener); 34 | } 35 | } -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 18 | 19 | 20 | 28 | 29 | 41 | 42 | 50 | 51 | 64 | 65 |