├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── common_back_white.png
│ │ │ ├── common_loading_tiny1.png
│ │ │ ├── common_loading_tiny2.png
│ │ │ ├── common_loading_tiny3.png
│ │ │ ├── common_loading_tiny4.png
│ │ │ ├── common_loading_tiny5.png
│ │ │ ├── common_loading_tiny6.png
│ │ │ ├── common_loading_tiny7.png
│ │ │ ├── common_loading_tiny8.png
│ │ │ ├── common_loading_tiny9.png
│ │ │ ├── common_right_arrow.png
│ │ │ ├── common_loading_tiny10.png
│ │ │ ├── common_loading_tiny11.png
│ │ │ └── common_loading_tiny12.png
│ │ ├── layout
│ │ │ ├── recycler_list_content.xml
│ │ │ ├── activity_list.xml
│ │ │ ├── activity_recycler.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_normal.xml
│ │ │ ├── activity_size_intro.xml
│ │ │ └── activity_api_intro.xml
│ │ └── drawable
│ │ │ └── common_anim_list_loading_tiny.xml
│ │ ├── java
│ │ └── com
│ │ │ └── github
│ │ │ └── iielse
│ │ │ └── switchbutton
│ │ │ └── demo
│ │ │ ├── ItemObject.java
│ │ │ ├── SizeIntroActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── APIIntroActivity.java
│ │ │ ├── RecyclerActivity.java
│ │ │ ├── ListActivity.java
│ │ │ ├── SpfsUtils.java
│ │ │ └── NormalActivity.java
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── switchbutton
├── .gitignore
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ └── values
│ │ │ └── attrs.xml
│ │ └── java
│ │ └── com
│ │ └── github
│ │ └── iielse
│ │ └── switchbutton
│ │ └── SwitchView.java
├── build.gradle
└── proguard-rules.pro
├── settings.gradle
├── previews
├── a.gif
├── b.gif
├── c.gif
├── 12345.png
├── 23456.png
├── 34567.png
├── 45678.png
└── app-debug.apk
├── .idea
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── vcs.xml
├── modules.xml
├── runConfigurations.xml
├── compiler.xml
├── gradle.xml
└── misc.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/switchbutton/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':switchbutton'
2 |
--------------------------------------------------------------------------------
/previews/a.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/previews/a.gif
--------------------------------------------------------------------------------
/previews/b.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/previews/b.gif
--------------------------------------------------------------------------------
/previews/c.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/previews/c.gif
--------------------------------------------------------------------------------
/previews/12345.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/previews/12345.png
--------------------------------------------------------------------------------
/previews/23456.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/previews/23456.png
--------------------------------------------------------------------------------
/previews/34567.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/previews/34567.png
--------------------------------------------------------------------------------
/previews/45678.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/previews/45678.png
--------------------------------------------------------------------------------
/previews/app-debug.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/previews/app-debug.apk
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | switchbutton
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_back_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_back_white.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny1.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny2.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny3.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny4.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny5.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny6.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny7.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny8.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny9.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_right_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_right_arrow.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.svn
2 | *.iml
3 | .idea/
4 | .gradle/
5 | build/
6 | /local.properties
7 | .DS_Store
8 | captures/
9 | .externalNativeBuild
10 | import-summary.txt
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny10.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny11.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/common_loading_tiny12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iielse/switchbutton/HEAD/app/src/main/res/mipmap-xhdpi/common_loading_tiny12.png
--------------------------------------------------------------------------------
/switchbutton/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/iielse/switchbutton/demo/ItemObject.java:
--------------------------------------------------------------------------------
1 | package com.github.iielse.switchbutton.demo;
2 |
3 | /**
4 | * Created by LY on 2016/9/13.
5 | */
6 | public class ItemObject {
7 | String title;
8 | boolean isOpened;
9 | }
10 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jan 29 17:03:05 CST 2020
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-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/switchbutton/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "29.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 29
10 | versionCode 4
11 | versionName "1.0.4"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | }
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/switchbutton/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\a_work\DevelopEnvironment\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 |
--------------------------------------------------------------------------------
/switchbutton/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 D:\a_work\DevelopEnvironment\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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "29.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.github.iielse.switchbutton.demo"
9 | minSdkVersion 14
10 | targetSdkVersion 29
11 | versionCode 1
12 | versionName "1.0.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 | implementation 'androidx.appcompat:appcompat:1.1.0'
24 | implementation 'androidx.recyclerview:recyclerview:1.1.0'
25 | // implementation project(':switchbutton')
26 | implementation 'com.github.iielse:switchbutton:1.0.4'
27 | }
28 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_list_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
20 |
21 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
19 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_recycler.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
19 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/iielse/switchbutton/demo/SizeIntroActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.iielse.switchbutton.demo;
2 |
3 | import android.os.Bundle;
4 | import androidx.appcompat.app.AppCompatActivity;
5 | import androidx.appcompat.widget.Toolbar;
6 | import android.view.View;
7 |
8 | import com.github.iielse.switchbutton.SwitchView;
9 |
10 |
11 |
12 |
13 | public class SizeIntroActivity extends AppCompatActivity {
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_size_intro);
19 |
20 | ((Toolbar) findViewById(R.id.toolbar)).setNavigationOnClickListener(new View.OnClickListener() {
21 | @Override
22 | public void onClick(View v) {
23 | SizeIntroActivity.this.finish();
24 | }
25 | });
26 |
27 | final SwitchView vSwitch1 = (SwitchView) findViewById(R.id.v_switch_1);
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/gradle.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 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/common_anim_list_loading_tiny.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
11 |
14 |
17 |
20 |
23 |
26 |
29 |
32 |
35 |
38 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
22 |
23 |
28 |
29 |
34 |
35 |
36 |
42 |
43 |
49 |
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SwitchView
2 |
3 |  
4 | 
5 | 
6 |
7 | ## Download
8 | [DemoApp.apk](https://github.com/iielse/SwitchButton/blob/master/previews/app-debug.apk)
9 |
10 | ## Usage
11 | 1. add library
12 |
13 | `implementation 'com.github.iielse:switchbutton:1.0.4'`
14 |
15 | 2. xml
16 | ```
17 |
20 | ```
21 | 3. activity
22 |
23 | 
24 |
25 | ```
26 | switchView.setOnClickListener(new View.OnClickListener() {
27 | @Override
28 | public void onClick(View v) {
29 | boolean isOpened = switchView.isOpened();
30 | }
31 | });
32 | ```
33 | or
34 |
35 | 
36 | 
37 |
38 | ```
39 | switchView.setOnStateChangedListener(new SwitchView.OnStateChangedListener() {
40 | @Override
41 | public void toggleToOn(SwitchView view) {
42 | view.toggleSwitch(true); // or false
43 | }
44 |
45 | @Override
46 | public void toggleToOff(SwitchView view) {
47 | view.toggleSwitch(false); // or true
48 | }
49 | });
50 | ```
51 |
52 | ## Attributes
53 | | attr | description |
54 | |:---|:---|
55 | | hasShadow | 是否显示按钮阴影 |
56 | | primaryColor | 开启状态背景色 |
57 | | primaryColorDark| 开启状态按钮描边色 |
58 | | offColor | 关闭状态描边色 |
59 | | offColorDark | 关闭状态按钮描边色 |
60 | | shadowColor | 按钮阴影色 |
61 | | ratioAspect | 按钮宽高形状比率(0,1] 不推荐大幅度调整 |
62 | | isOpened | 初始化默认状态 |
63 |
64 |
65 |
66 | ## Appreciation
67 | * [aigeStudio](http://blog.csdn.net/aigestudio)
68 |
69 | ##Others
70 | hope you like my work. `Star` support me a lot. thanks
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/iielse/switchbutton/demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.iielse.switchbutton.demo;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import androidx.appcompat.app.AppCompatActivity;
6 | import android.view.View;
7 |
8 |
9 |
10 | public class MainActivity extends AppCompatActivity {
11 |
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_main);
17 |
18 | findViewById(R.id.b_normal).setOnClickListener(new View.OnClickListener() {
19 | @Override
20 | public void onClick(View v) {
21 | Intent intent = new Intent(MainActivity.this, NormalActivity.class);
22 | startActivity(intent);
23 | }
24 | });
25 |
26 | findViewById(R.id.b_api_intro).setOnClickListener(new View.OnClickListener() {
27 | @Override
28 | public void onClick(View v) {
29 | Intent intent = new Intent(MainActivity.this, APIIntroActivity.class);
30 | startActivity(intent);
31 | }
32 | });
33 |
34 | findViewById(R.id.b_size_intro).setOnClickListener(new View.OnClickListener() {
35 | @Override
36 | public void onClick(View v) {
37 | Intent intent = new Intent(MainActivity.this, SizeIntroActivity.class);
38 | startActivity(intent);
39 | }
40 | });
41 |
42 | findViewById(R.id.b_list).setOnClickListener(new View.OnClickListener() {
43 | @Override
44 | public void onClick(View v) {
45 | Intent intent = new Intent(MainActivity.this, ListActivity.class);
46 | startActivity(intent);
47 | }
48 | });
49 |
50 | findViewById(R.id.b_recycler).setOnClickListener(new View.OnClickListener() {
51 | @Override
52 | public void onClick(View v) {
53 | Intent intent = new Intent(MainActivity.this, RecyclerActivity.class);
54 | startActivity(intent);
55 | }
56 | });
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/iielse/switchbutton/demo/APIIntroActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.iielse.switchbutton.demo;
2 |
3 | import android.os.Bundle;
4 | import androidx.appcompat.app.AppCompatActivity;
5 | import androidx.appcompat.widget.Toolbar;
6 | import android.view.View;
7 |
8 | import com.github.iielse.switchbutton.SwitchView;
9 |
10 |
11 |
12 |
13 | public class APIIntroActivity extends AppCompatActivity {
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_api_intro);
19 |
20 | ((Toolbar) findViewById(R.id.toolbar)).setNavigationOnClickListener(new View.OnClickListener() {
21 | @Override
22 | public void onClick(View v) {
23 | APIIntroActivity.this.finish();
24 | }
25 | });
26 |
27 | final SwitchView vSwitch1 = (SwitchView) findViewById(R.id.v_switch_1);
28 | findViewById(R.id.b_1_1).setOnClickListener(new View.OnClickListener() {
29 | @Override
30 | public void onClick(View v) {
31 | vSwitch1.setOpened(true);
32 | }
33 | });
34 | findViewById(R.id.b_1_2).setOnClickListener(new View.OnClickListener() {
35 | @Override
36 | public void onClick(View v) {
37 | vSwitch1.setOpened(false);
38 | }
39 | });
40 | findViewById(R.id.b_1_3).setOnClickListener(new View.OnClickListener() {
41 | @Override
42 | public void onClick(View v) {
43 | vSwitch1.toggleSwitch(true);
44 | }
45 | });
46 |
47 | findViewById(R.id.b_1_4).setOnClickListener(new View.OnClickListener() {
48 | @Override
49 | public void onClick(View v) {
50 | vSwitch1.toggleSwitch(false);
51 | }
52 | });
53 |
54 | final SwitchView vSwitch2 = (SwitchView) findViewById(R.id.v_switch_2);
55 | findViewById(R.id.b_2_1).setOnClickListener(new View.OnClickListener() {
56 | @Override
57 | public void onClick(View v) {
58 | vSwitch2.setShadow(true);
59 | }
60 | });
61 | findViewById(R.id.b_2_2).setOnClickListener(new View.OnClickListener() {
62 | @Override
63 | public void onClick(View v) {
64 | vSwitch2.setShadow(false);
65 | }
66 | });
67 |
68 | final SwitchView vSwitch3 = (SwitchView) findViewById(R.id.v_switch_3);
69 | findViewById(R.id.b_3_1).setOnClickListener(new View.OnClickListener() {
70 | @Override
71 | public void onClick(View v) {
72 | vSwitch3.setColor(0xFF4FC3F7, 0x4FC3F7);
73 | }
74 | });
75 | findViewById(R.id.b_3_2).setOnClickListener(new View.OnClickListener() {
76 | @Override
77 | public void onClick(View v) {
78 | vSwitch3.setColor(0xFF546E7A, 0xFF455A64);
79 | }
80 | });
81 | findViewById(R.id.b_3_3).setOnClickListener(new View.OnClickListener() {
82 | @Override
83 | public void onClick(View v) {
84 | vSwitch3.setColor(0xFFFFC400, 0xFFFFAB00);
85 | }
86 | });
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/iielse/switchbutton/demo/RecyclerActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.iielse.switchbutton.demo;
2 |
3 | import android.os.Bundle;
4 | import androidx.appcompat.app.AppCompatActivity;
5 | import androidx.appcompat.widget.Toolbar;
6 | import androidx.recyclerview.widget.LinearLayoutManager;
7 | import androidx.recyclerview.widget.RecyclerView;
8 |
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.TextView;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | import com.github.iielse.switchbutton.SwitchView;
18 |
19 |
20 | public class RecyclerActivity extends AppCompatActivity {
21 |
22 | private LinearLayoutManager layoutManager;
23 | private RecyclerView vRecycler;
24 | private ItemListAdapter adapter;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_recycler);
30 |
31 | ((Toolbar) findViewById(R.id.toolbar)).setNavigationOnClickListener(new View.OnClickListener() {
32 | @Override
33 | public void onClick(View v) {
34 | RecyclerActivity.this.finish();
35 | }
36 | });
37 |
38 |
39 | vRecycler = (RecyclerView) findViewById(R.id.v_recycler);
40 | vRecycler.setLayoutManager(layoutManager = new LinearLayoutManager(vRecycler.getContext()));
41 | vRecycler.setAdapter(adapter = new ItemListAdapter());
42 |
43 | adapter.set();
44 | }
45 |
46 | private static class ItemListAdapter extends RecyclerView.Adapter {
47 |
48 | List mDataList = new ArrayList();
49 |
50 | public void set() {
51 | mDataList.clear();
52 | for (int i = 0; i < 50; i++) {
53 | ItemObject itemObject = new ItemObject();
54 | itemObject.title = "item[" + i + "]";
55 | mDataList.add(itemObject);
56 | }
57 |
58 | notifyDataSetChanged();
59 | }
60 |
61 | private class ViewHolder extends RecyclerView.ViewHolder implements SwitchView.OnStateChangedListener {
62 | TextView tTitle;
63 | SwitchView vSwitch;
64 | ItemObject itemObject;
65 | int pos;
66 |
67 | ViewHolder(View view) {
68 | super(view);
69 | tTitle = (TextView) view.findViewById(R.id.t_title);
70 | vSwitch = (SwitchView) view.findViewById(R.id.v_switch);
71 | vSwitch.setOnStateChangedListener(this);
72 | }
73 |
74 | @Override
75 | public void toggleToOn(final SwitchView view) {
76 | view.postDelayed(new Runnable() {
77 | @Override
78 | public void run() {
79 | view.toggleSwitch(itemObject.isOpened = true);
80 | }
81 | }, 400);
82 | }
83 |
84 | @Override
85 | public void toggleToOff(final SwitchView view) {
86 | view.toggleSwitch(itemObject.isOpened = false);
87 | }
88 | }
89 |
90 | @Override
91 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
92 | return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list_content, parent, false));
93 | }
94 |
95 | @Override
96 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
97 | ViewHolder viewHolder = (ViewHolder) holder;
98 | viewHolder.pos = position;
99 | viewHolder.itemObject = mDataList.get(position);
100 | viewHolder.tTitle.setText(viewHolder.itemObject.title);
101 | viewHolder.vSwitch.setOpened(viewHolder.itemObject.isOpened);
102 | viewHolder.itemView.setBackgroundColor(position % 2 != 0 ? 0xFFFFFFFF : 0xFFEEEFF3);
103 | }
104 |
105 | @Override
106 | public int getItemCount() {
107 | return mDataList.size();
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/iielse/switchbutton/demo/ListActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.iielse.switchbutton.demo;
2 |
3 | import android.os.Bundle;
4 | import androidx.appcompat.app.AppCompatActivity;
5 | import androidx.appcompat.widget.Toolbar;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.BaseAdapter;
10 | import android.widget.ListView;
11 | import android.widget.TextView;
12 | import android.widget.Toast;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | import com.github.iielse.switchbutton.SwitchView;
18 |
19 |
20 |
21 | public class ListActivity extends AppCompatActivity {
22 |
23 | private ListView vList;
24 | private ItemListAdapter adapter;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_list);
30 |
31 | ((Toolbar) findViewById(R.id.toolbar)).setNavigationOnClickListener(new View.OnClickListener() {
32 | @Override
33 | public void onClick(View v) {
34 | ListActivity.this.finish();
35 | }
36 | });
37 |
38 |
39 | vList = (ListView) findViewById(R.id.v_list);
40 | vList.setAdapter(adapter = new ItemListAdapter());
41 |
42 | adapter.set();
43 | }
44 |
45 | private static class ItemListAdapter extends BaseAdapter {
46 |
47 | List mDataList = new ArrayList();
48 |
49 | public void set() {
50 | mDataList.clear();
51 | for (int i = 0; i < 50; i++) {
52 | ItemObject itemObject = new ItemObject();
53 | itemObject.title = "item[" + i + "]";
54 | mDataList.add(itemObject);
55 | }
56 |
57 | notifyDataSetChanged();
58 | }
59 |
60 | private class ViewHolder implements View.OnClickListener {
61 | View itemView;
62 | TextView tTitle;
63 | SwitchView vSwitch;
64 | ItemObject itemObject;
65 | int pos;
66 |
67 | ViewHolder(View view) {
68 | this.itemView = view;
69 | }
70 |
71 | @Override
72 | public void onClick(View v) {
73 | if (v == vSwitch) {
74 | itemObject.isOpened = vSwitch.isOpened();
75 | Toast.makeText(v.getContext().getApplicationContext(), "vSwitch[" + pos + "] change to " + itemObject.isOpened, Toast.LENGTH_SHORT).show();
76 | }
77 | }
78 | }
79 |
80 | @Override
81 | public int getCount() {
82 | return mDataList.size();
83 | }
84 |
85 | @Override
86 | public Object getItem(int position) {
87 | return mDataList.get(position);
88 | }
89 |
90 | @Override
91 | public long getItemId(int position) {
92 | return position;
93 | }
94 |
95 | @Override
96 | public View getView(int position, View convertView, ViewGroup parent) {
97 | if (convertView == null) {
98 | convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list_content, parent, false);
99 | }
100 | ViewHolder viewHolder = (ViewHolder) convertView.getTag();
101 | if (viewHolder == null) {
102 | viewHolder = new ViewHolder(convertView);
103 | convertView.setTag(viewHolder);
104 | viewHolder.tTitle = (TextView) convertView.findViewById(R.id.t_title);
105 | viewHolder.vSwitch = (SwitchView) convertView.findViewById(R.id.v_switch);
106 | viewHolder.vSwitch.setOnClickListener(viewHolder);
107 | }
108 |
109 | viewHolder.pos = position;
110 | viewHolder.itemObject = (ItemObject) getItem(position);
111 | viewHolder.tTitle.setText(viewHolder.itemObject.title);
112 | viewHolder.vSwitch.setOpened(viewHolder.itemObject.isOpened);
113 |
114 | viewHolder.itemView.setBackgroundColor(position % 2 != 0 ? 0xFFFFFFFF : 0xFFEEEFF3);
115 | return convertView;
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/iielse/switchbutton/demo/SpfsUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.iielse.switchbutton.demo;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.content.SharedPreferences.Editor;
6 |
7 | import java.util.Set;
8 |
9 | public class SpfsUtils {
10 |
11 | public static String ROOT_NAME = "app";
12 |
13 | public static void write(Context context, String key, Object value) {
14 | SharedPreferences spfs = context.getApplicationContext().getSharedPreferences(ROOT_NAME, Context.MODE_PRIVATE);
15 | Editor editor = spfs.edit();
16 | if (value instanceof String) {
17 | editor.putString(key, (String) value);
18 | } else if (value instanceof Double) {
19 | editor.putString(key, String.valueOf(((Double) value).doubleValue()));
20 | } else if (value instanceof Integer) {
21 | editor.putInt(key, (Integer) value);
22 | } else if (value instanceof Boolean) {
23 | editor.putBoolean(key, (Boolean) value);
24 | } else if (value instanceof Float) {
25 | editor.putFloat(key, (Float) value);
26 | } else if (value instanceof Long) {
27 | editor.putLong(key, (Long) value);
28 | } else {
29 | throw new IllegalArgumentException("not support type");
30 | }
31 | editor.commit();
32 | }
33 |
34 | public static String readString(Context context, String key) {
35 | return readString(context, key, null);
36 | }
37 |
38 | public static String readString(Context context, String key, String defValue) {
39 | SharedPreferences spfs = context.getApplicationContext().getSharedPreferences(ROOT_NAME, Context.MODE_PRIVATE);
40 | return spfs.getString(key, defValue);
41 | }
42 |
43 | public static int readInt(Context context, String key) {
44 | return readInt(context, key, 0);
45 | }
46 |
47 | public static int readInt(Context context, String key, int defValue) {
48 | SharedPreferences spfs = context.getApplicationContext().getSharedPreferences(ROOT_NAME, Context.MODE_PRIVATE);
49 | return spfs.getInt(key, defValue);
50 | }
51 |
52 | public static float readFloat(Context context, String key) {
53 | return readFloat(context, key, 0f);
54 | }
55 |
56 | public static float readFloat(Context context, String key, float defValue) {
57 | SharedPreferences spfs = context.getApplicationContext().getSharedPreferences(ROOT_NAME, Context.MODE_PRIVATE);
58 | return spfs.getFloat(key, defValue);
59 | }
60 |
61 | public static boolean readBoolean(Context context, String key) {
62 | return readBoolean(context, key, false);
63 | }
64 |
65 | public static boolean readBoolean(Context context, String key, boolean defValue) {
66 |
67 | SharedPreferences spfs = context.getApplicationContext().getSharedPreferences(ROOT_NAME, Context.MODE_PRIVATE);
68 | return spfs.getBoolean(key, defValue);
69 | }
70 |
71 | public static long readLong(Context context, String key) {
72 | return readLong(context, key, 0l);
73 | }
74 |
75 | public static long readLong(Context context, String key, long defValue) {
76 | SharedPreferences spfs = context.getApplicationContext().getSharedPreferences(ROOT_NAME, Context.MODE_PRIVATE);
77 | return spfs.getLong(key, defValue);
78 | }
79 |
80 | public static Set readStringSet(Context context, String key) {
81 | return readStringSet(context,key, null);
82 | }
83 |
84 | public static Set readStringSet(Context context, String key, Set defValues) {
85 | SharedPreferences spfs = context.getApplicationContext().getSharedPreferences(ROOT_NAME, Context.MODE_PRIVATE);
86 | return spfs.getStringSet(key, defValues);
87 | }
88 |
89 | public static boolean contains(Context context, String key) {
90 | SharedPreferences spfs = context.getApplicationContext().getSharedPreferences(ROOT_NAME, Context.MODE_PRIVATE);
91 | return spfs.contains(key);
92 | }
93 |
94 | public static boolean remove(Context context, String key) {
95 | SharedPreferences spfs = context.getApplicationContext().getSharedPreferences(ROOT_NAME, Context.MODE_PRIVATE);
96 | return spfs.edit().remove(key).commit();
97 | }
98 |
99 | public boolean clear(Context context) {
100 | SharedPreferences spfs = context.getApplicationContext().getSharedPreferences(ROOT_NAME, Context.MODE_PRIVATE);
101 | return spfs.edit().clear().commit();
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
24 |
25 |
31 |
32 |
35 |
36 |
40 |
41 |
42 |
49 |
50 |
56 |
57 |
61 |
62 |
63 |
69 |
70 |
71 |
72 |
76 |
77 |
81 |
82 |
86 |
87 |
88 |
95 |
96 |
102 |
103 |
107 |
108 |
114 |
115 |
116 |
122 |
123 |
124 |
125 |
129 |
130 |
135 |
136 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
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 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_size_intro.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
18 |
25 |
26 |
32 |
33 |
40 |
41 |
46 |
47 |
50 |
51 |
52 |
58 |
59 |
60 |
66 |
67 |
70 |
71 |
72 |
78 |
79 |
85 |
86 |
89 |
90 |
91 |
96 |
97 |
98 |
99 |
100 |
105 |
106 |
112 |
113 |
117 |
118 |
122 |
123 |
127 |
128 |
132 |
133 |
134 |
135 |
136 |
141 |
142 |
147 |
148 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/iielse/switchbutton/demo/NormalActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.iielse.switchbutton.demo;
2 |
3 | import android.graphics.drawable.AnimationDrawable;
4 | import android.os.Bundle;
5 | import android.os.Handler;
6 | import android.os.Looper;
7 | import androidx.annotation.NonNull;
8 |
9 |
10 | import androidx.appcompat.app.AppCompatActivity;
11 | import androidx.appcompat.widget.Toolbar;
12 | import android.view.View;
13 | import android.widget.ImageView;
14 | import android.widget.Toast;
15 |
16 | import com.github.iielse.switchbutton.SwitchView;
17 |
18 |
19 |
20 |
21 | public class NormalActivity extends AppCompatActivity {
22 |
23 | static final String SETTINGS_LAUNCHER_VOICE = "settings_launcher_voice";
24 | static final String SETTINGS_PUSH_ABLE = "settings_push_able";
25 |
26 | private SwitchView vLauncherVoice;
27 |
28 | private ImageView iLoadPush;
29 | private SwitchView vPushAble;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_normal);
35 |
36 | ((Toolbar) findViewById(R.id.toolbar)).setNavigationOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View v) {
39 | NormalActivity.this.finish();
40 | }
41 | });
42 |
43 | vLauncherVoice = (SwitchView) findViewById(R.id.v_launcher_voice);
44 | vPushAble = (SwitchView) findViewById(R.id.v_push_able);
45 | iLoadPush = (ImageView) findViewById(R.id.i_load_push);
46 |
47 | boolean isLauncherVoice = SpfsUtils.readBoolean(this, SETTINGS_LAUNCHER_VOICE, true);
48 | vLauncherVoice.setOpened(isLauncherVoice);
49 | vLauncherVoice.setOnClickListener(new View.OnClickListener() {
50 | @Override
51 | public void onClick(View v) {
52 | Toast.makeText(getApplicationContext(), "启动问候音切换到:" + vLauncherVoice.isOpened(), Toast.LENGTH_SHORT).show();
53 | SpfsUtils.write(NormalActivity.this, SETTINGS_LAUNCHER_VOICE, vLauncherVoice.isOpened());
54 | }
55 | });
56 |
57 | boolean isPushAble = SpfsUtils.readBoolean(this, SETTINGS_PUSH_ABLE, true);
58 | vPushAble.setOpened(isPushAble);
59 | vPushAble.setOnStateChangedListener(new SwitchView.OnStateChangedListener() {
60 | @Override
61 | public void toggleToOn(SwitchView view) {
62 | iLoadPush.setVisibility(View.VISIBLE);
63 | ((AnimationDrawable) iLoadPush.getBackground()).start();
64 |
65 | // 在此处被触发后,需要调用者根据业务逻辑确定SwitchView下一步动作。
66 | new PushServiceTask(new PushServiceStateChangedCallback() {
67 | @Override
68 | public void onPushServiceStateChanged(int state) {
69 | ((AnimationDrawable) iLoadPush.getBackground()).stop();
70 | iLoadPush.setVisibility(View.GONE);
71 |
72 | if (state == PushServiceStateChangedCallback.STATE_LAUNCHER_SUCCESS) {
73 | // 告诉SwitchView 更新UI
74 | Toast.makeText(getApplicationContext(), "推送服务开启完成", Toast.LENGTH_SHORT).show();
75 | vPushAble.toggleSwitch(true);
76 | SpfsUtils.write(NormalActivity.this, SETTINGS_PUSH_ABLE, true);
77 | } else {
78 | // 开启失败
79 | vPushAble.toggleSwitch(false);
80 | Toast.makeText(getApplicationContext(), "推送服务开启失败,请稍后重新尝试", Toast.LENGTH_SHORT).show();
81 | SpfsUtils.write(NormalActivity.this, SETTINGS_PUSH_ABLE, false);
82 | }
83 | }
84 | }).launch();
85 | }
86 |
87 | @Override
88 | public void toggleToOff(SwitchView view) {
89 | iLoadPush.setVisibility(View.VISIBLE);
90 | ((AnimationDrawable) iLoadPush.getBackground()).start();
91 |
92 | new PushServiceTask(new PushServiceStateChangedCallback() {
93 | @Override
94 | public void onPushServiceStateChanged(int state) {
95 | ((AnimationDrawable) iLoadPush.getBackground()).stop();
96 | iLoadPush.setVisibility(View.GONE);
97 |
98 | if (state == PushServiceStateChangedCallback.STATE_RELEASE_AND_CLOSE) {
99 | // 告诉SwitchView 更新UI
100 | vPushAble.toggleSwitch(false);
101 | SpfsUtils.write(NormalActivity.this, SETTINGS_PUSH_ABLE, false);
102 | } else {
103 | Toast.makeText(getApplicationContext(), "未知异常 关闭失败", Toast.LENGTH_SHORT).show();
104 | vPushAble.toggleSwitch(true);
105 | SpfsUtils.write(NormalActivity.this, SETTINGS_PUSH_ABLE, true);
106 | }
107 | }
108 | }).close();
109 | }
110 | });
111 | }
112 |
113 | interface PushServiceStateChangedCallback {
114 | int STATE_RELEASE_AND_CLOSE = 99;
115 | int STATE_LAUNCHER_FAILURE = 98;
116 | int STATE_LAUNCHER_SUCCESS = 1;
117 |
118 | void onPushServiceStateChanged(int state);
119 | }
120 |
121 |
122 | class PushServiceTask {
123 | PushServiceStateChangedCallback c;
124 | Handler handler = new Handler(Looper.getMainLooper());
125 |
126 | PushServiceTask(@NonNull PushServiceStateChangedCallback callback) {
127 | c = callback;
128 | }
129 |
130 | public void close() {
131 | new Thread(new Runnable() {
132 | @Override
133 | public void run() {
134 | try {
135 | Thread.sleep(500);
136 | } catch (InterruptedException e) {
137 | }
138 |
139 | handler.post(new Runnable() {
140 | @Override
141 | public void run() {
142 | c.onPushServiceStateChanged(PushServiceStateChangedCallback.STATE_RELEASE_AND_CLOSE);
143 | }
144 | });
145 | }
146 | }).start();
147 | }
148 |
149 | public void launch() {
150 | new Thread(new Runnable() {
151 | @Override
152 | public void run() {
153 | try {
154 | Thread.sleep(1500);
155 | } catch (InterruptedException e) {
156 | }
157 |
158 | handler.post(new Runnable() {
159 | @Override
160 | public void run() {
161 | if (System.currentTimeMillis() % 2 == 0) {
162 | c.onPushServiceStateChanged(PushServiceStateChangedCallback.STATE_LAUNCHER_FAILURE);
163 | } else {
164 | c.onPushServiceStateChanged(PushServiceStateChangedCallback.STATE_LAUNCHER_SUCCESS);
165 | }
166 | }
167 | });
168 |
169 | }
170 | }).start();
171 | }
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_api_intro.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
22 |
23 |
29 |
30 |
31 |
38 |
39 |
47 |
48 |
54 |
55 |
62 |
63 |
71 |
72 |
79 |
80 |
88 |
89 |
90 |
91 |
92 |
99 |
100 |
107 |
108 |
114 |
115 |
122 |
123 |
131 |
132 |
133 |
134 |
141 |
142 |
149 |
150 |
156 |
157 |
165 |
166 |
174 |
175 |
185 |
186 |
196 |
197 |
198 |
205 |
206 |
217 |
218 |
219 |
220 |
221 |
222 |
--------------------------------------------------------------------------------
/switchbutton/src/main/java/com/github/iielse/switchbutton/SwitchView.java:
--------------------------------------------------------------------------------
1 | package com.github.iielse.switchbutton;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Paint;
9 | import android.graphics.Path;
10 | import android.graphics.RadialGradient;
11 | import android.graphics.RectF;
12 | import android.graphics.Shader;
13 | import android.os.Build;
14 | import android.os.Parcel;
15 | import android.os.Parcelable;
16 | import android.util.AttributeSet;
17 | import android.util.TypedValue;
18 | import android.view.MotionEvent;
19 | import android.view.View;
20 | import android.view.animation.AccelerateInterpolator;
21 |
22 | /**
23 | * hei hei hei
24 | */
25 | public class SwitchView extends View {
26 |
27 | private static final int STATE_SWITCH_ON = 4;
28 | private static final int STATE_SWITCH_ON2 = 3;
29 | private static final int STATE_SWITCH_OFF2 = 2;
30 | private static final int STATE_SWITCH_OFF = 1;
31 |
32 | private final AccelerateInterpolator interpolator = new AccelerateInterpolator(2);
33 | private final Paint paint = new Paint();
34 | private final Path sPath = new Path();
35 | private final Path bPath = new Path();
36 | private final RectF bRectF = new RectF();
37 | private float sAnim, bAnim;
38 | private RadialGradient shadowGradient;
39 |
40 | protected float ratioAspect = 0.68f; // (0,1]
41 | protected float animationSpeed = 0.1f; // (0,1]
42 |
43 | private int state;
44 | private int lastState;
45 | private boolean isCanVisibleDrawing = false;
46 | private OnClickListener mOnClickListener;
47 | protected int colorPrimary;
48 | protected int colorPrimaryDark;
49 | protected int colorOff;
50 | protected int colorOffDark;
51 | protected int colorShadow;
52 | protected int colorBar;
53 | protected int colorBackground;
54 | protected boolean hasShadow;
55 | protected boolean isOpened;
56 |
57 | private float sRight;
58 | private float sCenterX, sCenterY;
59 | private float sScale;
60 |
61 | private float bOffset;
62 | private float bRadius, bStrokeWidth;
63 | private float bWidth;
64 | private float bLeft;
65 | private float bRight;
66 | private float bOnLeftX, bOn2LeftX, bOff2LeftX, bOffLeftX;
67 |
68 | private float shadowReservedHeight;
69 |
70 | public SwitchView(Context context) {
71 | this(context, null);
72 | }
73 |
74 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
75 | public SwitchView(Context context, AttributeSet attrs) {
76 | super(context, attrs);
77 | setLayerType(LAYER_TYPE_SOFTWARE, null);
78 |
79 | final int DEFAULT_COLOR_PRIMARY = 0xFF4BD763;
80 | final int DEFAULT_COLOR_PRIMARY_DARK = 0xFF3AC652;
81 |
82 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwitchView);
83 | colorPrimary = a.getColor(R.styleable.SwitchView_primaryColor, DEFAULT_COLOR_PRIMARY);
84 | colorPrimaryDark = a.getColor(R.styleable.SwitchView_primaryColorDark, DEFAULT_COLOR_PRIMARY_DARK);
85 | colorOff = a.getColor(R.styleable.SwitchView_offColor, 0xFFE3E3E3);
86 | colorOffDark = a.getColor(R.styleable.SwitchView_offColorDark, 0xFFBFBFBF);
87 | colorShadow = a.getColor(R.styleable.SwitchView_shadowColor, 0xFF333333);
88 | colorBar = a.getColor(R.styleable.SwitchView_barColor, 0xFFFFFFFF);
89 | colorBackground = a.getColor(R.styleable.SwitchView_bgColor, 0xFFFFFFFF);
90 | ratioAspect = a.getFloat(R.styleable.SwitchView_ratioAspect, 0.68f);
91 | hasShadow = a.getBoolean(R.styleable.SwitchView_hasShadow, true);
92 | isOpened = a.getBoolean(R.styleable.SwitchView_isOpened, false);
93 | state = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF;
94 | lastState = state;
95 | a.recycle();
96 |
97 | if (colorPrimary == DEFAULT_COLOR_PRIMARY && colorPrimaryDark == DEFAULT_COLOR_PRIMARY_DARK) {
98 | try {
99 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
100 | TypedValue primaryColorTypedValue = new TypedValue();
101 | context.getTheme().resolveAttribute(android.R.attr.colorPrimary, primaryColorTypedValue, true);
102 | if (primaryColorTypedValue.data > 0) colorPrimary = primaryColorTypedValue.data;
103 | TypedValue primaryColorDarkTypedValue = new TypedValue();
104 | context.getTheme().resolveAttribute(android.R.attr.colorPrimaryDark, primaryColorDarkTypedValue, true);
105 | if (primaryColorDarkTypedValue.data > 0)
106 | colorPrimaryDark = primaryColorDarkTypedValue.data;
107 | }
108 | } catch (Exception ignore) {
109 | }
110 | }
111 | }
112 |
113 | public void setColor(int newColorPrimary, int newColorPrimaryDark) {
114 | setColor(newColorPrimary, newColorPrimaryDark, colorOff, colorOffDark);
115 | }
116 |
117 | public void setColor(int newColorPrimary, int newColorPrimaryDark, int newColorOff, int newColorOffDark) {
118 | setColor(newColorPrimary, newColorPrimaryDark, newColorOff, newColorOffDark, colorShadow);
119 | }
120 |
121 | public void setColor(int newColorPrimary, int newColorPrimaryDark, int newColorOff, int newColorOffDark, int newColorShadow) {
122 | colorPrimary = newColorPrimary;
123 | colorPrimaryDark = newColorPrimaryDark;
124 | colorOff = newColorOff;
125 | colorOffDark = newColorOffDark;
126 | colorShadow = newColorShadow;
127 | invalidate();
128 | }
129 |
130 | public void setColor(int newColorPrimary, int newColorPrimaryDark, int newColorOff, int newColorOffDark, int newColorShadow, int newColorBar, int newColorBackground) {
131 | colorPrimary = newColorPrimary;
132 | colorPrimaryDark = newColorPrimaryDark;
133 | colorOff = newColorOff;
134 | colorOffDark = newColorOffDark;
135 | colorShadow = newColorShadow;
136 | colorBar = newColorBar;
137 | colorBackground = newColorBackground;
138 | invalidate();
139 | }
140 |
141 | public void setShadow(boolean shadow) {
142 | hasShadow = shadow;
143 | invalidate();
144 | }
145 |
146 | public boolean isOpened() {
147 | return isOpened;
148 | }
149 |
150 | public void setOpened(boolean isOpened) {
151 | int wishState = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF;
152 | if (wishState == state) {
153 | return;
154 | }
155 | refreshState(wishState);
156 | }
157 |
158 | public void toggleSwitch(boolean isOpened) {
159 | int wishState = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF;
160 | if (wishState == state) {
161 | return;
162 | }
163 | if ((wishState == STATE_SWITCH_ON && (state == STATE_SWITCH_OFF || state == STATE_SWITCH_OFF2))
164 | || (wishState == STATE_SWITCH_OFF && (state == STATE_SWITCH_ON || state == STATE_SWITCH_ON2))) {
165 | sAnim = 1;
166 | }
167 | bAnim = 1;
168 | refreshState(wishState);
169 | }
170 |
171 | private void refreshState(int newState) {
172 | if (!isOpened && newState == STATE_SWITCH_ON) {
173 | isOpened = true;
174 | } else if (isOpened && newState == STATE_SWITCH_OFF) {
175 | isOpened = false;
176 | }
177 | lastState = state;
178 | state = newState;
179 | postInvalidate();
180 | }
181 |
182 | @Override
183 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
184 | int widthSize = MeasureSpec.getSize(widthMeasureSpec);
185 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
186 | int resultWidth;
187 | if (widthMode == MeasureSpec.EXACTLY) {
188 | resultWidth = widthSize;
189 | } else {
190 | resultWidth = (int) (56 * getResources().getDisplayMetrics().density + 0.5f)
191 | + getPaddingLeft() + getPaddingRight();
192 | if (widthMode == MeasureSpec.AT_MOST) {
193 | resultWidth = Math.min(resultWidth, widthSize);
194 | }
195 | }
196 |
197 | int heightSize = MeasureSpec.getSize(heightMeasureSpec);
198 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
199 | int resultHeight;
200 | if (heightMode == MeasureSpec.EXACTLY) {
201 | resultHeight = heightSize;
202 | } else {
203 | resultHeight = (int) (resultWidth * ratioAspect) + getPaddingTop() + getPaddingBottom();
204 | if (heightMode == MeasureSpec.AT_MOST) {
205 | resultHeight = Math.min(resultHeight, heightSize);
206 | }
207 | }
208 | setMeasuredDimension(resultWidth, resultHeight);
209 | }
210 |
211 | @Override
212 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
213 | super.onSizeChanged(w, h, oldw, oldh);
214 |
215 | isCanVisibleDrawing = w > getPaddingLeft() + getPaddingRight() && h > getPaddingTop() + getPaddingBottom();
216 |
217 | if (isCanVisibleDrawing) {
218 | int actuallyDrawingAreaWidth = w - getPaddingLeft() - getPaddingRight();
219 | int actuallyDrawingAreaHeight = h - getPaddingTop() - getPaddingBottom();
220 |
221 | int actuallyDrawingAreaLeft;
222 | int actuallyDrawingAreaRight;
223 | int actuallyDrawingAreaTop;
224 | int actuallyDrawingAreaBottom;
225 | if (actuallyDrawingAreaWidth * ratioAspect < actuallyDrawingAreaHeight) {
226 | actuallyDrawingAreaLeft = getPaddingLeft();
227 | actuallyDrawingAreaRight = w - getPaddingRight();
228 | int heightExtraSize = (int) (actuallyDrawingAreaHeight - actuallyDrawingAreaWidth * ratioAspect);
229 | actuallyDrawingAreaTop = getPaddingTop() + heightExtraSize / 2;
230 | actuallyDrawingAreaBottom = getHeight() - getPaddingBottom() - heightExtraSize / 2;
231 | } else {
232 | int widthExtraSize = (int) (actuallyDrawingAreaWidth - actuallyDrawingAreaHeight / ratioAspect);
233 | actuallyDrawingAreaLeft = getPaddingLeft() + widthExtraSize / 2;
234 | actuallyDrawingAreaRight = getWidth() - getPaddingRight() - widthExtraSize / 2;
235 | actuallyDrawingAreaTop = getPaddingTop();
236 | actuallyDrawingAreaBottom = getHeight() - getPaddingBottom();
237 | }
238 |
239 | shadowReservedHeight = (int) ((actuallyDrawingAreaBottom - actuallyDrawingAreaTop) * 0.07f);
240 | float sLeft = actuallyDrawingAreaLeft;
241 | float sTop = actuallyDrawingAreaTop + shadowReservedHeight;
242 | sRight = actuallyDrawingAreaRight;
243 | float sBottom = actuallyDrawingAreaBottom - shadowReservedHeight;
244 |
245 | float sHeight = sBottom - sTop;
246 | sCenterX = (sRight + sLeft) / 2;
247 | sCenterY = (sBottom + sTop) / 2;
248 |
249 | bLeft = sLeft;
250 | bWidth = sBottom - sTop;
251 | bRight = sLeft + bWidth;
252 | final float halfHeightOfS = bWidth / 2; // OfB
253 | bRadius = halfHeightOfS * 0.95f;
254 | bOffset = bRadius * 0.2f; // offset of switching
255 | bStrokeWidth = (halfHeightOfS - bRadius) * 2;
256 | bOnLeftX = sRight - bWidth;
257 | bOn2LeftX = bOnLeftX - bOffset;
258 | bOffLeftX = sLeft;
259 | bOff2LeftX = bOffLeftX + bOffset;
260 | sScale = 1 - bStrokeWidth / sHeight;
261 |
262 | sPath.reset();
263 | RectF sRectF = new RectF();
264 | sRectF.top = sTop;
265 | sRectF.bottom = sBottom;
266 | sRectF.left = sLeft;
267 | sRectF.right = sLeft + sHeight;
268 | sPath.arcTo(sRectF, 90, 180);
269 | sRectF.left = sRight - sHeight;
270 | sRectF.right = sRight;
271 | sPath.arcTo(sRectF, 270, 180);
272 | sPath.close();
273 |
274 | bRectF.left = bLeft;
275 | bRectF.right = bRight;
276 | bRectF.top = sTop + bStrokeWidth / 2; // bTop = sTop
277 | bRectF.bottom = sBottom - bStrokeWidth / 2; // bBottom = sBottom
278 | float bCenterX = (bRight + bLeft) / 2;
279 | float bCenterY = (sBottom + sTop) / 2;
280 |
281 | int red = colorShadow >> 16 & 0xFF;
282 | int green = colorShadow >> 8 & 0xFF;
283 | int blue = colorShadow & 0xFF;
284 | shadowGradient = new RadialGradient(bCenterX, bCenterY, bRadius, Color.argb(200, red, green, blue),
285 | Color.argb(25, red, green, blue), Shader.TileMode.CLAMP);
286 | }
287 | }
288 |
289 | private void calcBPath(float percent) {
290 | bPath.reset();
291 | bRectF.left = bLeft + bStrokeWidth / 2;
292 | bRectF.right = bRight - bStrokeWidth / 2;
293 | bPath.arcTo(bRectF, 90, 180);
294 | bRectF.left = bLeft + percent * bOffset + bStrokeWidth / 2;
295 | bRectF.right = bRight + percent * bOffset - bStrokeWidth / 2;
296 | bPath.arcTo(bRectF, 270, 180);
297 | bPath.close();
298 | }
299 |
300 | private float calcBTranslate(float percent) {
301 | float result = 0;
302 | switch (state - lastState) {
303 | case 1:
304 | if (state == STATE_SWITCH_OFF2) {
305 | result = bOffLeftX; // off -> off2
306 | } else if (state == STATE_SWITCH_ON) {
307 | result = bOnLeftX - (bOnLeftX - bOn2LeftX) * percent; // on2 -> on
308 | }
309 | break;
310 | case 2:
311 | if (state == STATE_SWITCH_ON) {
312 | result = bOnLeftX - (bOnLeftX - bOffLeftX) * percent; // off2 -> on
313 | } else if (state == STATE_SWITCH_ON2) {
314 | result = bOn2LeftX - (bOn2LeftX - bOffLeftX) * percent; // off -> on2
315 | }
316 | break;
317 | case 3:
318 | result = bOnLeftX - (bOnLeftX - bOffLeftX) * percent; // off -> on
319 | break;
320 | case -1:
321 | if (state == STATE_SWITCH_ON2) {
322 | result = bOn2LeftX + (bOnLeftX - bOn2LeftX) * percent; // on -> on2
323 | } else if (state == STATE_SWITCH_OFF) {
324 | result = bOffLeftX; // off2 -> off
325 | }
326 | break;
327 | case -2:
328 | if (state == STATE_SWITCH_OFF) {
329 | result = bOffLeftX + (bOn2LeftX - bOffLeftX) * percent; // on2 -> off
330 | } else if (state == STATE_SWITCH_OFF2) {
331 | result = bOff2LeftX + (bOnLeftX - bOff2LeftX) * percent; // on -> off2
332 | }
333 | break;
334 | case -3:
335 | result = bOffLeftX + (bOnLeftX - bOffLeftX) * percent; // on -> off
336 | break;
337 | default: // init
338 | case 0:
339 | if (state == STATE_SWITCH_OFF) {
340 | result = bOffLeftX; // off -> off
341 | } else if (state == STATE_SWITCH_ON) {
342 | result = bOnLeftX; // on -> on
343 | }
344 | break;
345 | }
346 | return result - bOffLeftX;
347 | }
348 |
349 | @Override
350 | protected void onDraw(Canvas canvas) {
351 | super.onDraw(canvas);
352 | if (!isCanVisibleDrawing) return;
353 |
354 | paint.setAntiAlias(true);
355 | final boolean isOn = (state == STATE_SWITCH_ON || state == STATE_SWITCH_ON2);
356 | // Draw background
357 | paint.setStyle(Paint.Style.FILL);
358 | paint.setColor(isOn ? colorPrimary : colorOff);
359 | canvas.drawPath(sPath, paint);
360 |
361 | sAnim = sAnim - animationSpeed > 0 ? sAnim - animationSpeed : 0;
362 | bAnim = bAnim - animationSpeed > 0 ? bAnim - animationSpeed : 0;
363 |
364 | final float dsAnim = interpolator.getInterpolation(sAnim);
365 | final float dbAnim = interpolator.getInterpolation(bAnim);
366 | // Draw background animation
367 | final float scale = sScale * (isOn ? dsAnim : 1 - dsAnim);
368 | final float scaleOffset = (sRight - sCenterX - bRadius) * (isOn ? 1 - dsAnim : dsAnim);
369 | canvas.save();
370 | canvas.scale(scale, scale, sCenterX + scaleOffset, sCenterY);
371 | paint.setColor(colorBackground);
372 | canvas.drawPath(sPath, paint);
373 | canvas.restore();
374 | // To prepare center bar path
375 | canvas.save();
376 | canvas.translate(calcBTranslate(dbAnim), shadowReservedHeight);
377 | final boolean isState2 = (state == STATE_SWITCH_ON2 || state == STATE_SWITCH_OFF2);
378 | calcBPath(isState2 ? 1 - dbAnim : dbAnim);
379 | // Use center bar path to draw shadow
380 | if (hasShadow) {
381 | paint.setStyle(Paint.Style.FILL);
382 | paint.setShader(shadowGradient);
383 | canvas.drawPath(bPath, paint);
384 | paint.setShader(null);
385 | }
386 | canvas.translate(0, -shadowReservedHeight);
387 | // draw bar
388 | canvas.scale(0.98f, 0.98f, bWidth / 2, bWidth / 2);
389 | paint.setStyle(Paint.Style.FILL);
390 | paint.setColor(colorBar);
391 | canvas.drawPath(bPath, paint);
392 | paint.setStyle(Paint.Style.STROKE);
393 | paint.setStrokeWidth(bStrokeWidth * 0.5f);
394 | paint.setColor(isOn ? colorPrimaryDark : colorOffDark);
395 | canvas.drawPath(bPath, paint);
396 | canvas.restore();
397 |
398 | paint.reset();
399 | if (sAnim > 0 || bAnim > 0) invalidate();
400 | }
401 |
402 | @Override
403 | public boolean onTouchEvent(MotionEvent event) {
404 | if ((state == STATE_SWITCH_ON || state == STATE_SWITCH_OFF) && (sAnim * bAnim == 0)) {
405 | switch (event.getAction()) {
406 | case MotionEvent.ACTION_DOWN:
407 | return true;
408 | case MotionEvent.ACTION_UP:
409 | lastState = state;
410 |
411 | bAnim = 1;
412 | if (state == STATE_SWITCH_OFF) {
413 | refreshState(STATE_SWITCH_OFF2);
414 | listener.toggleToOn(this);
415 | } else if (state == STATE_SWITCH_ON) {
416 | refreshState(STATE_SWITCH_ON2);
417 | listener.toggleToOff(this);
418 | }
419 |
420 | if (mOnClickListener != null) {
421 | mOnClickListener.onClick(this);
422 | }
423 | break;
424 | }
425 | }
426 | return super.onTouchEvent(event);
427 | }
428 |
429 | @Override
430 | public void setOnClickListener(OnClickListener l) {
431 | super.setOnClickListener(l);
432 | mOnClickListener = l;
433 | }
434 |
435 | public interface OnStateChangedListener {
436 | void toggleToOn(SwitchView view);
437 |
438 | void toggleToOff(SwitchView view);
439 | }
440 |
441 | private OnStateChangedListener listener = new OnStateChangedListener() {
442 | @Override
443 | public void toggleToOn(SwitchView view) {
444 | toggleSwitch(true);
445 | }
446 |
447 | @Override
448 | public void toggleToOff(SwitchView view) {
449 | toggleSwitch(false);
450 | }
451 | };
452 |
453 | public void setOnStateChangedListener(OnStateChangedListener listener) {
454 | if (listener == null) throw new IllegalArgumentException("empty listener");
455 | this.listener = listener;
456 | }
457 |
458 | @Override
459 | public Parcelable onSaveInstanceState() {
460 | Parcelable superState = super.onSaveInstanceState();
461 | SavedState ss = new SavedState(superState);
462 | ss.isOpened = isOpened;
463 | return ss;
464 | }
465 |
466 | @Override
467 | public void onRestoreInstanceState(Parcelable state) {
468 | SavedState ss = (SavedState) state;
469 | super.onRestoreInstanceState(ss.getSuperState());
470 | this.isOpened = ss.isOpened;
471 | this.state = this.isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF;
472 | invalidate();
473 | }
474 |
475 | private static final class SavedState extends BaseSavedState {
476 | private boolean isOpened;
477 |
478 | SavedState(Parcelable superState) {
479 | super(superState);
480 | }
481 |
482 | private SavedState(Parcel in) {
483 | super(in);
484 | isOpened = 1 == in.readInt();
485 | }
486 |
487 | @Override
488 | public void writeToParcel(Parcel out, int flags) {
489 | super.writeToParcel(out, flags);
490 | out.writeInt(isOpened ? 1 : 0);
491 | }
492 |
493 | // fixed by Night99 https://github.com/g19980115
494 | @Override
495 | public int describeContents() {
496 | return 0;
497 | }
498 |
499 | public static final Creator CREATOR = new Creator() {
500 | @Override
501 | public SavedState createFromParcel(Parcel in) {
502 | return new SavedState(in);
503 | }
504 |
505 | @Override
506 | public SavedState[] newArray(int size) {
507 | return new SavedState[size];
508 | }
509 | };
510 | }
511 | }
512 |
--------------------------------------------------------------------------------