├── sample
├── .gitignore
├── src
│ └── main
│ │ ├── assets
│ │ ├── vazir.ttf
│ │ └── vazir_b.ttf
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ └── layout
│ │ │ └── activity_main.xml
│ │ ├── java
│ │ └── ir
│ │ │ └── oveissi
│ │ │ └── threestateswitch
│ │ │ └── sample
│ │ │ ├── FontHelper.java
│ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
├── build.gradle
└── proguard-rules.pro
├── threestateswitch
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable
│ │ │ └── switch_circle.png
│ │ └── values
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ ├── colors.xml
│ │ │ └── attrs.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── ir
│ │ └── oveissi
│ │ └── threestateswitch
│ │ └── ThreeStateSwitch.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── assets
└── demo.gif
├── .idea
├── copyright
│ └── profiles_settings.xml
├── markdown-navigator
│ └── profiles_settings.xml
├── encodings.xml
├── vcs.xml
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
├── compiler.xml
├── misc.xml
└── markdown-navigator.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── README.md
└── gradlew
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/threestateswitch/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':sample', ':threestateswitch'
2 |
--------------------------------------------------------------------------------
/assets/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/assets/demo.gif
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/sample/src/main/assets/vazir.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/assets/vazir.ttf
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ThreeStateSwitch
3 |
4 |
--------------------------------------------------------------------------------
/sample/src/main/assets/vazir_b.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/assets/vazir_b.ttf
--------------------------------------------------------------------------------
/.idea/markdown-navigator/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/threestateswitch/src/main/res/drawable/switch_circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbas-oveissi/ThreeStateSwitch/HEAD/threestateswitch/src/main/res/drawable/switch_circle.png
--------------------------------------------------------------------------------
/threestateswitch/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16sp
3 | 16sp
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/threestateswitch/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ThreeStateSwitch
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 09 02:15:23 IRDT 2017
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-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/threestateswitch/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/threestateswitch/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - #bfbfbf
5 | - #5ab72e
6 |
7 |
8 | - #646464
9 | - #5bb434
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/threestateswitch/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/sample/src/main/java/ir/oveissi/threestateswitch/sample/FontHelper.java:
--------------------------------------------------------------------------------
1 | package ir.oveissi.threestateswitch.sample;
2 |
3 | import android.content.Context;
4 | import android.graphics.Typeface;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | * Created by USER on 11/23/2015.
11 | */
12 | public class FontHelper {
13 | private static final Map TYPEFACES = new HashMap<>();
14 |
15 | public static Typeface get(Context context, String fontFileName){
16 | Typeface typeface = TYPEFACES.get(fontFileName);
17 | if(typeface == null){
18 | typeface = Typeface.createFromAsset(context.getResources().getAssets(), fontFileName);
19 | TYPEFACES.put(fontFileName, typeface);
20 | }
21 | return typeface;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 | defaultConfig {
7 | applicationId "ir.oveissi.threestateswitch.sample"
8 | minSdkVersion 14
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 | compile 'com.android.support:appcompat-v7:25.3.1'
25 | compile project(':threestateswitch')
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 /home/abbas/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 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/threestateswitch/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 /home/abbas/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 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/sample/src/main/java/ir/oveissi/threestateswitch/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package ir.oveissi.threestateswitch.sample;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 |
6 | import ir.oveissi.threestateswitch.ThreeStateSwitch;
7 |
8 | public class MainActivity extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_main);
14 |
15 |
16 | ThreeStateSwitch threeState= (ThreeStateSwitch) findViewById(R.id.threeState);
17 | ThreeStateSwitch threeState1= (ThreeStateSwitch) findViewById(R.id.threeState1);
18 |
19 | threeState.setNormalTextTypeface(FontHelper.get(this,"vazir.ttf"));
20 | threeState.setSelectedTextTypeface(FontHelper.get(this,"vazir_b.ttf"));
21 |
22 | threeState1.setNormalTextTypeface(FontHelper.get(this,"vazir.ttf"));
23 | threeState1.setSelectedTextTypeface(FontHelper.get(this,"vazir_b.ttf"));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/threestateswitch/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'maven'
3 |
4 | group='com.github.abbas-oveissi'
5 |
6 | android {
7 | compileSdkVersion 25
8 | buildToolsVersion "25.0.2"
9 |
10 | defaultConfig {
11 | minSdkVersion 14
12 | targetSdkVersion 25
13 | versionCode 3
14 | versionName "0.9.0"
15 |
16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
17 |
18 | }
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 | compile 'com.android.support:appcompat-v7:25.3.1'
29 | }
30 |
31 |
32 | task sourcesJar(type: Jar) {
33 | from android.sourceSets.main.java.srcDirs
34 | classifier = 'sources'
35 | }
36 |
37 | task javadoc(type: Javadoc) {
38 | failOnError false
39 | source = android.sourceSets.main.java.sourceFiles
40 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
41 | }
42 |
43 | task javadocJar(type: Jar, dependsOn: javadoc) {
44 | classifier = 'javadoc'
45 | from javadoc.destinationDir
46 | }
47 |
48 | artifacts {
49 | archives sourcesJar
50 | archives javadocJar
51 | }
52 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
21 |
22 |
33 |
34 |
35 |
40 |
41 |
42 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
47 |
48 |
49 |
50 | 1.8
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://jitpack.io/#abbas-oveissi/ThreeStateSwitch)
2 |
3 | ## ThreeStateSwitch
4 |
5 | A simple three-state switch view for Android.
6 |
7 | **Please Note:** This library has not been fully tested, so use with a little caution, and submit an issue or better, a pull request if you notice any issues at all.
8 |
9 | **Project Setup and Dependencies**
10 | - MinSDK 14
11 |
12 | **Highlights**
13 | - supports showing text on both sides of view
14 | - supports customization in color or size
15 |
16 |
17 | # Preview
18 |
19 | 
20 |
21 | # Setup
22 | ## 1. Provide the gradle dependency
23 |
24 | Add it in your root build.gradle at the end of repositories:
25 | ```gradle
26 | allprojects {
27 | repositories {
28 | ...
29 | maven { url "https://jitpack.io" }
30 | }
31 | }
32 | ```
33 | Add the dependency:
34 | ```gradle
35 | dependencies {
36 | compile 'com.github.abbas-oveissi:threestateswitch:0.8.2'
37 | }
38 | ```
39 |
40 | ## 2. How to use
41 |
42 | Add the ThreeStateSwitch in your layout file and customize it the way you like it.
43 | ```xml
44 |
56 | ```
57 | You can set a listener for state changes
58 | ```java
59 | threeState.setOnChangeListener(new ThreeStateSwitch.OnStateChangeListener() {
60 | @Override
61 | public void OnStateChangeListener(int currentState) {
62 | //current state= -1 0 1
63 | Toast.makeText(MainActivity.this, String.valueOf(currentState), Toast.LENGTH_SHORT).show();
64 | }
65 | });
66 | ```
67 | You can set typeface for texts.
68 | ```java
69 | threeState.setNormalTextTypeface( );
70 | threeState.setSelectedTextTypeface( );
71 | ```
72 | Get the current state.
73 | ```java
74 | //state= -1 0 1
75 | threeState.getState();
76 | ```
77 | ## attributes
78 |
79 | | Name | Type | Default | Description |
80 | |:----:|:----:|:-------:|:-----------:|
81 | |background_selected_color|Color|#5bb434| |
82 | |background_normal_color|Color|#bfbfbf| |
83 | |text_normal_color|Color|#646464| |
84 | |text_selected_color|Color|#5bb434| |
85 | |text_left|String|| |
86 | |text_right|String|| |
87 | |text_normal_size|Dp or Sp|16sp| |
88 | |text_selected_size|Dp or Sp|16sp| |
89 | |two_state_after_init|Boolean|false|Converts switch to a two state switch after first interaction |
90 |
91 | # Bugs and features
92 |
93 | For bugs, feature requests, and discussion please use GitHub Issues.
94 |
95 | # Developed By
96 |
97 | * Abbas Oveissi - [@abbas_oveissi](https://twitter.com/abbas_oveissi)
98 |
99 |
100 | # License
101 |
102 | Copyright 2017 Abbas Oveissi
103 |
104 | Licensed under the Apache License, Version 2.0 (the "License");
105 | you may not use this file except in compliance with the License.
106 | You may obtain a copy of the License at
107 |
108 | http://www.apache.org/licenses/LICENSE-2.0
109 |
110 | Unless required by applicable law or agreed to in writing, software
111 | distributed under the License is distributed on an "AS IS" BASIS,
112 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
113 | See the License for the specific language governing permissions and
114 | limitations under the License.
--------------------------------------------------------------------------------
/.idea/markdown-navigator.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 |
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/threestateswitch/src/main/java/ir/oveissi/threestateswitch/ThreeStateSwitch.java:
--------------------------------------------------------------------------------
1 | package ir.oveissi.threestateswitch;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorSet;
5 | import android.animation.ArgbEvaluator;
6 | import android.animation.ObjectAnimator;
7 | import android.annotation.TargetApi;
8 | import android.content.Context;
9 | import android.content.res.Resources;
10 | import android.content.res.TypedArray;
11 | import android.graphics.Bitmap;
12 | import android.graphics.BitmapFactory;
13 | import android.graphics.Canvas;
14 | import android.graphics.Color;
15 | import android.graphics.Paint;
16 | import android.graphics.Rect;
17 | import android.graphics.RectF;
18 | import android.graphics.Typeface;
19 | import android.os.Build;
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 | import android.util.AttributeSet;
23 | import android.view.MotionEvent;
24 | import android.view.View;
25 |
26 | import java.util.ArrayList;
27 |
28 | /**
29 | * Created by abbas on 8/6/16.
30 | */
31 |
32 | public class ThreeStateSwitch extends View {
33 | private Context context;
34 | private AttributeSet attrs;
35 |
36 | private int state=0;
37 | private boolean isDrag;
38 | private float xDrag;
39 | private float yDrag;
40 | private float startX;
41 | private boolean isAnimate;
42 | private boolean isPressed;
43 | private Typeface selectedTextTypeface;
44 | private Typeface normalTextTypeface;
45 |
46 |
47 |
48 |
49 |
50 |
51 | int text_normal_color ;
52 | int text_selected_color;
53 | int text_normal_size ;
54 | int text_selected_size;
55 |
56 | boolean twoStateAfterInit = false;
57 |
58 | // - #bfbfbf
59 | // - #5ab72e
60 | int colorStateUnSelected = Color.parseColor("#bfbfbf");
61 | int colorStateSelected = Color.parseColor("#5ab72e");
62 |
63 | public int backgroundColor;
64 |
65 |
66 | Paint ovalPaint,textSelectedPaint,textNormalPaint;
67 | Bitmap thumbIcon;
68 | RectF ovalRectF;
69 | Rect orginalBitmapRect,drawnBitmapRect;
70 | Rect textBounds;
71 |
72 | private float viewWidth;
73 | private float viewHeight;
74 |
75 |
76 | private int paddingRight;
77 | private int paddingLeft;
78 | private int paddingBottom;
79 | private int paddingTop;
80 |
81 |
82 | public int xCircle=0;
83 | public int yCircle=0;
84 | public int diameterSize =0;
85 |
86 |
87 | String lessText="";
88 | String moreText="";
89 |
90 |
91 | public ThreeStateSwitch(Context context) {
92 | super(context);
93 | init(context,null);
94 | }
95 |
96 | public ThreeStateSwitch(Context context, AttributeSet attrs) {
97 | super(context, attrs);
98 | init(context,attrs);
99 | }
100 |
101 | public ThreeStateSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
102 | super(context, attrs, defStyleAttr);
103 | init(context,attrs);
104 | }
105 |
106 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
107 | public ThreeStateSwitch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
108 | super(context, attrs, defStyleAttr, defStyleRes);
109 | init(context,attrs);
110 | }
111 |
112 |
113 | public void init(Context context, AttributeSet attrs)
114 | {
115 | this.context = context;
116 | this.attrs = attrs;
117 |
118 | // int[] attrsArray = new int[] {
119 | // R.attr.background_selected_color, // 0
120 | // R.attr.background_normal_color, // 1
121 | // R.attr.text_normal_color, // 2
122 | // R.attr.text_selected_color, // 3
123 | // R.attr.text_normal_size, // 4
124 | // R.attr.text_selected_size, // 5
125 | // R.styleable.ThreeStateSwitch_text_left, // 6
126 | // R.styleable.ThreeStateSwitch_text_right // 7
127 | // };
128 | TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ThreeStateSwitch);
129 |
130 | colorStateSelected = ta.getColor(R.styleable.ThreeStateSwitch_background_selected_color ,getResources().getColor(R.color.background_selected_color));
131 | colorStateUnSelected = ta.getColor(R.styleable.ThreeStateSwitch_background_normal_color ,getResources().getColor(R.color.background_normal_color));
132 |
133 | backgroundColor=colorStateUnSelected;
134 |
135 |
136 | text_normal_color = ta.getColor(R.styleable.ThreeStateSwitch_text_normal_color ,getResources().getColor(R.color.text_normal_color));
137 | text_selected_color = ta.getColor(R.styleable.ThreeStateSwitch_text_selected_color ,getResources().getColor(R.color.text_selected_color));
138 |
139 | text_normal_size = ta.getDimensionPixelSize(R.styleable.ThreeStateSwitch_text_normal_size ,(int)getResources().getDimension(R.dimen.text_normal_size));
140 | text_selected_size = ta.getDimensionPixelSize(R.styleable.ThreeStateSwitch_text_selected_size ,(int)getResources().getDimension(R.dimen.text_selected_size));
141 |
142 | twoStateAfterInit = ta.getBoolean(R.styleable.ThreeStateSwitch_two_state_after_init , false);
143 |
144 |
145 | lessText = ta.getString(R.styleable.ThreeStateSwitch_text_left);
146 | if(lessText==null)
147 | {
148 | lessText=getResources().getString(R.string.text_left);
149 | }
150 | moreText = ta.getString(R.styleable.ThreeStateSwitch_text_right);
151 | if(moreText==null)
152 | {
153 | moreText=getResources().getString(R.string.text_right);
154 | }
155 |
156 |
157 | ta.recycle();
158 |
159 |
160 | ovalPaint =new Paint();
161 | ovalPaint.setColor(backgroundColor);
162 | ovalPaint.setAntiAlias(true);
163 |
164 | thumbIcon = BitmapFactory.decodeResource(context.getResources(),
165 | R.drawable.switch_circle);
166 |
167 | orginalBitmapRect=new Rect();
168 | drawnBitmapRect=new Rect();
169 | ovalRectF=new RectF();
170 | textBounds= new Rect();
171 |
172 | textSelectedPaint = new Paint();
173 | textSelectedPaint.setColor(text_selected_color);
174 | textSelectedPaint.setTextSize( text_selected_size);
175 | textSelectedPaint.setAntiAlias(true);
176 |
177 |
178 | textNormalPaint = new Paint();
179 | textNormalPaint.setColor(text_normal_color);
180 | textNormalPaint.setTextSize( text_normal_size);
181 | textNormalPaint.setAntiAlias(true);
182 | }
183 |
184 |
185 | public interface OnStateChangeListener
186 | {
187 | void OnStateChangeListener(int currentState);
188 | }
189 | public OnStateChangeListener onStateChangeListener;
190 | public void setOnChangeListener(OnStateChangeListener onStateChangeListener) {
191 | this.onStateChangeListener = onStateChangeListener;
192 | }
193 |
194 |
195 | public int getBackColor() {
196 | return this.backgroundColor;
197 | }
198 |
199 | public int getXCircle() {
200 | return xCircle;
201 | }
202 |
203 | public void setBackColor(int backgroundColor) {
204 | this.backgroundColor = backgroundColor;
205 | invalidate();
206 | }
207 |
208 | public void setXCircle(int xCircle) {
209 | this.xCircle = xCircle;
210 | invalidate();
211 | }
212 |
213 |
214 | public int getState()
215 | {
216 | return this.state;
217 | }
218 |
219 | @Override
220 | protected void onMeasure(int widthSpec, int heightSpec) {
221 | int widthSize = MeasureSpec.getSize(widthSpec);
222 | int heightSize = MeasureSpec.getSize(heightSpec);
223 |
224 | paddingRight=getPaddingRight();
225 | paddingLeft=getPaddingLeft();
226 | paddingBottom=getPaddingBottom();
227 | paddingTop=getPaddingTop();
228 |
229 |
230 | textLeftNormalWidth =textNormalPaint.measureText(lessText);
231 | textRightNormalWidth =textNormalPaint.measureText(moreText);
232 |
233 | textLeftSelectedWidth =textSelectedPaint.measureText(lessText);
234 | textRightSelectedWidth =textSelectedPaint.measureText(moreText);
235 |
236 | maxNeededTextWidth= Math.max(textLeftNormalWidth, textRightNormalWidth);
237 | maxNeededTextWidth= Math.max(maxNeededTextWidth, textLeftSelectedWidth);
238 | maxNeededTextWidth= Math.max(maxNeededTextWidth, textRightSelectedWidth);
239 | maxNeededTextWidth+=dpToPx(5);
240 |
241 |
242 | float minWidth=(2*maxNeededTextWidth)+dpToPx(130)+paddingLeft+paddingRight;
243 | float minHeight=dpToPx(35)+paddingBottom+paddingTop;
244 |
245 |
246 | int pWidth=resolveSize((int) minWidth,widthSpec);
247 | int pHeight=resolveSize((int) minHeight,heightSpec);
248 |
249 |
250 | float LeftRect=maxNeededTextWidth+paddingLeft;
251 | float topRect=paddingTop;
252 | float rightRect=pWidth-maxNeededTextWidth-paddingRight;
253 | float bottomRect=pHeight-paddingBottom;
254 |
255 | ovalRectF.set(LeftRect,topRect,rightRect,bottomRect);
256 |
257 |
258 | diameterSize = Math.min(pWidth-paddingRight-paddingLeft-(int)(2*maxNeededTextWidth)
259 | ,pHeight-paddingTop-paddingBottom);
260 |
261 | switch (state)
262 | {
263 | case -1:
264 | if (!twoStateAfterInit)
265 | xCircle=(int)(ovalRectF.left+(diameterSize /2.0));
266 | else
267 | xCircle=(int)(ovalRectF.centerX());
268 | break;
269 | case 0:
270 | xCircle=(int)(ovalRectF.centerX());
271 | break;
272 | case 1:
273 | xCircle=(int)(ovalRectF.right- (diameterSize /2.0));
274 | break;
275 | }
276 | yCircle= (int) ovalRectF.centerY();
277 |
278 |
279 |
280 | // changeViewSize(widthSize,heightSize);
281 | viewWidth = pWidth;
282 | viewHeight = pHeight;
283 | setMeasuredDimension(pWidth,pHeight);
284 | }
285 |
286 |
287 | float textLeftSelectedWidth,textRightSelectedWidth,textLeftNormalWidth, textRightNormalWidth,maxNeededTextWidth;
288 |
289 |
290 |
291 | int delta=0;
292 |
293 | @Override
294 | public boolean onTouchEvent(MotionEvent event) {
295 | int action = event.getAction() & MotionEvent.ACTION_MASK;
296 | switch(action) {
297 | case MotionEvent.ACTION_DOWN : {
298 | this.getParent().requestDisallowInterceptTouchEvent(true);
299 | startX=event.getX();
300 | if(state==whichStateClick(event.getX(),event.getY()))
301 | {
302 | delta=-1*((int)event.getX()-xCircle);
303 | isPressed=true;
304 | }
305 | }
306 | case MotionEvent.ACTION_MOVE:
307 | if(isDrag==false&& Math.abs(startX-event.getX())>15) {
308 | isDrag = true;
309 | }
310 | if(isDrag)
311 | {
312 | int endBoundry=(int) Math.max((diameterSize /2)-delta,event.getX());
313 | int tempX=(int) Math.min(endBoundry,viewWidth- (diameterSize /2));
314 | xCircle=tempX+delta;
315 | xCircle=setBoundForXCircle(xCircle);
316 | }
317 | break;
318 | case MotionEvent.ACTION_UP:
319 | int tempState=whichStateClick(event.getX(),event.getY());
320 | isDrag=false;
321 | isPressed=false;
322 | changeState(tempState);
323 | break;
324 | }
325 | xDrag=event.getX();
326 | yDrag=event.getY();
327 | invalidate();
328 | return true;
329 | }
330 |
331 | public void setNormalTextTypeface(Typeface typeface)
332 | {
333 | this.normalTextTypeface=typeface;
334 | textNormalPaint.setTypeface(typeface);
335 | }
336 |
337 | public void setSelectedTextTypeface(Typeface typeface)
338 | {
339 | this.selectedTextTypeface=typeface;
340 | textSelectedPaint.setTypeface(typeface);
341 | }
342 |
343 |
344 | private int whichStateClick(float x ,float y)
345 | {
346 | if (twoStateAfterInit) {
347 | int half = (int) ((viewWidth - (2 * maxNeededTextWidth) - paddingLeft - paddingRight) / 2.0);
348 | if (x < half + maxNeededTextWidth + paddingLeft)
349 | return -1;
350 | else
351 | return 1;
352 | }
353 | int yekSevom=(int)((viewWidth-(2*maxNeededTextWidth)-paddingLeft-paddingRight)/3.0);
354 | if(x(2*yekSevom)+maxNeededTextWidth+paddingLeft)
357 | return 1;
358 | return 0;
359 | }
360 |
361 |
362 | private int setBoundForXCircle(float xCircle)
363 | {
364 | //Log.d("before",String.valueOf(xCircle));
365 | if(xCircle(float)(ovalRectF.right-(diameterSize /2.0)))
368 | xCircle=(float)(ovalRectF.right-(diameterSize /2.0));
369 |
370 | //Log.d("after",String.valueOf(xCircle));
371 | return (int)xCircle;
372 | }
373 |
374 | @Override
375 | protected void onDraw(Canvas canvas) {
376 |
377 | //ovalRectF.set(0,0,viewWidth,viewHeight);
378 | ovalPaint.setColor(backgroundColor);
379 | canvas.drawRoundRect(ovalRectF, diameterSize /2, diameterSize /2, ovalPaint);
380 |
381 |
382 | if(!isAnimate&&!isDrag)
383 | {
384 | if(state==-1)
385 | {
386 | xCircle=(int)(diameterSize /2.0)+(int)ovalRectF.left;
387 | }
388 | else if(state==0)
389 | {
390 | xCircle=(int)(ovalRectF.centerX());
391 | }
392 | else if(state==1)
393 | {
394 | xCircle=(int)(ovalRectF.right- (diameterSize /2.0));
395 | }
396 | yCircle=(int)(ovalRectF.centerY());
397 | }
398 |
399 |
400 | if(isPressed)
401 | diameterSize +=dpToPx(4);
402 |
403 |
404 | yCircle=(int)(ovalRectF.centerY());
405 |
406 |
407 |
408 | xCircle=setBoundForXCircle(xCircle);
409 | orginalBitmapRect.set(0,0,thumbIcon.getWidth(),thumbIcon.getHeight());
410 | drawnBitmapRect.set(xCircle-(int)(diameterSize /2.0),yCircle-(int)(diameterSize /2.0)
411 | ,xCircle+ (int)(diameterSize /2.0), yCircle+(int)(diameterSize /2.0));
412 |
413 | canvas.drawBitmap(thumbIcon,orginalBitmapRect,drawnBitmapRect,null);
414 | if (isPressed)
415 | diameterSize -=dpToPx(4);
416 |
417 | if(state==-1)
418 | drawCenter(canvas,(int)(maxNeededTextWidth/2.0)+paddingLeft,(int)(ovalRectF.centerY()),textSelectedPaint,lessText);
419 | else
420 | drawCenter(canvas,(int)(maxNeededTextWidth/2.0)+paddingLeft,(int)(ovalRectF.centerY()),textNormalPaint,lessText);
421 |
422 | if(state==1)
423 | drawCenter(canvas,(int)(viewWidth-(maxNeededTextWidth/2.0)-paddingRight),(int)(ovalRectF.centerY()),textSelectedPaint,moreText);
424 | else
425 | drawCenter(canvas,(int)(viewWidth-(maxNeededTextWidth/2.0)-paddingRight),(int)(ovalRectF.centerY()),textNormalPaint,moreText);
426 |
427 | }
428 |
429 |
430 | private Rect r = new Rect();
431 | private void drawCenter(Canvas canvas, int drawX, int drawY, Paint paint, String text) {
432 | paint.setTextAlign(Paint.Align.LEFT);
433 | paint.getTextBounds(text, 0, text.length(), r);
434 | float x = drawX - r.width() / 2f - r.left;
435 | float y = drawY + r.height() / 2f - r.bottom;
436 | canvas.drawText(text, x, y, paint);
437 | }
438 |
439 |
440 | public void changeState(int mState)
441 | {
442 | this.changeState(mState,true);
443 | }
444 | public void changeState(int mState,boolean animate)
445 | {
446 | if(animate==false)
447 | {
448 | switch (mState) {
449 | case -1:
450 | if (!twoStateAfterInit)
451 | setBackColor(colorStateSelected);
452 | else
453 | setBackColor(colorStateUnSelected);
454 |
455 | break;
456 | case 0:
457 | setBackColor(colorStateUnSelected);
458 | break;
459 | case 1:
460 | setBackColor(colorStateSelected);
461 | break;
462 | }
463 | this.state=mState;
464 | return;
465 | }
466 | if(onStateChangeListener!=null)
467 | onStateChangeListener.OnStateChangeListener(mState);
468 | AnimatorSet animSet = new AnimatorSet();
469 | ArrayList viewAnimList = new ArrayList();
470 | ObjectAnimator anim,anim1;
471 | switch (mState) {
472 | case -1:
473 | if (twoStateAfterInit) {
474 | anim = ObjectAnimator.ofInt(this, "BackColor", colorStateUnSelected)
475 | .setDuration(400);
476 | } else {
477 | anim = ObjectAnimator.ofInt(this, "BackColor", colorStateSelected)
478 | .setDuration(400);
479 | }
480 | anim.setEvaluator(new ArgbEvaluator());
481 | viewAnimList.add(anim);
482 | anim1 = ObjectAnimator.ofInt(this, "xCircle",setBoundForXCircle((float)(diameterSize /2.0)))
483 | .setDuration(400);
484 | viewAnimList.add(anim1);
485 | break;
486 | case 0:
487 | anim = ObjectAnimator.ofInt(this, "BackColor", colorStateUnSelected)
488 | .setDuration(400);
489 | anim.setEvaluator(new ArgbEvaluator());
490 | viewAnimList.add(anim);
491 |
492 | anim1 = ObjectAnimator.ofInt(this, "xCircle",setBoundForXCircle((float)(ovalRectF.centerX())))
493 | .setDuration(400);
494 | viewAnimList.add(anim1);
495 | break;
496 | case 1:
497 | anim = ObjectAnimator.ofInt(this, "BackColor", colorStateSelected)
498 | .setDuration(400);
499 | anim.setEvaluator(new ArgbEvaluator());
500 | viewAnimList.add(anim);
501 |
502 | anim1 = ObjectAnimator.ofInt(this, "xCircle", setBoundForXCircle((float)(viewWidth- (diameterSize /2.0))))
503 | .setDuration(400);
504 | viewAnimList.add(anim1);
505 | break;
506 | }
507 | animSet.playTogether(viewAnimList);
508 | animSet.addListener(new Animator.AnimatorListener() {
509 | @Override
510 | public void onAnimationStart(Animator animation) {
511 | isAnimate=true;
512 |
513 | }
514 |
515 | @Override
516 | public void onAnimationEnd(Animator animation) {
517 | isAnimate=false;
518 | }
519 |
520 | @Override
521 | public void onAnimationCancel(Animator animation) {
522 | isAnimate=false;
523 |
524 | }
525 |
526 | @Override
527 | public void onAnimationRepeat(Animator animation) {
528 | isAnimate=false;
529 |
530 | }
531 | });
532 |
533 | animSet.start();
534 | this.state=mState;
535 | }
536 |
537 | public static int dpToPx(int dp)
538 | {
539 | return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
540 | }
541 |
542 | public static int pxToDp(int px)
543 | {
544 | return (int) (px / Resources.getSystem().getDisplayMetrics().density);
545 | }
546 |
547 |
548 |
549 | @Override
550 | protected Parcelable onSaveInstanceState() {
551 | Parcelable superState = super.onSaveInstanceState();
552 | return new SavedState(superState, this.state);
553 | }
554 |
555 | @Override
556 | protected void onRestoreInstanceState(Parcelable state) {
557 | SavedState savedState = (SavedState) state;
558 | super.onRestoreInstanceState(savedState.getSuperState());
559 | changeState(savedState.state,false);
560 | }
561 |
562 |
563 | /**
564 | * Convenience class to save / restore the lock combination picker state. Looks clumsy
565 | * but once created is easy to maintain and use.
566 | */
567 | protected static class SavedState extends BaseSavedState {
568 |
569 | public static final Parcelable.Creator CREATOR = new Creator() {
570 |
571 | public SavedState createFromParcel(Parcel in) {
572 | return new SavedState(in);
573 | }
574 |
575 | public SavedState[] newArray(int size) {
576 | return new SavedState[size];
577 | }
578 |
579 | };
580 | public final Integer state;
581 |
582 | private SavedState(Parcelable superState, Integer state) {
583 | super(superState);
584 | this.state = state;
585 | }
586 |
587 | private SavedState(Parcel in) {
588 | super(in);
589 | state = in.readInt();
590 | }
591 |
592 |
593 |
594 | @Override
595 | public void writeToParcel(Parcel destination, int flags) {
596 | super.writeToParcel(destination, flags);
597 | destination.writeInt(state);
598 | }
599 |
600 | }
601 | }
602 |
--------------------------------------------------------------------------------