├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── cleveroad
│ │ └── example
│ │ └── androidmanimation
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── cleveroad
│ │ │ └── example
│ │ │ └── androidmanimation
│ │ │ ├── AnimationActivity.java
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── layout
│ │ ├── activity_animation.xml
│ │ └── activity_main.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── cleveroad
│ └── example
│ └── androidmanimation
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── images
└── animation_demo.gif
├── library
├── .gitignore
├── build.gradle
├── gradle-mvn-push.gradle
├── gradle.properties
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── cleveroad
│ │ └── androidmanimation
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── cleveroad
│ │ │ └── androidmanimation
│ │ │ ├── AnimationDialogFragment.java
│ │ │ ├── ColorUtil.java
│ │ │ ├── Constants.java
│ │ │ ├── DrawableObject.java
│ │ │ ├── DrawableObjectImpl.java
│ │ │ ├── DrawableUtils.java
│ │ │ ├── FirstLayer.java
│ │ │ ├── FourthLayer.java
│ │ │ ├── Layer.java
│ │ │ ├── LoadingAnimationView.java
│ │ │ ├── Resetable.java
│ │ │ ├── SecondLayer.java
│ │ │ ├── ThirdLayer.java
│ │ │ └── YellowRectangle.java
│ └── res
│ │ ├── layout
│ │ └── lav_view_loading_animation.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── public.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── cleveroad
│ └── androidmanimation
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | ### Android template
10 | # Built application files
11 | *.apk
12 | *.ap_
13 |
14 | # Files for the Dalvik VM
15 | *.dex
16 |
17 | # Java class files
18 | *.class
19 |
20 | # Generated files
21 | bin/
22 | gen/
23 |
24 | # Gradle files
25 | .gradle/
26 | build/
27 |
28 | # Local configuration file (sdk path, etc)
29 | local.properties
30 |
31 | # Proguard folder generated by Eclipse
32 | proguard/
33 |
34 | # Log Files
35 | *.log
36 |
37 | # Android Studio Navigation editor temp files
38 | .navigation/
39 | ### JetBrains template
40 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
41 |
42 | *.iml
43 |
44 | ## Directory-based project format:
45 | .idea/
46 | # if you remove the above rule, at least ignore the following:
47 |
48 | # User-specific stuff:
49 | # .idea/workspace.xml
50 | # .idea/tasks.xml
51 | # .idea/dictionaries
52 |
53 | # Sensitive or high-churn files:
54 | # .idea/dataSources.ids
55 | # .idea/dataSources.xml
56 | # .idea/sqlDataSources.xml
57 | # .idea/dynamic.xml
58 | # .idea/uiDesigner.xml
59 |
60 | # Gradle:
61 | # .idea/gradle.xml
62 | # .idea/libraries
63 |
64 | # Mongo Explorer plugin:
65 | # .idea/mongoSettings.xml
66 |
67 | ## File-based project format:
68 | *.ipr
69 | *.iws
70 |
71 | ## Plugin-specific files:
72 |
73 | # IntelliJ
74 | /out/
75 |
76 | # mpeltonen/sbt-idea plugin
77 | .idea_modules/
78 |
79 | # JIRA plugin
80 | atlassian-ide-plugin.xml
81 |
82 | # Crashlytics plugin (for Android Studio and IntelliJ)
83 | com_crashlytics_export_strings.xml
84 | crashlytics.properties
85 | crashlytics-build.properties
86 |
87 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Cleveroad Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android Marshmallow Boot Animation View #
2 |
3 | Implementation of [Android Marshmallow Boot Animation](https://dribbble.com/shots/2487137-Daily-UI-076-Loading-Android-Marshmallow-Boot).
4 |
5 | 
6 |
7 | To use LoadingAnimationView first add dependency to your project:
8 |
9 | ```groovy
10 | dependencies {
11 | compile 'com.cleveroad:androidmanimation:0.9.1'
12 | }
13 | ```
14 |
15 | Then you can declare it in your layout file like this:
16 |
17 | ```XML
18 |
32 | ```
33 |
34 | Pay attention that you need to manually start/pause/stop animation.
35 |
36 | ```JAVA
37 | private LoadingAnimationView animation;
38 |
39 | ...
40 |
41 | @Override
42 | protected void onResume() {
43 | super.onResume();
44 | // user interacts with screen, start animation
45 | animation.startAnimation();
46 | }
47 |
48 | @Override
49 | protected void onPause() {
50 | // user stops interacting with screen, pause animation, save your battery!
51 | animation.pauseAnimation();
52 | super.onPause();
53 | }
54 |
55 | @Override
56 | protected void onDestroy() {
57 | // user leaves screen. Clean up everything.
58 | animation.stopAnimation();
59 | super.onDestroy();
60 | }
61 | ```
62 |
63 | Another way to display loading animation is to use builder and display a dialog:
64 |
65 | ```JAVA
66 | AnimationDialogFragment fragment = new AnimationDialogFragment.Builder()
67 | .setBackgroundColor(Color.WHITE)
68 | .setFirstColor(getResources().getColor(R.color.google_red))
69 | .setSecondColor(getResources().getColor(R.color.google_green))
70 | .setThirdColor(getResources().getColor(R.color.google_blue))
71 | .setFourthColor(getResources().getColor(R.color.google_yellow))
72 | .setSpeedCoefficient(1.0f)
73 | .build();
74 | fragment.show(getSupportFragmentManager(), "Animation");
75 | ```
76 |
77 | ## Changelog
78 |
79 | | Version | Changes |
80 | | --- | --- |
81 | | v.0.9.1 | Replaced Timer with ValueAnimator |
82 | | v.0.9.0 | First public release |
83 |
84 | #### Migrations from v.0.9.0 to v.0.9.1
85 | * **LoadingAnimationView.getState()** was replaced with **LoadingAnimationView.isRunning()** method.
86 | * All resources marked as private, prefix `lav_` added to their names.
87 | * Minimum SDK version set to 12
88 |
89 |
90 |
91 | #### Support ####
92 | * * *
93 | If you have any other questions regarding the use of this library, please contact us for support at info@cleveroad.com (email subject: "Android loading animation view. Support request.")
94 | or
95 |
96 | Use our contacts:
97 |
98 | * [Official site](https://www.cleveroad.com/?utm_source=github&utm_medium=link&utm_campaign=contacts)
99 | * [Facebook account](https://www.facebook.com/cleveroadinc)
100 | * [Twitter account](https://twitter.com/CleveroadInc)
101 | * [Google+ account](https://plus.google.com/+CleveroadInc/)
102 |
103 |
104 | #### License ####
105 | * * *
106 | The MIT License (MIT)
107 |
108 | Copyright (c) 2016 Cleveroad Inc.
109 |
110 | Permission is hereby granted, free of charge, to any person obtaining a copy
111 | of this software and associated documentation files (the "Software"), to deal
112 | in the Software without restriction, including without limitation the rights
113 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
114 | copies of the Software, and to permit persons to whom the Software is
115 | furnished to do so, subject to the following conditions:
116 |
117 | The above copyright notice and this permission notice shall be included in all
118 | copies or substantial portions of the Software.
119 |
120 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
121 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
122 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
123 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
124 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
125 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
126 | SOFTWARE.
127 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | ### Android template
3 | # Built application files
4 | *.apk
5 | *.ap_
6 |
7 | # Files for the Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
30 | # Android Studio Navigation editor temp files
31 | .navigation/
32 | ### JetBrains template
33 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
34 |
35 | *.iml
36 |
37 | ## Directory-based project format:
38 | .idea/
39 | # if you remove the above rule, at least ignore the following:
40 |
41 | # User-specific stuff:
42 | # .idea/workspace.xml
43 | # .idea/tasks.xml
44 | # .idea/dictionaries
45 |
46 | # Sensitive or high-churn files:
47 | # .idea/dataSources.ids
48 | # .idea/dataSources.xml
49 | # .idea/sqlDataSources.xml
50 | # .idea/dynamic.xml
51 | # .idea/uiDesigner.xml
52 |
53 | # Gradle:
54 | # .idea/gradle.xml
55 | # .idea/libraries
56 |
57 | # Mongo Explorer plugin:
58 | # .idea/mongoSettings.xml
59 |
60 | ## File-based project format:
61 | *.ipr
62 | *.iws
63 |
64 | ## Plugin-specific files:
65 |
66 | # IntelliJ
67 | /out/
68 |
69 | # mpeltonen/sbt-idea plugin
70 | .idea_modules/
71 |
72 | # JIRA plugin
73 | atlassian-ide-plugin.xml
74 |
75 | # Crashlytics plugin (for Android Studio and IntelliJ)
76 | com_crashlytics_export_strings.xml
77 | crashlytics.properties
78 | crashlytics-build.properties
79 |
80 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.cleveroad.example.androidmanimation"
9 | minSdkVersion 12
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.2.0'
26 | compile project(':library')
27 | }
28 |
--------------------------------------------------------------------------------
/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 C:\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 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/cleveroad/example/androidmanimation/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.example.androidmanimation;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/cleveroad/example/androidmanimation/AnimationActivity.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.example.androidmanimation;
2 |
3 | import android.os.Build;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.View;
8 |
9 | import com.cleveroad.androidmanimation.LoadingAnimationView;
10 |
11 | /**
12 | * Example of using animation as view in layout.
13 | */
14 | public class AnimationActivity extends AppCompatActivity {
15 |
16 | private LoadingAnimationView animation;
17 |
18 | @Override
19 | protected void onCreate(@Nullable Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_animation);
22 | animation = (LoadingAnimationView) findViewById(R.id.animation);
23 | animation.setOnClickListener(new View.OnClickListener() {
24 | @Override
25 | public void onClick(View v) {
26 | if (!animation.isRunning()) {
27 | animation.startAnimation();
28 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
29 | animation.pauseAnimation();
30 | } else {
31 | animation.stopAnimation();
32 | }
33 | }
34 | });
35 | }
36 |
37 | @Override
38 | protected void onResume() {
39 | super.onResume();
40 | animation.startAnimation();
41 | }
42 |
43 | @Override
44 | protected void onPause() {
45 | animation.pauseAnimation();
46 | super.onPause();
47 | }
48 |
49 | @Override
50 | protected void onDestroy() {
51 | animation.stopAnimation();
52 | super.onDestroy();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/cleveroad/example/androidmanimation/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.example.androidmanimation;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 |
8 | import com.cleveroad.androidmanimation.AnimationDialogFragment;
9 |
10 | public class MainActivity extends AppCompatActivity {
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_main);
16 | findViewById(R.id.btn_activity).setOnClickListener(new View.OnClickListener() {
17 | @Override
18 | public void onClick(View v) {
19 | startActivity(new Intent(MainActivity.this, AnimationActivity.class));
20 | }
21 | });
22 | findViewById(R.id.btn_dialog).setOnClickListener(new View.OnClickListener() {
23 | @Override
24 | public void onClick(View v) {
25 | AnimationDialogFragment fragment = new AnimationDialogFragment.Builder()
26 | .build();
27 | fragment.show(getSupportFragmentManager(), "Animation");
28 | }
29 | });
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_animation.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/Android-Marshmallow-Boot-Animation/47c0422b52d1e3fd1e8e61f04fba0063658bd3bb/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/Android-Marshmallow-Boot-Animation/47c0422b52d1e3fd1e8e61f04fba0063658bd3bb/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/Android-Marshmallow-Boot-Animation/47c0422b52d1e3fd1e8e61f04fba0063658bd3bb/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/Android-Marshmallow-Boot-Animation/47c0422b52d1e3fd1e8e61f04fba0063658bd3bb/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/Android-Marshmallow-Boot-Animation/47c0422b52d1e3fd1e8e61f04fba0063658bd3bb/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Android M Animation Example
3 | Activity
4 | Dialog
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/cleveroad/example/androidmanimation/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.example.androidmanimation;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.0.0-beta6'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | VERSION_NAME=0.9.1
2 | VERSION_CODE=2
3 | GROUP=com.cleveroad
4 |
5 | POM_DESCRIPTION=Implementation of Android Marshmallow Boot Animation.
6 |
7 | POM_URL=https://github.com/Cleveroad/CRAndroidMBootAnimationView.git
8 | POM_SCM_URL=https://github.com/Cleveroad/CRAndroidMBootAnimationView.git
9 | POM_SCM_CONNECTION=scm:git@github.com:Cleveroad/CRAndroidMBootAnimationView.git
10 | POM_SCM_DEV_CONNECTION=scm:git@github.com:Cleveroad/CRAndroidMBootAnimationView.git
11 |
12 | POM_LICENCE_NAME=MIT License
13 | POM_LICENCE_URL=http://opensource.org/licenses/MIT
14 | POM_LICENCE_DIST=repo
15 |
16 | POM_DEVELOPER_ID=cleveroad
17 | POM_DEVELOPER_NAME=Cleveroad
--------------------------------------------------------------------------------
/images/animation_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/Android-Marshmallow-Boot-Animation/47c0422b52d1e3fd1e8e61f04fba0063658bd3bb/images/animation_demo.gif
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | ### Android template
3 | # Built application files
4 | *.apk
5 | *.ap_
6 |
7 | # Files for the Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
30 | # Android Studio Navigation editor temp files
31 | .navigation/
32 | ### JetBrains template
33 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
34 |
35 | *.iml
36 |
37 | ## Directory-based project format:
38 | .idea/
39 | # if you remove the above rule, at least ignore the following:
40 |
41 | # User-specific stuff:
42 | # .idea/workspace.xml
43 | # .idea/tasks.xml
44 | # .idea/dictionaries
45 |
46 | # Sensitive or high-churn files:
47 | # .idea/dataSources.ids
48 | # .idea/dataSources.xml
49 | # .idea/sqlDataSources.xml
50 | # .idea/dynamic.xml
51 | # .idea/uiDesigner.xml
52 |
53 | # Gradle:
54 | # .idea/gradle.xml
55 | # .idea/libraries
56 |
57 | # Mongo Explorer plugin:
58 | # .idea/mongoSettings.xml
59 |
60 | ## File-based project format:
61 | *.ipr
62 | *.iws
63 |
64 | ## Plugin-specific files:
65 |
66 | # IntelliJ
67 | /out/
68 |
69 | # mpeltonen/sbt-idea plugin
70 | .idea_modules/
71 |
72 | # JIRA plugin
73 | atlassian-ide-plugin.xml
74 |
75 | # Crashlytics plugin (for Android Studio and IntelliJ)
76 | com_crashlytics_export_strings.xml
77 | crashlytics.properties
78 | crashlytics-build.properties
79 |
80 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 12
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | resourcePrefix "lav_"
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.2.0'
26 | }
27 |
28 | apply from: './gradle-mvn-push.gradle'
--------------------------------------------------------------------------------
/library/gradle-mvn-push.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | def isReleaseBuild() {
21 | return VERSION_NAME.contains("SNAPSHOT") == false
22 | }
23 |
24 | def getReleaseRepositoryUrl() {
25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
26 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
27 | }
28 |
29 | def getSnapshotRepositoryUrl() {
30 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
31 | : "https://oss.sonatype.org/content/repositories/snapshots/"
32 | }
33 |
34 | def getRepositoryUsername() {
35 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
36 | }
37 |
38 | def getRepositoryPassword() {
39 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
40 | }
41 |
42 | afterEvaluate { project ->
43 | uploadArchives {
44 | repositories {
45 | mavenDeployer {
46 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
47 |
48 | pom.groupId = GROUP
49 | pom.artifactId = POM_ARTIFACT_ID
50 | pom.version = VERSION_NAME
51 |
52 | repository(url: getReleaseRepositoryUrl()) {
53 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
54 | }
55 | snapshotRepository(url: getSnapshotRepositoryUrl()) {
56 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
57 | }
58 |
59 | pom.project {
60 | name POM_NAME
61 | packaging POM_PACKAGING
62 | description POM_DESCRIPTION
63 | url POM_URL
64 |
65 | scm {
66 | url POM_SCM_URL
67 | connection POM_SCM_CONNECTION
68 | developerConnection POM_SCM_DEV_CONNECTION
69 | }
70 |
71 | licenses {
72 | license {
73 | name POM_LICENCE_NAME
74 | url POM_LICENCE_URL
75 | distribution POM_LICENCE_DIST
76 | }
77 | }
78 |
79 | developers {
80 | developer {
81 | id POM_DEVELOPER_ID
82 | name POM_DEVELOPER_NAME
83 | }
84 | }
85 | }
86 | }
87 | }
88 | }
89 |
90 | signing {
91 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
92 | sign configurations.archives
93 | }
94 |
95 | task apklib(type: Zip){
96 | appendix = extension = 'apklib'
97 |
98 | from 'AndroidManifest.xml'
99 | into('res') {
100 | from 'res'
101 | }
102 | into('src') {
103 | from 'src'
104 | }
105 | }
106 |
107 |
108 | task androidJavadocs(type: Javadoc) {
109 | source = android.sourceSets.main.java.srcDirs
110 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
111 | options.links("http://docs.oracle.com/javase/7/docs/api/");
112 | options.linksOffline "http://d.android.com/reference","${android.sdkDirectory}/docs/reference"
113 | exclude '**/BuildConfig.java'
114 | exclude '**/R.java'
115 | failOnError = false
116 | }
117 |
118 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
119 | classifier = 'javadoc'
120 | from androidJavadocs.destinationDir
121 | }
122 |
123 | task androidSourcesJar(type: Jar) {
124 | classifier = 'sources'
125 | from android.sourceSets.main.java.sourceFiles
126 | }
127 |
128 | artifacts {
129 | archives androidSourcesJar
130 | archives androidJavadocsJar
131 | archives apklib
132 | }
133 | }
--------------------------------------------------------------------------------
/library/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_NAME=Android M Boot Animation View Library
2 | POM_ARTIFACT_ID=androidmanimation
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/cleveroad/androidmanimation/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/AnimationDialogFragment.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.os.Parcel;
8 | import android.os.Parcelable;
9 | import android.support.annotation.ColorInt;
10 | import android.support.annotation.NonNull;
11 | import android.support.annotation.Nullable;
12 | import android.support.v4.app.DialogFragment;
13 | import android.view.LayoutInflater;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 |
17 | /**
18 | * Dialog fragment with loading animation.
19 | */
20 | public class AnimationDialogFragment extends DialogFragment {
21 |
22 | private static final String EXTRA_BUILDER = "EXTRA_BUILDER";
23 | private LoadingAnimationView animationView;
24 |
25 | public AnimationDialogFragment() {
26 | setStyle(DialogFragment.STYLE_NO_TITLE, 0);
27 | }
28 |
29 | @SuppressLint("ValidFragment")
30 | private AnimationDialogFragment(Builder builder) {
31 | this();
32 | Bundle args = new Bundle();
33 | args.putParcelable(EXTRA_BUILDER, builder);
34 | setArguments(args);
35 | }
36 |
37 | @Nullable
38 | @Override
39 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
40 | return inflater.inflate(R.layout.lav_view_loading_animation, container, false);
41 | }
42 |
43 | @Override
44 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
45 | super.onViewCreated(view, savedInstanceState);
46 | animationView = (LoadingAnimationView) view.findViewById(R.id.animation);
47 | Bundle args = getArguments();
48 | if (args != null) {
49 | Builder builder = args.getParcelable(EXTRA_BUILDER);
50 | if (builder != null) {
51 | animationView.fromBuilder(builder);
52 | }
53 | }
54 | }
55 |
56 | @Override
57 | public void onResume() {
58 | super.onResume();
59 | animationView.startAnimation();
60 | }
61 |
62 | @Override
63 | public void onPause() {
64 | animationView.pauseAnimation();
65 | super.onPause();
66 | }
67 |
68 | @Override
69 | public void onDestroyView() {
70 | animationView.stopAnimation();
71 | super.onDestroyView();
72 | }
73 |
74 | /**
75 | * Builder class for dialog with loading animation.
76 | */
77 | public static final class Builder implements Parcelable {
78 |
79 | private Integer firstColor, secondColor, thirdColor, fourthColor;
80 | private Integer backgroundColor;
81 | private float speedCoefficient;
82 |
83 |
84 | /**
85 | * Set first color. Default value: red.
86 | * @param firstColor first color
87 | */
88 | public Builder setFirstColor(@ColorInt int firstColor) {
89 | this.firstColor = firstColor;
90 | return this;
91 | }
92 |
93 | /**
94 | * Set second color. Default value: green.
95 | * @param secondColor second color
96 | */
97 | public Builder setSecondColor(@ColorInt int secondColor) {
98 | this.secondColor = secondColor;
99 | return this;
100 | }
101 |
102 | /**
103 | * Set third color. Default value: blue.
104 | * @param thirdColor third color
105 | */
106 | public Builder setThirdColor(@ColorInt int thirdColor) {
107 | this.thirdColor = thirdColor;
108 | return this;
109 | }
110 |
111 | /**
112 | * Set fourth color. Default value: yellow.
113 | * @param fourthColor fourth color
114 | */
115 | public Builder setFourthColor(@ColorInt int fourthColor) {
116 | this.fourthColor = fourthColor;
117 | return this;
118 | }
119 |
120 | /**
121 | * Set background color. Default value: black.
122 | * @param backgroundColor background color
123 | */
124 | public Builder setBackgroundColor(@ColorInt int backgroundColor) {
125 | this.backgroundColor = backgroundColor;
126 | return this;
127 | }
128 |
129 | /**
130 | * Set speed coefficient. Default value: 1.
131 | * @param speedCoefficient speed coefficient in range [0..Integer.MAX_VALUE]
132 | */
133 | public Builder setSpeedCoefficient(float speedCoefficient) {
134 | this.speedCoefficient = speedCoefficient;
135 | return this;
136 | }
137 |
138 | int getFirstColor(@NonNull Context context) {
139 | if (firstColor == null)
140 | return ColorUtil.getColor(context, R.color.lav_google_red);
141 | return firstColor;
142 | }
143 |
144 | int getSecondColor(@NonNull Context context) {
145 | if (secondColor == null)
146 | return ColorUtil.getColor(context, R.color.lav_google_green);
147 | return secondColor;
148 | }
149 |
150 | int getThirdColor(@NonNull Context context) {
151 | if (thirdColor == null)
152 | return ColorUtil.getColor(context, R.color.lav_google_blue);
153 | return thirdColor;
154 | }
155 |
156 | int getFourthColor(@NonNull Context context) {
157 | if (fourthColor == null)
158 | return ColorUtil.getColor(context, R.color.lav_google_yellow);
159 | return fourthColor;
160 | }
161 |
162 | int getBackgroundColor() {
163 | if (backgroundColor == null)
164 | return Color.BLACK;
165 | return backgroundColor;
166 | }
167 |
168 | float getSpeedCoefficient() {
169 | return speedCoefficient;
170 | }
171 |
172 |
173 | /**
174 | * Create new dialog fragment with loading animation.
175 | * @return created dialog fragment.
176 | */
177 | public AnimationDialogFragment build() {
178 | if (speedCoefficient < 0) {
179 | throw new IllegalArgumentException("Speed coefficient must be positive.");
180 | }
181 | if (speedCoefficient == 0) {
182 | speedCoefficient = Constants.DEFAULT_SPEED_COEFFICIENT;
183 | }
184 | return new AnimationDialogFragment(this);
185 | }
186 |
187 | @Override
188 | public int describeContents() {
189 | return 0;
190 | }
191 |
192 | @Override
193 | public void writeToParcel(Parcel dest, int flags) {
194 | dest.writeValue(this.firstColor);
195 | dest.writeValue(this.secondColor);
196 | dest.writeValue(this.thirdColor);
197 | dest.writeValue(this.fourthColor);
198 | dest.writeValue(this.backgroundColor);
199 | dest.writeFloat(this.speedCoefficient);
200 | }
201 |
202 | public Builder() {
203 |
204 | }
205 |
206 | protected Builder(Parcel in) {
207 | this.firstColor = (Integer) in.readValue(Integer.class.getClassLoader());
208 | this.secondColor = (Integer) in.readValue(Integer.class.getClassLoader());
209 | this.thirdColor = (Integer) in.readValue(Integer.class.getClassLoader());
210 | this.fourthColor = (Integer) in.readValue(Integer.class.getClassLoader());
211 | this.backgroundColor = (Integer) in.readValue(Integer.class.getClassLoader());
212 | this.speedCoefficient = in.readFloat();
213 | }
214 |
215 | public static final Creator CREATOR = new Creator() {
216 | public Builder createFromParcel(Parcel source) {
217 | return new Builder(source);
218 | }
219 |
220 | public Builder[] newArray(int size) {
221 | return new Builder[size];
222 | }
223 | };
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/ColorUtil.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.content.Context;
4 | import android.os.Build;
5 | import android.support.annotation.NonNull;
6 |
7 | /**
8 | * Color utils class.
9 | */
10 | class ColorUtil {
11 |
12 | private ColorUtil() {
13 |
14 | }
15 |
16 | @SuppressWarnings("deprecation")
17 | public static int getColor(@NonNull Context context, int colorId) {
18 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
19 | return context.getColor(colorId);
20 | }
21 | return context.getResources().getColor(colorId);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/Constants.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | /**
4 | * Constants class.
5 | */
6 | class Constants {
7 |
8 | private Constants() {
9 | }
10 |
11 | public static final float DEFAULT_SPEED_COEFFICIENT = 1f;
12 |
13 | public static float SPEED_COEFFICIENT;
14 |
15 | public static final int TOTAL_DURATION = 4530;
16 |
17 | public static final int TOTAL_FRAMES = 151;
18 |
19 | public static final int MS_PER_FRAME = 30;
20 |
21 | public static final float FRAME_SPEED = 1f * MS_PER_FRAME / TOTAL_DURATION;
22 |
23 | public static final float FIRST_FRAME_FRACTION = 0;
24 |
25 | public static final float LAST_FRAME_FRACTION = TOTAL_FRAMES * FRAME_SPEED;
26 | }
27 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/DrawableObject.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.RectF;
5 | import android.support.annotation.NonNull;
6 |
7 | /**
8 | * Interface of drawable shape
9 | */
10 | interface DrawableObject {
11 |
12 | void update(@NonNull RectF bounds, float dt);
13 |
14 | void draw(@NonNull Canvas canvas);
15 | }
16 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/DrawableObjectImpl.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.graphics.Paint;
4 | import android.graphics.RectF;
5 | import android.support.annotation.NonNull;
6 |
7 | /**
8 | * Implementation of {@link DrawableObject}.
9 | */
10 | abstract class DrawableObjectImpl implements DrawableObject, Resetable {
11 |
12 | private final Paint paint;
13 | private final RectF bounds;
14 |
15 | public DrawableObjectImpl(Paint paint) {
16 | this.paint = paint;
17 | this.bounds = new RectF();
18 | }
19 |
20 | @Override
21 | public final void update(@NonNull RectF bounds, float dt) {
22 | float spacing = (1 - getSizeFraction()) / 2f;
23 | float l = bounds.left + spacing * bounds.width();
24 | float t = bounds.top + spacing * bounds.height();
25 | float r = l + getSizeFraction() * bounds.width();
26 | float b = t + getSizeFraction() * bounds.height();
27 | getBounds().set(l, t, r, b);
28 | updateImpl(bounds, dt);
29 | }
30 |
31 | protected abstract float getSizeFraction();
32 |
33 | protected abstract void updateImpl(@NonNull RectF bounds, float ddt);
34 |
35 | public Paint getPaint() {
36 | return paint;
37 | }
38 |
39 | public RectF getBounds() {
40 | return bounds;
41 | }
42 |
43 | @Override
44 | public void reset() {
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/DrawableUtils.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | /**
4 | * Helpful utils class.
5 | */
6 | class DrawableUtils {
7 |
8 | private DrawableUtils() {}
9 |
10 | /**
11 | * Trapeze function.
12 | * @param t current value
13 | * @param a value at aT point of time
14 | * @param aT first point
15 | * @param b value at bT point of time
16 | * @param bT second point
17 | * @param c value at cT point of time
18 | * @param cT third point
19 | * @param d value at dT point of time
20 | * @param dT forth point
21 | * @return calculated value
22 | */
23 | public static float trapeze(float t, float a, float aT, float b, float bT, float c, float cT, float d, float dT) {
24 | if (t < aT) {
25 | return a;
26 | }
27 | if (t >= aT && t < bT) {
28 | float norm = normalize(t, aT, bT);
29 | return a + norm * (b - a);
30 | }
31 | if (t >= bT && t < cT) {
32 | float norm = normalize(t, bT, cT);
33 | return b + norm * (c - b);
34 | }
35 | if (t >= cT && t <= dT) {
36 | float norm = normalize(t, cT, dT);
37 | return c + norm * (d - c);
38 | }
39 | return d;
40 | }
41 |
42 | /**
43 | * Normalize value between minimum and maximum.
44 | * @param val value
45 | * @param minVal minimum value
46 | * @param maxVal maximum value
47 | * @return normalized value in range 0..1
48 | * @throws IllegalArgumentException if value is out of range [minVal, maxVal]
49 | */
50 | public static float normalize(float val, float minVal, float maxVal) {
51 | if (val < minVal || val > maxVal)
52 | throw new IllegalArgumentException("Value must be between min and max values. [val, min, max]: [" + val + "," + minVal + ", " + maxVal + "]");
53 | return (val - minVal) / (maxVal - minVal);
54 | }
55 |
56 | /**
57 | * Quadratic Bezier curve.
58 | * @param t time
59 | * @param p0 start point
60 | * @param p1 control point
61 | * @param p2 end point
62 | * @return point on Bezier curve at some time t
63 | */
64 | public static float quad(float t, float p0, float p1, float p2) {
65 | return (float) (p0 * Math.pow(1 - t, 2) + p1 * 2 * t * (1 - t) + p2 * t * t);
66 | }
67 |
68 | /**
69 | * Rotate point P around center point C.
70 | * @param pX x coordinate of point P
71 | * @param pY y coordinate of point P
72 | * @param cX x coordinate of point C
73 | * @param cY y coordinate of point C
74 | * @param angleInDegrees rotation angle in degrees
75 | * @return new x coordinate
76 | */
77 | public static float rotateX(float pX, float pY, float cX, float cY, float angleInDegrees) {
78 | double angle = Math.toRadians(angleInDegrees);
79 | return (float) (Math.cos(angle) * (pX - cX) - Math.sin(angle) * (pY - cY) + cX);
80 | }
81 |
82 | /**
83 | * Rotate point P around center point C.
84 | * @param pX x coordinate of point P
85 | * @param pY y coordinate of point P
86 | * @param cX x coordinate of point C
87 | * @param cY y coordinate of point C
88 | * @param angleInDegrees rotation angle in degrees
89 | * @return new y coordinate
90 | */
91 | public static float rotateY(float pX, float pY, float cX, float cY, float angleInDegrees) {
92 | double angle = Math.toRadians(angleInDegrees);
93 | return (float) (Math.sin(angle) * (pX - cX) + Math.cos(angle) * (pY - cY) + cY);
94 | }
95 |
96 | /**
97 | * Checks if value belongs to range [start, end]
98 | * @param value value
99 | * @param start start of range
100 | * @param end end of range
101 | * @return true if value belogs to range, false otherwise
102 | */
103 | public static boolean between(float value, float start, float end) {
104 | if (start > end) {
105 | float tmp = start;
106 | start = end;
107 | end = tmp;
108 | }
109 | return value >= start && value <= end;
110 | }
111 |
112 | /**
113 | * Enlarge value from startValue to endValue
114 | * @param startValue start size
115 | * @param endValue end size
116 | * @param time time of animation
117 | * @return new size value
118 | */
119 | public static float enlarge(float startValue, float endValue, float time) {
120 | if (startValue > endValue)
121 | throw new IllegalArgumentException("Start size can't be larger than end size.");
122 | return startValue + (endValue - startValue) * time;
123 | }
124 |
125 | /**
126 | * Reduce value from startValue to endValue
127 | * @param startValue start size
128 | * @param endValue end size
129 | * @param time time of animation
130 | * @return new size value
131 | */
132 | public static float reduce(float startValue, float endValue, float time) {
133 | if (startValue < endValue)
134 | throw new IllegalArgumentException("End size can't be larger than start size.");
135 | return endValue + (startValue - endValue) * (1 - time);
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/FirstLayer.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.graphics.RectF;
6 | import android.support.annotation.NonNull;
7 | import android.view.animation.AccelerateDecelerateInterpolator;
8 | import android.view.animation.Interpolator;
9 |
10 | /**
11 | * First layer of animation.
12 | */
13 | class FirstLayer extends Layer {
14 |
15 |
16 | private final DrawableObject[] objects;
17 |
18 | public FirstLayer(Paint bluePaint, Paint greenPaint, Paint yellowPaint, Paint bgPaint) {
19 | objects = new DrawableObject[4];
20 | objects[0] = new YellowCircle(yellowPaint, bgPaint);
21 | objects[1] = new BlueCircle(bluePaint);
22 | objects[2] = new BlueArc(bluePaint);
23 | objects[3] = new GreenCircles(greenPaint);
24 | }
25 |
26 | @Override
27 | public void update(@NonNull RectF bounds, float dt) {
28 | for (DrawableObject object : objects) {
29 | object.update(bounds, dt);
30 | }
31 | }
32 |
33 | @Override
34 | public void draw(@NonNull Canvas canvas) {
35 | for (DrawableObject object : objects) {
36 | object.draw(canvas);
37 | }
38 | }
39 |
40 | @Override
41 | public void reset() {
42 | for (DrawableObject object : objects) {
43 | if (object instanceof Resetable) {
44 | ((Resetable) object).reset();
45 | }
46 | }
47 | }
48 |
49 | private static final class GreenCircles extends DrawableObjectImpl {
50 |
51 | private static final float FRACTION_START = Constants.FIRST_FRAME_FRACTION;
52 | private static final float FRACTION_END = 50 * Constants.FRAME_SPEED;
53 |
54 | private static final float SIZE_FRACTION = 0.75f;
55 | private static final float START_ANGLE = 135;
56 | private static final float ENG_ANGLE = 245;
57 | private static final int CIRCLES_COUNT = 14;
58 | private static final int VISIBLE_CIRCLES = 6;
59 | private static final float ANGLE_STEP = 360f / CIRCLES_COUNT;
60 | private final float[][] circlePositions;
61 | private final float[] sizes;
62 | private final float[] coefficients = new float[4];
63 | private boolean draw;
64 |
65 | public GreenCircles(Paint paint) {
66 | super(paint);
67 | circlePositions = new float[CIRCLES_COUNT][2];
68 | sizes = new float[CIRCLES_COUNT];
69 | }
70 |
71 | @Override
72 | protected float getSizeFraction() {
73 | return SIZE_FRACTION;
74 | }
75 |
76 | @Override
77 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
78 | draw = DrawableUtils.between(ddt, FRACTION_START, FRACTION_END);
79 | if (!draw) {
80 | return;
81 | }
82 | int i = 0;
83 | float t = DrawableUtils.normalize(ddt, FRACTION_START, FRACTION_END);
84 | float angle = START_ANGLE + (ENG_ANGLE - START_ANGLE) * t;
85 | for (float step = 0; step < 360 + ANGLE_STEP / 2; step += ANGLE_STEP) {
86 | float cX = getBounds().centerX();
87 | float cY = getBounds().centerY();
88 | float pX = cX;
89 | float pY = getBounds().top;
90 | float x = DrawableUtils.rotateX(pX, pY, cX, cY, step + angle);
91 | float y = DrawableUtils.rotateY(pX, pY, cX, cY, step + angle);
92 | circlePositions[i][0] = x;
93 | circlePositions[i][1] = y;
94 | i++;
95 | if (i >= CIRCLES_COUNT)
96 | break;
97 | }
98 | float step = 1f / (VISIBLE_CIRCLES + 1);
99 | float d = 1f * VISIBLE_CIRCLES / (CIRCLES_COUNT + VISIBLE_CIRCLES);
100 | for (i = 0; i < CIRCLES_COUNT; i++) {
101 | int index = i;
102 | if (index >= CIRCLES_COUNT) {
103 | index %= CIRCLES_COUNT;
104 | }
105 | getCoefficients(0, i, step, t, d, coefficients);
106 | float k = DrawableUtils.trapeze(t, 0, coefficients[0], 1, coefficients[1], 1, coefficients[2], 0, coefficients[3]);
107 | sizes[index] = k;
108 | }
109 | }
110 |
111 | private void getCoefficients(float startT, int i, float step, float t, float d, float[] array) {
112 | float aT = startT + step * i * d;
113 | float bT = aT + 0.25f * d;
114 | float cT = bT + 0.5f * d;
115 | float dT = cT + 0.25f * d;
116 | array[0] = aT;
117 | array[1] = bT;
118 | array[2] = cT;
119 | array[3] = dT;
120 | }
121 |
122 | @Override
123 | public void draw(@NonNull Canvas canvas) {
124 | for (int i = 0; i < CIRCLES_COUNT; i++) {
125 | if (sizes[i] > 0) {
126 | canvas.drawCircle(circlePositions[i][0], circlePositions[i][1], getBounds().width() * 0.07f * sizes[i], getPaint());
127 | }
128 | }
129 | }
130 | }
131 |
132 | private static final class BlueArc extends DrawableObjectImpl {
133 |
134 | private static final float FRACTION_START = 77 * Constants.FRAME_SPEED;
135 | private static final float FRACTION_END = 132 * Constants.FRAME_SPEED;
136 |
137 |
138 | private static final float SIZE_FRACTION = 0.55f;
139 | private static final float START_ANGLE = 135f;
140 | private static final float END_ANGLE = 1260f;
141 | private static final float START_SWEEP_ANGLE = 0f;
142 | private static final float END_SWEEP_ANGLE = 180f;
143 | private float startAngle = START_ANGLE;
144 | private float sweepAngle;
145 | private boolean draw;
146 | private Interpolator accelerate = new AccelerateDecelerateInterpolator();
147 | private Interpolator decelerate = new AccelerateDecelerateInterpolator();
148 |
149 | public BlueArc(Paint paint) {
150 | super(new Paint(paint));
151 | getPaint().setStyle(Paint.Style.STROKE);
152 | }
153 |
154 | @Override
155 | protected float getSizeFraction() {
156 | return SIZE_FRACTION;
157 | }
158 |
159 | @Override
160 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
161 | getPaint().setStrokeWidth(bounds.width() * 0.08f);
162 | draw = DrawableUtils.between(ddt, FRACTION_START, FRACTION_END);
163 | if (!draw) {
164 | startAngle = START_ANGLE;
165 | return;
166 | }
167 | float time = DrawableUtils.normalize(ddt, FRACTION_START, FRACTION_END);
168 | startAngle = START_ANGLE + accelerate.getInterpolation(time) * END_ANGLE;
169 | sweepAngle = DrawableUtils.trapeze(decelerate.getInterpolation(time), START_SWEEP_ANGLE, 0, END_SWEEP_ANGLE, 0.25f, END_SWEEP_ANGLE, 0.75f, START_SWEEP_ANGLE, 1);
170 | }
171 |
172 | @Override
173 | public void draw(@NonNull Canvas canvas) {
174 | if (draw) {
175 | canvas.drawArc(getBounds(), startAngle, sweepAngle, false, getPaint());
176 | }
177 | }
178 | }
179 |
180 | private static final class YellowCircle extends DrawableObjectImpl {
181 |
182 | private static final float BLACK_REDUCE_FRACTION_START = 50 * Constants.FRAME_SPEED;
183 | private static final float BLACK_REDUCE_FRACTION_END = 64 * Constants.FRAME_SPEED;
184 |
185 | private static final float YELLOW_REDUCE_FRACTION_START = 64 * Constants.FRAME_SPEED;
186 | private static final float YELLOW_REDUCE_FRACTION_END = 80 * Constants.FRAME_SPEED;
187 |
188 | private static final float YELLOW_INVISIBLE_FRACTION_START = 141 * Constants.FRAME_SPEED;
189 |
190 | private static final float SIZE_FRACTION = 0.75f;
191 | private static final float ZERO_SIZE = 0;
192 | private static final float LARGE_SIZE = 1;
193 | private static final float BLACK_INVISIBLE_SIZE = BlueCircle.SIZE_FRACTION / BlueCircle.LARGE_SIZE;
194 | private static final float SMALL_SIZE = 0.3f;
195 |
196 | private float yellowSize;
197 | private float blackSize;
198 | private Paint bgPaint;
199 |
200 |
201 | public YellowCircle(Paint paint, Paint bgPaint) {
202 | super(paint);
203 | this.bgPaint = bgPaint;
204 | }
205 |
206 | @Override
207 | protected float getSizeFraction() {
208 | return SIZE_FRACTION;
209 | }
210 |
211 | @Override
212 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
213 | yellowSize = computeYellowSizeFraction(ddt) * getBounds().width();
214 | blackSize = computeBlackSizeFraction(ddt) * getBounds().width();
215 | }
216 |
217 | private float computeBlackSizeFraction(float ddt) {
218 | if (DrawableUtils.between(ddt, BLACK_REDUCE_FRACTION_START, BLACK_REDUCE_FRACTION_END)) {
219 | float t = DrawableUtils.normalize(ddt, BLACK_REDUCE_FRACTION_START, BLACK_REDUCE_FRACTION_END);
220 | return DrawableUtils.reduce(LARGE_SIZE * 0.9f, BLACK_INVISIBLE_SIZE, t);
221 | }
222 | return ZERO_SIZE;
223 | }
224 |
225 | private float computeYellowSizeFraction(float ddt) {
226 | if (DrawableUtils.between(ddt, BLACK_REDUCE_FRACTION_START, BLACK_REDUCE_FRACTION_END)) {
227 | float t = DrawableUtils.normalize(ddt, BLACK_REDUCE_FRACTION_START, BLACK_REDUCE_FRACTION_END);
228 | return DrawableUtils.reduce(LARGE_SIZE, BLACK_INVISIBLE_SIZE * 1.4f, t);
229 | }
230 | if (DrawableUtils.between(ddt, BLACK_REDUCE_FRACTION_END, YELLOW_REDUCE_FRACTION_START)) {
231 | return BLACK_INVISIBLE_SIZE * 1.4f;
232 | }
233 | if (DrawableUtils.between(ddt, YELLOW_REDUCE_FRACTION_START, YELLOW_REDUCE_FRACTION_END)) {
234 | float t = DrawableUtils.normalize(ddt, YELLOW_REDUCE_FRACTION_START, YELLOW_REDUCE_FRACTION_END);
235 | return DrawableUtils.reduce(BLACK_INVISIBLE_SIZE * 1.4f, SMALL_SIZE, t);
236 | }
237 | if (DrawableUtils.between(ddt, YELLOW_REDUCE_FRACTION_END, YELLOW_INVISIBLE_FRACTION_START)) {
238 | return SMALL_SIZE;
239 | }
240 | return ZERO_SIZE;
241 | }
242 |
243 | @Override
244 | public void draw(@NonNull Canvas canvas) {
245 | if (yellowSize > 0) {
246 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), yellowSize / 2f, getPaint());
247 | }
248 | if (blackSize > 0) {
249 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), blackSize / 2f, bgPaint);
250 | }
251 | }
252 | }
253 |
254 | private static final class BlueCircle extends DrawableObjectImpl {
255 |
256 | private static final float SMALL_REDUCE_FRACTION_START = Constants.FIRST_FRAME_FRACTION;
257 | private static final float SMALL_REDUCE_FRACTION_END = 12 * Constants.FRAME_SPEED;
258 |
259 | private static final float SMALL_ENLARGE_FRACTION_START = 44 * Constants.FRAME_SPEED;
260 | private static final float SMALL_ENLARGE_FRACTION_END = 56 * Constants.FRAME_SPEED;
261 |
262 | private static final float LARGE_REDUCE_FRACTION_START = 58 * Constants.FRAME_SPEED;
263 | private static final float LARGE_REDUCE_FRACTION_END = 80 * Constants.FRAME_SPEED;
264 |
265 | private static final float LARGE_ENLARGE_FRACTION_START = 133 * Constants.FRAME_SPEED;
266 | private static final float LARGE_ENLARGE_FRACTION_END = Constants.LAST_FRAME_FRACTION;
267 |
268 |
269 | private static final float SIZE_FRACTION = 0.6f;
270 | private static final float DEFAULT_SIZE = 0.8f;
271 | private static final float ZERO_SIZE = 0f;
272 | private static final float LARGE_SIZE = 1f;
273 |
274 | private float diameter;
275 |
276 | public BlueCircle(Paint paint) {
277 | super(paint);
278 | }
279 |
280 | @Override
281 | protected float getSizeFraction() {
282 | return SIZE_FRACTION;
283 | }
284 |
285 | @Override
286 | public void updateImpl(@NonNull RectF bounds, float ddt) {
287 | diameter = computeSizeFraction(ddt) * getBounds().width();
288 | }
289 |
290 | @Override
291 | public void draw(@NonNull Canvas canvas) {
292 | if (diameter > 0) {
293 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), diameter / 2f, getPaint());
294 | }
295 | }
296 |
297 | private float computeSizeFraction(float ddt) {
298 | if (DrawableUtils.between(ddt, SMALL_REDUCE_FRACTION_START, SMALL_REDUCE_FRACTION_END)) {
299 | float t = DrawableUtils.normalize(ddt, SMALL_REDUCE_FRACTION_START, SMALL_REDUCE_FRACTION_END);
300 | return DrawableUtils.reduce(LARGE_SIZE, DEFAULT_SIZE, t);
301 | }
302 | if (DrawableUtils.between(ddt, SMALL_REDUCE_FRACTION_END, SMALL_ENLARGE_FRACTION_START)) {
303 | return DEFAULT_SIZE;
304 | }
305 | if (DrawableUtils.between(ddt, SMALL_ENLARGE_FRACTION_START, SMALL_ENLARGE_FRACTION_END)) {
306 | float t = DrawableUtils.normalize(ddt, SMALL_ENLARGE_FRACTION_START, SMALL_ENLARGE_FRACTION_END);
307 | return DrawableUtils.enlarge(DEFAULT_SIZE, LARGE_SIZE, t);
308 | }
309 | if (DrawableUtils.between(ddt, SMALL_ENLARGE_FRACTION_END, LARGE_REDUCE_FRACTION_START)) {
310 | return LARGE_SIZE;
311 | }
312 | if (DrawableUtils.between(ddt, LARGE_REDUCE_FRACTION_START, LARGE_REDUCE_FRACTION_END)) {
313 | float t = DrawableUtils.normalize(ddt, LARGE_REDUCE_FRACTION_START, LARGE_REDUCE_FRACTION_END);
314 | return DrawableUtils.reduce(LARGE_SIZE, ZERO_SIZE, t);
315 | }
316 | if (DrawableUtils.between(ddt, LARGE_REDUCE_FRACTION_END, LARGE_ENLARGE_FRACTION_START)) {
317 | return ZERO_SIZE;
318 | }
319 | if (DrawableUtils.between(ddt, LARGE_ENLARGE_FRACTION_START, LARGE_ENLARGE_FRACTION_END)) {
320 | float t = DrawableUtils.normalize(ddt, LARGE_ENLARGE_FRACTION_START, LARGE_ENLARGE_FRACTION_END);
321 | return DrawableUtils.enlarge(ZERO_SIZE, LARGE_SIZE, t);
322 | }
323 |
324 | // default value
325 | return DEFAULT_SIZE;
326 | }
327 | }
328 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/FourthLayer.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.graphics.RectF;
6 | import android.support.annotation.NonNull;
7 | import android.view.animation.AccelerateDecelerateInterpolator;
8 | import android.view.animation.Interpolator;
9 |
10 | /**
11 | * Fourth layer of animation.
12 | */
13 | class FourthLayer extends Layer {
14 |
15 | private final DrawableObject[] objects;
16 |
17 | public FourthLayer(Paint redPaint, Paint greenPaint, Paint bluePaint, Paint yellowPaint, Paint bgPaint) {
18 | objects = new DrawableObject[8];
19 | objects[0] = new BlueArc(bluePaint);
20 | objects[1] = new YellowArc(yellowPaint);
21 | objects[2] = new GreenCircle(greenPaint, bgPaint);
22 | objects[3] = new YellowCircle(yellowPaint); // first yellow circle
23 | objects[4] = new BlueCircle(bluePaint);
24 | objects[5] = new RedCircle(redPaint);
25 | objects[6] = new YellowCircle(yellowPaint, true); // second yellow circle
26 | objects[7] = new BlackCircle(bgPaint);
27 | }
28 |
29 | @Override
30 | public void update(@NonNull RectF bounds, float dt) {
31 | for (DrawableObject object : objects) {
32 | object.update(bounds, dt);
33 | }
34 | }
35 |
36 | @Override
37 | public void draw(@NonNull Canvas canvas) {
38 | for (DrawableObject object : objects) {
39 | object.draw(canvas);
40 | }
41 | }
42 |
43 | @Override
44 | public void reset() {
45 | for (DrawableObject object : objects) {
46 | if (object instanceof Resetable) {
47 | ((Resetable) object).reset();
48 | }
49 | }
50 | }
51 |
52 | private static final class RedCircle extends DrawableObjectImpl {
53 | // TIMING
54 | private static final float IDLE_1_FRACTION_START = 0f;
55 | private static final float IDLE_1_FRACTION_END = 140 * Constants.FRAME_SPEED;
56 |
57 | private static final float FRACTION_ENLARGING_START = 140 * Constants.FRAME_SPEED;
58 | private static final float FRACTION_ENLARGING_END = 146 * Constants.FRAME_SPEED;
59 |
60 | private static final float IDLE_2_FRACTION_START = 146 * Constants.FRAME_SPEED;
61 | private static final float IDLE_2_FRACTION_END = 149 * Constants.FRAME_SPEED;
62 |
63 | // DIMENSIONS
64 | private static final float SIZE_FRACTION_75 = 0.75f;
65 | private static final float SIZE_FRACTION_0 = 0f;
66 |
67 | private float width;
68 |
69 | public RedCircle(Paint paint) {
70 | super(paint);
71 | }
72 |
73 | @Override
74 | protected float getSizeFraction() {
75 | return 1f;
76 | }
77 |
78 | @Override
79 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
80 | width = getWidthFraction(ddt) * getBounds().width();
81 | }
82 |
83 | private float getWidthFraction(float ddt) {
84 | float time;
85 | if (DrawableUtils.between(ddt, IDLE_1_FRACTION_START, IDLE_1_FRACTION_END)) {
86 | return SIZE_FRACTION_0;
87 | }
88 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_START, FRACTION_ENLARGING_END)) {
89 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_START, FRACTION_ENLARGING_END);
90 | return DrawableUtils.enlarge(SIZE_FRACTION_0, SIZE_FRACTION_75, time);
91 | }
92 | if (DrawableUtils.between(ddt, IDLE_2_FRACTION_START, IDLE_2_FRACTION_END)) {
93 | return SIZE_FRACTION_75;
94 | }
95 | return SIZE_FRACTION_75;
96 | }
97 |
98 | @Override
99 | public void draw(@NonNull Canvas canvas) {
100 | if (width > 0) {
101 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), width / 2f, getPaint());
102 | }
103 | }
104 | }
105 |
106 | private static final class BlueCircle extends DrawableObjectImpl {
107 | // TIMING
108 | private static final float IDLE_1_FRACTION_START = 0f;
109 | private static final float IDLE_1_FRACTION_END = 137 * Constants.FRAME_SPEED;
110 |
111 | private static final float FRACTION_ENLARGING_START = 137 * Constants.FRAME_SPEED;
112 | private static final float FRACTION_ENLARGING_END = 143 * Constants.FRAME_SPEED;
113 |
114 | private static final float IDLE_2_FRACTION_START = 143 * Constants.FRAME_SPEED;
115 | private static final float IDLE_2_FRACTION_END = 146 * Constants.FRAME_SPEED;
116 |
117 | // DIMENSIONS
118 | private static final float SIZE_FRACTION_75 = 0.75f;
119 | private static final float SIZE_FRACTION_0 = 0f;
120 |
121 | private float width;
122 |
123 | public BlueCircle(Paint paint) {
124 | super(paint);
125 | }
126 |
127 | @Override
128 | protected float getSizeFraction() {
129 | return 1.0f;
130 | }
131 |
132 | @Override
133 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
134 | width = getBounds().width() * getWidthFraction(ddt);
135 | }
136 |
137 | private float getWidthFraction(float ddt) {
138 | float time;
139 | if (DrawableUtils.between(ddt, IDLE_1_FRACTION_START, IDLE_1_FRACTION_END)) {
140 | return SIZE_FRACTION_0;
141 | }
142 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_START, FRACTION_ENLARGING_END)) {
143 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_START, FRACTION_ENLARGING_END);
144 | return DrawableUtils.enlarge(SIZE_FRACTION_0, SIZE_FRACTION_75, time);
145 | }
146 | if (DrawableUtils.between(ddt, IDLE_2_FRACTION_START, IDLE_2_FRACTION_END)) {
147 | return SIZE_FRACTION_75;
148 | }
149 | return SIZE_FRACTION_75;
150 | }
151 |
152 | @Override
153 | public void draw(@NonNull Canvas canvas) {
154 | if (width > 0) {
155 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), width / 2f, getPaint());
156 | }
157 | }
158 | }
159 |
160 | private static final class YellowCircle extends DrawableObjectImpl {
161 | // TIMING FOR FIRST YELLOW CIRCLE
162 | private static final float IDLE_FRACTION_1_START = 0f;
163 | private static final float IDLE_FRACTION_1_END = 131 * Constants.FRAME_SPEED;
164 |
165 | private static final float FRACTION_ENLARGING_1_START = 131 * Constants.FRAME_SPEED;
166 | private static final float FRACTION_ENLARGING_1_END = 139 * Constants.FRAME_SPEED;
167 |
168 | private static final float IDLE_FRACTION_2_START = 139 * Constants.FRAME_SPEED;
169 | private static final float IDLE_FRACTION_2_END = 143 * Constants.FRAME_SPEED;
170 |
171 | private static final float FRACTION_ENLARGING_2_START = 143 * Constants.FRAME_SPEED;
172 | private static final float FRACTION_ENLARGING_2_END = 149 * Constants.FRAME_SPEED;
173 |
174 | // DIMENSIONS
175 | private static final float SIZE_FRACTION_75 = 0.75f;
176 | private static final float SIZE_FRACTION_0 = 0f;
177 |
178 | private float width;
179 | private boolean isSecondCircle;
180 |
181 | public YellowCircle(Paint paint) {
182 | super(paint);
183 | }
184 |
185 | public YellowCircle(Paint paint, boolean isSecondCircle) {
186 | super(paint);
187 | this.isSecondCircle = isSecondCircle;
188 | }
189 |
190 | @Override
191 | protected float getSizeFraction() {
192 | return 1f;
193 | }
194 |
195 | @Override
196 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
197 | width = getBounds().width() * (isSecondCircle ? getWidthFractionSecondCircle(ddt) : getWidthFractionFirstCircle(ddt));
198 | }
199 |
200 | private float getWidthFractionFirstCircle(float ddt) {
201 | float time;
202 | if (DrawableUtils.between(ddt, IDLE_FRACTION_1_START, IDLE_FRACTION_1_END)) {
203 | return SIZE_FRACTION_0;
204 | }
205 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_1_START, FRACTION_ENLARGING_1_END)) {
206 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_1_START, FRACTION_ENLARGING_1_END);
207 | return DrawableUtils.enlarge(SIZE_FRACTION_0, SIZE_FRACTION_75, time);
208 | }
209 | if (DrawableUtils.between(ddt, IDLE_FRACTION_2_START, IDLE_FRACTION_2_END)) {
210 | return SIZE_FRACTION_75;
211 | }
212 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_2_START, FRACTION_ENLARGING_2_END)) {
213 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_2_START, FRACTION_ENLARGING_2_END);
214 | return DrawableUtils.enlarge(SIZE_FRACTION_0, SIZE_FRACTION_75, time);
215 | }
216 | return SIZE_FRACTION_75;
217 | }
218 |
219 | private float getWidthFractionSecondCircle(float ddt) {
220 | float time;
221 | if (DrawableUtils.between(ddt, IDLE_FRACTION_1_START, IDLE_FRACTION_2_END)) {
222 | return SIZE_FRACTION_0;
223 | }
224 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_2_START, FRACTION_ENLARGING_2_END)) {
225 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_2_START, FRACTION_ENLARGING_2_END);
226 | return DrawableUtils.enlarge(SIZE_FRACTION_0, SIZE_FRACTION_75, time);
227 | }
228 | return SIZE_FRACTION_75;
229 | }
230 |
231 | @Override
232 | public void draw(@NonNull Canvas canvas) {
233 | if (width > 0) {
234 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), width / 2f, getPaint());
235 | }
236 | }
237 | }
238 |
239 | private static final class BlackCircle extends DrawableObjectImpl {
240 | // TIMING
241 | private static final float IDLE_FRACTION_1_START = 0f;
242 | private static final float IDLE_FRACTION_1_END = 37 * Constants.FRAME_SPEED;
243 |
244 | private static final float FRACTION_ENLARGING_1_START = 37 * Constants.FRAME_SPEED;
245 | private static final float FRACTION_ENLARGING_1_END = 51 * Constants.FRAME_SPEED;
246 |
247 | private static final float IDLE_FRACTION_2_START = 51 * Constants.FRAME_SPEED;
248 | private static final float IDLE_FRACTION_2_END = 79 * Constants.FRAME_SPEED;
249 |
250 | private static final float FRACTION_REDUCING_1_START = 79 * Constants.FRAME_SPEED;
251 | private static final float FRACTION_REDUCING_1_END = 86 * Constants.FRAME_SPEED;
252 |
253 | private static final float IDLE_FRACTION_3_START = 86 * Constants.FRAME_SPEED;
254 | private static final float IDLE_FRACTION_3_END = 116 * Constants.FRAME_SPEED;
255 |
256 | private static final float FRACTION_ENLARGING_2_START = 116 * Constants.FRAME_SPEED;
257 | private static final float FRACTION_ENLARGING_2_END = 130 * Constants.FRAME_SPEED;
258 |
259 | // DIMENSIONS
260 | private static final float SIZE_FRACTION_25 = 0.25f;
261 | private static final float SIZE_FRACTION_20 = 0.2f;
262 | private static final float SIZE_FRACTION_0 = 0f;
263 |
264 |
265 | private float width;
266 |
267 | public BlackCircle(Paint paint) {
268 | super(paint);
269 | }
270 |
271 | @Override
272 | protected float getSizeFraction() {
273 | return 1.0f;
274 | }
275 |
276 | @Override
277 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
278 | width = getBounds().width() * getWidthFraction(ddt);
279 | }
280 |
281 | private float getWidthFraction(float ddt) {
282 | float time;
283 | if (DrawableUtils.between(ddt, IDLE_FRACTION_1_START, IDLE_FRACTION_1_END)) {
284 | return SIZE_FRACTION_0;
285 | }
286 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_1_START, FRACTION_ENLARGING_1_END)) {
287 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_1_START, FRACTION_ENLARGING_1_END);
288 | return DrawableUtils.enlarge(SIZE_FRACTION_0, SIZE_FRACTION_20, time);
289 | }
290 | if (DrawableUtils.between(ddt, IDLE_FRACTION_2_START, IDLE_FRACTION_2_END)) {
291 | return SIZE_FRACTION_20;
292 | }
293 | if (DrawableUtils.between(ddt, FRACTION_REDUCING_1_START, FRACTION_REDUCING_1_END)) {
294 | time = DrawableUtils.normalize(ddt, FRACTION_REDUCING_1_START, FRACTION_REDUCING_1_END);
295 | return DrawableUtils.reduce(SIZE_FRACTION_20, SIZE_FRACTION_0, time);
296 | }
297 | if (DrawableUtils.between(ddt, IDLE_FRACTION_3_START, IDLE_FRACTION_3_END)) {
298 | return SIZE_FRACTION_0;
299 | }
300 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_2_START, FRACTION_ENLARGING_2_END)) {
301 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_2_START, FRACTION_ENLARGING_2_END);
302 | return DrawableUtils.enlarge(SIZE_FRACTION_0, SIZE_FRACTION_25, time);
303 | }
304 | return SIZE_FRACTION_25;
305 | }
306 |
307 | @Override
308 | public void draw(@NonNull Canvas canvas) {
309 | if (width > 0) {
310 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), width / 2f, getPaint());
311 | }
312 | }
313 | }
314 |
315 | private static final class GreenCircle extends DrawableObjectImpl {
316 | // TIMING
317 | private static final float FRACTION_ENLARGING_1_START = 0f;
318 | private static final float FRACTION_ENLARGING_1_END = 20 * Constants.FRAME_SPEED;
319 |
320 | private static final float IDLE_FRACTION_1_START = 20 * Constants.FRAME_SPEED;
321 | private static final float IDLE_FRACTION_1_END = 92 * Constants.FRAME_SPEED;
322 |
323 | private static final float FRACTION_REDUCING_1_START = 92 * Constants.FRAME_SPEED;
324 | private static final float FRACTION_REDUCING_1_END = 103 * Constants.FRAME_SPEED;
325 |
326 | private static final float FRACTION_ENLARGING_2_START = 103 * Constants.FRAME_SPEED;
327 | private static final float FRACTION_ENLARGING_2_END = 129 * Constants.FRAME_SPEED;
328 |
329 | private static final float IDLE_FRACTION_2_START = 129 * Constants.FRAME_SPEED;
330 | private static final float IDLE_FRACTION_2_END = 139 * Constants.FRAME_SPEED;
331 |
332 | private static final float IDLE_BG_1_START = 0f;
333 | private static final float IDLE_BG_1_END = 12 * Constants.FRAME_SPEED;
334 |
335 | // DIMENSIONS FACTORS
336 | private static final float SIZE_FRACTION_75 = 0.75f;
337 | private static final float SIZE_FRACTION_45 = 0.45f;
338 | private static final float SIZE_FRACTION_25 = 0.25f;
339 | private static final float SIZE_FRACTION_0 = 0f;
340 |
341 | private float width;
342 | private float bgWidth;
343 | private Paint bgPaint;
344 |
345 | public GreenCircle(Paint paint, Paint bgPaint) {
346 | super(paint);
347 | this.bgPaint = bgPaint;
348 | }
349 |
350 | @Override
351 | protected float getSizeFraction() {
352 | return 1.0f;
353 | }
354 |
355 | @Override
356 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
357 | width = getWidthFraction(ddt) * getBounds().width();
358 | bgWidth = getBgWidthFraction(ddt) * getBounds().width();
359 | }
360 |
361 | private float getWidthFraction(float ddt) {
362 | float time;
363 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_1_START, FRACTION_ENLARGING_1_END)) {
364 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_1_START, FRACTION_ENLARGING_1_END);
365 | return DrawableUtils.enlarge(SIZE_FRACTION_0, SIZE_FRACTION_45, time);
366 | }
367 | if (DrawableUtils.between(ddt, IDLE_FRACTION_1_START, IDLE_FRACTION_1_END)) {
368 | return SIZE_FRACTION_45;
369 | }
370 | if (DrawableUtils.between(ddt, FRACTION_REDUCING_1_START, FRACTION_REDUCING_1_END)) {
371 | time = DrawableUtils.normalize(ddt, FRACTION_REDUCING_1_START, FRACTION_REDUCING_1_END);
372 | return DrawableUtils.reduce(SIZE_FRACTION_45, SIZE_FRACTION_25, time);
373 | }
374 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_2_START, FRACTION_ENLARGING_2_END)) {
375 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_2_START, FRACTION_ENLARGING_2_END);
376 | return DrawableUtils.enlarge(SIZE_FRACTION_25, SIZE_FRACTION_75, time);
377 | }
378 | if (DrawableUtils.between(ddt, IDLE_FRACTION_2_START, IDLE_FRACTION_2_END)) {
379 | return SIZE_FRACTION_75;
380 | }
381 | return SIZE_FRACTION_0;
382 | }
383 |
384 | private float getBgWidthFraction(float ddt) {
385 | if (DrawableUtils.between(ddt, IDLE_BG_1_START, IDLE_BG_1_END)) {
386 | return SIZE_FRACTION_25;
387 | }
388 | return SIZE_FRACTION_0;
389 | }
390 |
391 | @Override
392 | public void draw(@NonNull Canvas canvas) {
393 | if (bgWidth > 0) {
394 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), bgWidth / 2f, bgPaint);
395 | }
396 | if (width > 0) {
397 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), width / 2f, getPaint());
398 | }
399 | }
400 | }
401 |
402 | private static final class BlueArc extends DrawableObjectImpl {
403 | // TIMING
404 | private static final float IDLE_1_ANGLE_START = 0f;
405 | private static final float IDLE_1_ANGLE_END = 29 * Constants.FRAME_SPEED;
406 |
407 | private static final float ANGLE_CHANGING_START = 34 * Constants.FRAME_SPEED;
408 | private static final float ANGLE_CHANGING_END = 60 * Constants.FRAME_SPEED;
409 |
410 | // DIMENSIONS
411 | private static final float SIZE_FRACTION_60 = 0.6f;
412 | private static final float SIZE_FRACTION_0 = 0f;
413 |
414 | private static final float START_ANGLE_BEGIN = 90f;
415 | private static final float END_ANGLE_BEGIN = -110f;
416 |
417 | private static final float ZERO_ANGLE = 0f;
418 | private static final float MAX_ANGLE = 360f;
419 |
420 | private Interpolator interpolator = new AccelerateDecelerateInterpolator();
421 |
422 | private float arcAngle;
423 | private float arcAngleBegin;
424 | private RectF rect;
425 |
426 | public BlueArc(Paint paint) {
427 | super(paint);
428 | rect = new RectF();
429 | }
430 |
431 | @Override
432 | protected float getSizeFraction() {
433 | return 1f;
434 | }
435 |
436 | @Override
437 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
438 | float coef = getWidthFraction(ddt);
439 | float leftRightMargin = (getBounds().width() - getBounds().width() * coef) / 2f;
440 | float topBottomMargin = (getBounds().height() - getBounds().height() * coef) / 2f;
441 | float l = getBounds().left + leftRightMargin;
442 | float r = getBounds().right - leftRightMargin;
443 | float t = getBounds().top + topBottomMargin;
444 | float b = getBounds().bottom - topBottomMargin;
445 | rect.set(l, t, r, b);
446 | arcAngle = getArcAngle(ddt, MAX_ANGLE, ZERO_ANGLE);
447 | arcAngleBegin = getArcAngle(ddt, END_ANGLE_BEGIN, START_ANGLE_BEGIN);
448 | }
449 |
450 | private float getWidthFraction(float ddt) {
451 | if (DrawableUtils.between(ddt, IDLE_1_ANGLE_START, IDLE_1_ANGLE_END)) {
452 | return SIZE_FRACTION_0;
453 | }
454 | if (DrawableUtils.between(ddt, ANGLE_CHANGING_START, ANGLE_CHANGING_END)) {
455 | return SIZE_FRACTION_60;
456 | }
457 | return SIZE_FRACTION_0;
458 | }
459 |
460 | private float getArcAngle(float ddt, float start, float end) {
461 | float time;
462 | if (DrawableUtils.between(ddt, IDLE_1_ANGLE_START, IDLE_1_ANGLE_END)) {
463 | return start;
464 | }
465 | if (DrawableUtils.between(ddt, ANGLE_CHANGING_START, ANGLE_CHANGING_END)) {
466 | time = interpolator.getInterpolation(DrawableUtils.normalize(ddt, ANGLE_CHANGING_START, ANGLE_CHANGING_END));
467 | return end + (start - end) * (1 - time);
468 | }
469 | return start;
470 | }
471 |
472 | @Override
473 | public void draw(@NonNull Canvas canvas) {
474 | if (Math.abs(arcAngle) > 0) {
475 | canvas.drawArc(rect, arcAngleBegin, -arcAngle, true, getPaint());
476 | }
477 | }
478 | }
479 |
480 | private static final class YellowArc extends DrawableObjectImpl {
481 | // TIMING OF FRACTION SIZE
482 | private static final float IDLE_FRACTION_1_START = 0f;
483 | private static final float IDLE_FRACTION_1_END = 17 * Constants.FRAME_SPEED;
484 |
485 | private static final float FRACTION_REDUCING_1_START = 17 * Constants.FRAME_SPEED;
486 | private static final float FRACTION_REDUCING_1_END = 25 * Constants.FRAME_SPEED;
487 |
488 | private static final float IDLE_FRACTION_2_START = 25 * Constants.FRAME_SPEED;
489 | private static final float IDLE_FRACTION_2_END = 53 * Constants.FRAME_SPEED;
490 |
491 | private static final float FRACTION_REDUCING_2_START = 53 * Constants.FRAME_SPEED;
492 | private static final float FRACTION_REDUCING_2_END = 59 * Constants.FRAME_SPEED;
493 |
494 | private static final float IDLE_FRACTION_3_START = 59 * Constants.FRAME_SPEED;
495 | private static final float IDLE_FRACTION_3_END = 133 * Constants.FRAME_SPEED;
496 |
497 | private static final float FRACTION_ENLARGING_1_START = 133 * Constants.FRAME_SPEED;
498 | private static final float FRACTION_ENLARGING_1_END = 139 * Constants.FRAME_SPEED;
499 |
500 | private static final float IDLE_FRACTION_4_START = 139 * Constants.FRAME_SPEED;
501 | private static final float IDLE_FRACTION_4_END = 143 * Constants.FRAME_SPEED;
502 |
503 | private static final float FRACTION_ENLARGING_2_START = 143 * Constants.FRAME_SPEED;
504 | private static final float FRACTION_ENLARGING_2_END = 149 * Constants.FRAME_SPEED;
505 |
506 | // TIMING OF ARC ANGLE
507 | private static final float IDLE_ANGLE_1_START = 0f;
508 | private static final float IDLE_ANGLE_1_END = 27 * Constants.FRAME_SPEED;
509 |
510 | private static final float ANGLE_CHANGING_START = 26 * Constants.FRAME_SPEED;
511 | private static final float ANGLE_CHANGING_END = 60 * Constants.FRAME_SPEED;
512 |
513 | // DIMENSIONS
514 | private static final float SIZE_FRACTION_75 = 0.75f;
515 | private static final float SIZE_FRACTION_60 = 0.6f;
516 | private static final float SIZE_FRACTION_0 = 0f;
517 |
518 | private static final float START_ANGLE_BEGIN = 90f;
519 | private static final float END_ANGLE_BEGIN = -110f;
520 |
521 | private static final float ZERO_ANGLE = 0f;
522 | private static final float MAX_ANGLE = 360f;
523 |
524 | private Interpolator accelerate = new AccelerateDecelerateInterpolator();
525 |
526 | private RectF rect;
527 | private float arcAngleBegin;
528 | private float arcAngle;
529 |
530 | public YellowArc(Paint paint) {
531 | super(paint);
532 | rect = new RectF();
533 | }
534 |
535 | @Override
536 | protected float getSizeFraction() {
537 | return 1.0f;
538 | }
539 |
540 | @Override
541 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
542 | float coef = getWidthFraction(ddt);
543 | float leftRightMargin = (getBounds().width() - getBounds().width() * coef) / 2f;
544 | float topBottomMargin = (getBounds().height() - getBounds().height() * coef) / 2f;
545 | float l = getBounds().left + leftRightMargin;
546 | float r = getBounds().right - leftRightMargin;
547 | float t = getBounds().top + topBottomMargin;
548 | float b = getBounds().bottom - topBottomMargin;
549 | rect.set(l, t, r, b);
550 | arcAngle = getArcAngle(ddt, MAX_ANGLE, ZERO_ANGLE);
551 | arcAngleBegin = getArcAngle(ddt, END_ANGLE_BEGIN, START_ANGLE_BEGIN);
552 | }
553 |
554 | private float getWidthFraction(float ddt) {
555 | float time;
556 | if (DrawableUtils.between(ddt, IDLE_FRACTION_1_START, IDLE_FRACTION_1_END)) {
557 | return SIZE_FRACTION_75;
558 | }
559 | if (DrawableUtils.between(ddt, FRACTION_REDUCING_1_START, FRACTION_REDUCING_1_END)) {
560 | time = DrawableUtils.normalize(ddt, FRACTION_REDUCING_1_START, FRACTION_REDUCING_1_END);
561 | return DrawableUtils.reduce(SIZE_FRACTION_75, SIZE_FRACTION_60, time);
562 | }
563 | if (DrawableUtils.between(ddt, IDLE_FRACTION_2_START, IDLE_FRACTION_2_END)) {
564 | return SIZE_FRACTION_60;
565 | }
566 | if (DrawableUtils.between(ddt, FRACTION_REDUCING_2_START, FRACTION_REDUCING_2_END)) {
567 | time = DrawableUtils.normalize(ddt, FRACTION_REDUCING_2_START, FRACTION_REDUCING_2_END);
568 | return DrawableUtils.reduce(SIZE_FRACTION_60, SIZE_FRACTION_0, time);
569 | }
570 | if (DrawableUtils.between(ddt, IDLE_FRACTION_3_START, IDLE_FRACTION_3_END)) {
571 | return SIZE_FRACTION_0;
572 | }
573 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_1_START, FRACTION_ENLARGING_1_END)) {
574 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_1_START, FRACTION_ENLARGING_1_END);
575 | return DrawableUtils.enlarge(SIZE_FRACTION_0, SIZE_FRACTION_75, time);
576 | }
577 | if (DrawableUtils.between(ddt, IDLE_FRACTION_4_START, IDLE_FRACTION_4_END)) {
578 | return SIZE_FRACTION_75;
579 | }
580 | if (DrawableUtils.between(ddt, FRACTION_ENLARGING_2_START, FRACTION_ENLARGING_2_END)) {
581 | time = DrawableUtils.normalize(ddt, FRACTION_ENLARGING_2_START, FRACTION_ENLARGING_2_END);
582 | return DrawableUtils.enlarge(SIZE_FRACTION_0, SIZE_FRACTION_75, time);
583 | }
584 | return SIZE_FRACTION_75;
585 | }
586 |
587 | private float getArcAngle(float ddt, float start, float end) {
588 | float time;
589 | if (DrawableUtils.between(ddt, IDLE_ANGLE_1_START, IDLE_ANGLE_1_END)) {
590 | return start;
591 | }
592 | if (DrawableUtils.between(ddt, ANGLE_CHANGING_START, ANGLE_CHANGING_END)) {
593 | time = accelerate.getInterpolation(DrawableUtils.normalize(ddt, ANGLE_CHANGING_START, ANGLE_CHANGING_END));
594 | return end + (start - end) * (1 - time);
595 | }
596 | return start;
597 | }
598 |
599 | @Override
600 | public void draw(@NonNull Canvas canvas) {
601 | if (Math.abs(arcAngle) > 0) {
602 | canvas.drawArc(rect, arcAngleBegin, -arcAngle, true, getPaint());
603 | }
604 | }
605 | }
606 | }
607 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/Layer.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | /**
4 | * Abstract layer implementation.
5 | */
6 | abstract class Layer implements DrawableObject, Resetable {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/LoadingAnimationView.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.annotation.TargetApi;
5 | import android.content.Context;
6 | import android.content.res.TypedArray;
7 | import android.graphics.Canvas;
8 | import android.graphics.Color;
9 | import android.graphics.Paint;
10 | import android.graphics.RectF;
11 | import android.os.Build;
12 | import android.support.annotation.NonNull;
13 | import android.util.AttributeSet;
14 | import android.view.View;
15 | import android.view.animation.LinearInterpolator;
16 |
17 | import java.util.Random;
18 |
19 | /**
20 | * Android M Loading animation view.
21 | */
22 | public class LoadingAnimationView extends View {
23 |
24 | private static final int LAYERS_COUNT = 4;
25 |
26 | private final Layer[] layers = new Layer[LAYERS_COUNT];
27 | private YellowRectangle yellowRectangle;
28 | private final RectF bounds = new RectF();
29 | private ValueAnimator valueAnimator;
30 | private Random random;
31 |
32 | private int bgColor;
33 |
34 | public LoadingAnimationView(Context context) {
35 | this(context, null);
36 | }
37 |
38 | public LoadingAnimationView(Context context, AttributeSet attrs) {
39 | super(context, attrs);
40 | init(context, attrs);
41 | }
42 |
43 | public LoadingAnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
44 | this(context, attrs, defStyleAttr, 0);
45 | }
46 |
47 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
48 | public LoadingAnimationView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
49 | super(context, attrs, defStyleAttr, defStyleRes);
50 | init(context, attrs);
51 | }
52 |
53 | void fromBuilder(@NonNull AnimationDialogFragment.Builder builder) {
54 | initValues(
55 | builder.getFirstColor(getContext()),
56 | builder.getSecondColor(getContext()),
57 | builder.getThirdColor(getContext()),
58 | builder.getFourthColor(getContext()),
59 | builder.getBackgroundColor(),
60 | builder.getSpeedCoefficient()
61 | );
62 | }
63 |
64 |
65 |
66 | private void init(Context context, AttributeSet attrs) {
67 | int googleBlue = ColorUtil.getColor(context, R.color.lav_google_blue);
68 | int googleYellow = ColorUtil.getColor(context, R.color.lav_google_yellow);
69 | int googleRed = ColorUtil.getColor(context, R.color.lav_google_red);
70 | int googleGreen = ColorUtil.getColor(context, R.color.lav_google_green);
71 |
72 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LoadingAnimationView);
73 | int firstColor;
74 | int secondColor;
75 | int thirdColor;
76 | int fourthColor;
77 | int bgColor;
78 | float speedCoefficient;
79 | try {
80 | firstColor = typedArray.getColor(R.styleable.LoadingAnimationView_lav_firstColor, googleRed);
81 | secondColor = typedArray.getColor(R.styleable.LoadingAnimationView_lav_secondColor, googleGreen);
82 | thirdColor = typedArray.getColor(R.styleable.LoadingAnimationView_lav_thirdColor, googleBlue);
83 | fourthColor = typedArray.getColor(R.styleable.LoadingAnimationView_lav_fourthColor, googleYellow);
84 | bgColor = typedArray.getColor(R.styleable.LoadingAnimationView_lav_backgroundColor, Color.BLACK);
85 | speedCoefficient = typedArray.getFloat(R.styleable.LoadingAnimationView_lav_speedCoefficient, Constants.DEFAULT_SPEED_COEFFICIENT);
86 | } finally {
87 | typedArray.recycle();
88 | }
89 |
90 | initValues(firstColor, secondColor, thirdColor, fourthColor, bgColor, speedCoefficient);
91 | }
92 |
93 | private void initValues(int red, int green, int blue, int yellow, int bgColor, float speedCoefficient) {
94 | Paint bluePaint = new Paint();
95 | Paint yellowPaint = new Paint();
96 | Paint redPaint = new Paint();
97 | Paint greenPaint = new Paint();
98 | redPaint.setColor(red);
99 | redPaint.setAntiAlias(true);
100 | greenPaint.setColor(green);
101 | greenPaint.setAntiAlias(true);
102 | bluePaint.setColor(blue);
103 | bluePaint.setAntiAlias(true);
104 | yellowPaint.setColor(yellow);
105 | yellowPaint.setAntiAlias(true);
106 | Paint bgPaint = new Paint();
107 | bgPaint.setColor(bgColor);
108 | bgPaint.setAntiAlias(true);
109 |
110 | this.bgColor = bgColor;
111 | layers[0] = new FirstLayer(bluePaint, greenPaint, yellowPaint, bgPaint);
112 | layers[1] = new SecondLayer(redPaint, yellowPaint, bgPaint);
113 | layers[2] = new ThirdLayer(redPaint, greenPaint, bgPaint);
114 | layers[3] = new FourthLayer(redPaint, greenPaint, bluePaint, yellowPaint, bgPaint);
115 | yellowRectangle = new YellowRectangle(yellowPaint);
116 | Constants.SPEED_COEFFICIENT = speedCoefficient;
117 | valueAnimator = ValueAnimator.ofFloat(0, 1);
118 | valueAnimator.setInterpolator(new LinearInterpolator());
119 | valueAnimator.setDuration((long) (Constants.TOTAL_DURATION * Constants.SPEED_COEFFICIENT));
120 | valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
121 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
122 | @Override
123 | public void onAnimationUpdate(ValueAnimator animation) {
124 | updateAnimation(getWidth(), animation.getAnimatedFraction());
125 | invalidate();
126 | }
127 | });
128 | }
129 |
130 | private void updateAnimation(float width, float dt) {
131 | float left = getPaddingLeft();
132 | float right = getPaddingRight();
133 | float maxWidth = 1f * (width - (left + right)) / LAYERS_COUNT;
134 | float spacing = maxWidth * 0.1f;
135 | float size = maxWidth - spacing;
136 | float halfSize = size / 2f;
137 |
138 | for (int i = 0; i< LAYERS_COUNT; i++) {
139 | float l = left + i * (size + spacing);
140 | float t = getHeight() / 2f - halfSize;
141 | float r = l + size;
142 | float b = t + size;
143 | bounds.set(l, t, r, b);
144 | layers[i].update(bounds, dt);
145 | if (i == 1) {
146 | yellowRectangle.setFirstValues(bounds.centerX(), bounds.centerY());
147 | } else if (i == 2) {
148 | yellowRectangle.setSecondValues(bounds.centerX(), bounds.centerY());
149 | } else if (i == 3) {
150 | yellowRectangle.setThirdValues(bounds.centerX(), bounds.centerY());
151 | yellowRectangle.updateRadius(bounds.height());
152 | }
153 | }
154 | yellowRectangle.update(bounds, dt);
155 | }
156 |
157 | @Override
158 | public void onDraw(Canvas canvas) {
159 | if (isInEditMode()) {
160 | if (random == null) {
161 | random = new Random();
162 | }
163 | updateAnimation(canvas.getWidth(), random.nextFloat());
164 | }
165 | canvas.drawColor(bgColor);
166 | for (int i = 0; i< LAYERS_COUNT; i++) {
167 | layers[i].draw(canvas);
168 | }
169 | yellowRectangle.draw(canvas);
170 | }
171 |
172 | /**
173 | * Start animation.
174 | */
175 | public void startAnimation() {
176 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && valueAnimator.isPaused()) {
177 | valueAnimator.resume();
178 | return;
179 | }
180 | if (valueAnimator.isRunning())
181 | return;
182 | valueAnimator.start();
183 | }
184 |
185 | /**
186 | * Pause animation. It behaves like {@link #stopAnimation()} on API < 19.
187 | */
188 | public void pauseAnimation() {
189 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
190 | stopAnimation();
191 | } else if (!valueAnimator.isPaused()) {
192 | valueAnimator.pause();
193 | }
194 | }
195 |
196 | /**
197 | * Stop animation.
198 | */
199 | public void stopAnimation() {
200 | if (!valueAnimator.isRunning()) {
201 | return;
202 | }
203 | valueAnimator.cancel();
204 | resetAll();
205 | invalidate();
206 | }
207 |
208 | private void resetAll() {
209 | for (Layer layer : layers) {
210 | layer.reset();
211 | }
212 | yellowRectangle.reset();
213 | }
214 |
215 | /**
216 | * Check current state of animation.
217 | * @return true if animation is running, false otherwise
218 | */
219 | public boolean isRunning() {
220 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && valueAnimator.isPaused()) {
221 | return false;
222 | }
223 | return valueAnimator.isRunning();
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/Resetable.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | /**
4 | * Interface that allows to reset current state.
5 | */
6 | interface Resetable {
7 | void reset();
8 | }
9 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/SecondLayer.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.graphics.RectF;
6 | import android.support.annotation.NonNull;
7 |
8 | /**
9 | * Second layer of animation.
10 | */
11 | class SecondLayer extends Layer {
12 |
13 | private final DrawableObject[] objects;
14 |
15 | public SecondLayer(Paint redPaint, Paint yellowPaint, Paint bgPaint) {
16 | objects = new DrawableObject[3];
17 | objects[0] = new YellowCircleInner(yellowPaint);
18 | objects[1] = new RedSunRays(redPaint);
19 | objects[2] = new RedRing(redPaint, yellowPaint, bgPaint);
20 | }
21 |
22 | @Override
23 | public void update(@NonNull RectF bounds, float dt) {
24 | for (DrawableObject object : objects) {
25 | object.update(bounds, dt);
26 | }
27 | }
28 |
29 | @Override
30 | public void draw(@NonNull Canvas canvas) {
31 | for (DrawableObject object : objects) {
32 | object.draw(canvas);
33 | }
34 | }
35 |
36 | @Override
37 | public void reset() {
38 | for (DrawableObject object : objects) {
39 | if (object instanceof Resetable) {
40 | ((Resetable) object).reset();
41 | }
42 | }
43 | }
44 |
45 | private static final class RedSunRays extends DrawableObjectImpl {
46 |
47 | private static final float ROTATION_FRACTION_START = 54 * Constants.FRAME_SPEED;
48 | private static final float ROTATION_FRACTION_END = 88 * Constants.FRAME_SPEED;
49 |
50 | private static final float ENLARGE_1_FRACTION_START = 48 * Constants.FRAME_SPEED;
51 | private static final float ENLARGE_1_FRACTION_END = 57 * Constants.FRAME_SPEED;
52 |
53 | private static final float REDUCE_1_FRACTION_START = 58 * Constants.FRAME_SPEED;
54 | private static final float REDUCE_1_FRACTION_END = 64 * Constants.FRAME_SPEED;
55 |
56 | private static final float CIRCLES_MOVEMENT_FRACTION_START = 63 * Constants.FRAME_SPEED;
57 | private static final float CIRCLES_MOVEMENT_FRACTION_END = 68 * Constants.FRAME_SPEED;
58 |
59 | private static final float CIRCLES_VISIBILITY_FRACTION_START = 59 * Constants.FRAME_SPEED;
60 | private static final float CIRCLES_VISIBILITY_FRACTION_END = 63 * Constants.FRAME_SPEED;
61 |
62 | private static final float RAYS_VISIBILITY_1_FRACTION_START = 64 * Constants.FRAME_SPEED;
63 | private static final float RAYS_VISIBILITY_1_FRACTION_END = 69 * Constants.FRAME_SPEED;
64 |
65 | private static final float ENLARGE_2_FRACTION_START = 114 * Constants.FRAME_SPEED;
66 | private static final float ENLARGE_2_FRACTION_END = 126 * Constants.FRAME_SPEED;
67 |
68 | private static final float REDUCE_2_FRACTION_START = 127 * Constants.FRAME_SPEED;
69 | private static final float REDUCE_2_FRACTION_END = 137 * Constants.FRAME_SPEED;
70 |
71 | private static final float RAYS_VISIBILITY_2_FRACTION_START = 132 * Constants.FRAME_SPEED;
72 | private static final float RAYS_VISIBILITY_2_FRACTION_END = 136 * Constants.FRAME_SPEED;
73 |
74 | private static final float SWAP_FRACTION = 90 * Constants.FRAME_SPEED;
75 |
76 | private static final float SIZE_FRACTION = 0.8f;
77 |
78 | private static final int RAYS_COUNT = 8;
79 | private static final float END_ANGLE = -90;
80 |
81 | private final Paint dotsPaint;
82 | private final RectF rect;
83 | private float angle;
84 | private boolean draw;
85 | private float dotSize;
86 | private float dotCx, dotCy;
87 |
88 | public RedSunRays(Paint paint) {
89 | super(new Paint(paint));
90 | this.dotsPaint = new Paint(paint);
91 | this.rect = new RectF();
92 | }
93 |
94 | @Override
95 | protected float getSizeFraction() {
96 | return SIZE_FRACTION;
97 | }
98 |
99 | @Override
100 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
101 | draw = true;
102 | dotSize = 0;
103 | if (ddt < ENLARGE_1_FRACTION_START || ddt > REDUCE_2_FRACTION_END) {
104 | draw = false;
105 | return;
106 | }
107 |
108 | if (DrawableUtils.between(ddt, ROTATION_FRACTION_START, ROTATION_FRACTION_END)) {
109 | float t = DrawableUtils.normalize(ddt, ROTATION_FRACTION_START, ROTATION_FRACTION_END);
110 | angle = t * END_ANGLE;
111 | }
112 |
113 | if (ddt >= SWAP_FRACTION) {
114 | getPaint().setAlpha(255);
115 | dotsPaint.setAlpha(0);
116 | }
117 |
118 | float width = getBounds().width() * 0.07f;
119 | float height = getBounds().width() * 0.28f;
120 | float halfSize = width / 2f;
121 | float cx = getBounds().centerX();
122 |
123 | if (DrawableUtils.between(ddt, ENLARGE_1_FRACTION_START, ENLARGE_1_FRACTION_END)) {
124 | float l, t, r, b;
125 | l = cx - halfSize;
126 | r = cx + halfSize;
127 | b = getBounds().top + height;
128 | float time = DrawableUtils.normalize(ddt, ENLARGE_1_FRACTION_START, ENLARGE_1_FRACTION_END);
129 | t = b - DrawableUtils.enlarge(width, height, time);
130 | rect.set(l, t, r, b);
131 | }
132 | if (DrawableUtils.between(ddt, REDUCE_1_FRACTION_START, REDUCE_1_FRACTION_END)) {
133 | float l, t, r, b;
134 | l = cx - halfSize;
135 | r = cx + halfSize;
136 | t = getBounds().top;
137 | float time = DrawableUtils.normalize(ddt, REDUCE_1_FRACTION_START, REDUCE_1_FRACTION_END);
138 | b = t + DrawableUtils.reduce(height, width, time);
139 | rect.set(l, t, r, b);
140 | }
141 |
142 | if (DrawableUtils.between(ddt, ENLARGE_2_FRACTION_START, ENLARGE_2_FRACTION_END)) {
143 | float l, t, r, b;
144 | l = cx - halfSize;
145 | r = cx + halfSize;
146 | t = getBounds().top;
147 | float time = DrawableUtils.normalize(ddt, ENLARGE_2_FRACTION_START, ENLARGE_2_FRACTION_END);
148 | b = t + DrawableUtils.enlarge(width, height, time);
149 | rect.set(l, t, r, b);
150 | }
151 | if (DrawableUtils.between(ddt, REDUCE_2_FRACTION_START, REDUCE_2_FRACTION_END)) {
152 | float l, t, r, b;
153 | l = cx - halfSize;
154 | r = cx + halfSize;
155 | b = getBounds().top + height;
156 | float time = DrawableUtils.normalize(ddt, REDUCE_2_FRACTION_START, REDUCE_2_FRACTION_END);
157 | t = b - DrawableUtils.reduce(height, width, time);
158 | rect.set(l, t, r, b);
159 | }
160 |
161 | float startPoint = getBounds().top + height - halfSize;
162 | if (DrawableUtils.between(ddt, CIRCLES_VISIBILITY_FRACTION_START, SWAP_FRACTION)) {
163 | dotCx = cx;
164 | if (dotCy == 0)
165 | dotCy = startPoint;
166 | dotSize = width;
167 | } else {
168 | dotSize = 0;
169 | }
170 |
171 | if (DrawableUtils.between(ddt, CIRCLES_VISIBILITY_FRACTION_START, CIRCLES_VISIBILITY_FRACTION_END)) {
172 | float t = DrawableUtils.normalize(ddt, CIRCLES_VISIBILITY_FRACTION_START, CIRCLES_VISIBILITY_FRACTION_END);
173 | dotsPaint.setAlpha((int) (t * 255));
174 | }
175 | if (DrawableUtils.between(ddt, CIRCLES_MOVEMENT_FRACTION_START, CIRCLES_MOVEMENT_FRACTION_END)) {
176 | float t = DrawableUtils.normalize(ddt, CIRCLES_MOVEMENT_FRACTION_START, CIRCLES_MOVEMENT_FRACTION_END);
177 | dotCy = DrawableUtils.reduce(startPoint, getBounds().top + halfSize, t);
178 | dotsPaint.setAlpha(255);
179 | }
180 |
181 |
182 | if (DrawableUtils.between(ddt, RAYS_VISIBILITY_1_FRACTION_START, RAYS_VISIBILITY_1_FRACTION_END)) {
183 | float t = DrawableUtils.normalize(ddt, RAYS_VISIBILITY_1_FRACTION_START, RAYS_VISIBILITY_1_FRACTION_END);
184 | getPaint().setAlpha((int) ((1 - t) * 255));
185 | }
186 |
187 | if (DrawableUtils.between(ddt, RAYS_VISIBILITY_2_FRACTION_START, RAYS_VISIBILITY_2_FRACTION_END)) {
188 | float t = DrawableUtils.normalize(ddt, RAYS_VISIBILITY_2_FRACTION_START, RAYS_VISIBILITY_2_FRACTION_END);
189 | getPaint().setAlpha((int) ((1 - t) * 255));
190 | }
191 | }
192 |
193 | @Override
194 | public void draw(@NonNull Canvas canvas) {
195 | if (!draw)
196 | return;
197 | float halfSize = rect.width() / 2f;
198 | float cx = getBounds().centerX();
199 | float cy = getBounds().centerY();
200 | canvas.save();
201 | canvas.rotate(angle, cx, cy);
202 | for (int i=0; i 0) {
206 | canvas.drawCircle(dotCx, dotCy, dotSize / 2f, dotsPaint);
207 | }
208 | }
209 | canvas.restore();
210 | }
211 | }
212 |
213 | private static final class YellowCircleInner extends DrawableObjectImpl {
214 |
215 | private static final float ENLARGE_FRACTION_START = 65 * Constants.FRAME_SPEED;
216 | private static final float ENLARGE_FRACTION_END = 72 * Constants.FRAME_SPEED;
217 |
218 | private static final float MORE_ENLARGE_FRACTION_START = 97 * Constants.FRAME_SPEED;
219 | private static final float MORE_ENLARGE_FRACTION_END = 110 * Constants.FRAME_SPEED;
220 |
221 | private static final float MORE_REDUCE_FRACTION_START = 110 * Constants.FRAME_SPEED;
222 | private static final float MORE_REDUCE_FRACTION_END = 121 * Constants.FRAME_SPEED;
223 |
224 | private static final float DEFAULT_SIZE = 0.5f;
225 | private static final float LARGER_SIZE = 0.65f;
226 | private static final float LARGEST_SIZE = 0.8f;
227 |
228 | private static final float SIZE_FRACTION = 0.6f;
229 |
230 | private float size;
231 |
232 | public YellowCircleInner(Paint paint) {
233 | super(paint);
234 | }
235 |
236 | @Override
237 | protected float getSizeFraction() {
238 | return SIZE_FRACTION;
239 | }
240 |
241 | @Override
242 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
243 | size = getSizeFraction(ddt) * getBounds().width();
244 | }
245 |
246 | private float getSizeFraction(float ddt) {
247 | if (DrawableUtils.between(ddt, ENLARGE_FRACTION_START, ENLARGE_FRACTION_END)) {
248 | float t = DrawableUtils.normalize(ddt, ENLARGE_FRACTION_START, ENLARGE_FRACTION_END);
249 | return DrawableUtils.enlarge(DEFAULT_SIZE, LARGER_SIZE, t);
250 | }
251 | if (DrawableUtils.between(ddt, ENLARGE_FRACTION_END, MORE_ENLARGE_FRACTION_START)) {
252 | return LARGER_SIZE;
253 | }
254 | if (DrawableUtils.between(ddt, MORE_ENLARGE_FRACTION_START, MORE_ENLARGE_FRACTION_END)) {
255 | float t = DrawableUtils.normalize(ddt, MORE_ENLARGE_FRACTION_START, MORE_ENLARGE_FRACTION_END);
256 | return DrawableUtils.enlarge(LARGER_SIZE, LARGEST_SIZE, t);
257 | }
258 | if (DrawableUtils.between(ddt, MORE_ENLARGE_FRACTION_END, MORE_REDUCE_FRACTION_START)) {
259 | return LARGEST_SIZE;
260 | }
261 | if (DrawableUtils.between(ddt, MORE_REDUCE_FRACTION_START, MORE_REDUCE_FRACTION_END)) {
262 | float t = DrawableUtils.normalize(ddt, MORE_REDUCE_FRACTION_START, MORE_REDUCE_FRACTION_END);
263 | return DrawableUtils.reduce(LARGEST_SIZE, DEFAULT_SIZE, t);
264 | }
265 | return 0;
266 | }
267 |
268 | @Override
269 | public void draw(@NonNull Canvas canvas) {
270 | if (size > 0) {
271 | float cx = getBounds().centerX();
272 | float cy = getBounds().centerY();
273 | canvas.drawCircle(cx, cy, size / 2f, getPaint());
274 | }
275 | }
276 | }
277 |
278 | private static final class RedRing extends DrawableObjectImpl {
279 |
280 | private static final float FRACTION_START = Constants.FIRST_FRAME_FRACTION;
281 |
282 | private static final float YELLOW_ENLARGE_FRACTION_START = 7 * Constants.FRAME_SPEED;
283 | private static final float YELLOW_ENLARGE_FRACTION_END = 16.5f * Constants.FRAME_SPEED;
284 | private static final float YELLOW_MEDIUM_ENLARGE_FRACTION_START = 52 * Constants.FRAME_SPEED;
285 | private static final float YELLOW_MEDIUM_ENLARGE_FRACTION_END = 62 * Constants.FRAME_SPEED;
286 | private static final float YELLOW_MEDIUM_REDUCE_FRACTION_START = 131 * Constants.FRAME_SPEED;
287 | private static final float YELLOW_MEDIUM_REDUCE_FRACTION_END = 139 * Constants.FRAME_SPEED;
288 | private static final float YELLOW_RESTORE_FRACTION_START = 140 * Constants.FRAME_SPEED;
289 | private static final float YELLOW_RESTORE_FRACTION_END = Constants.LAST_FRAME_FRACTION;
290 |
291 | private static final float BLACK_REDUCED_FRACTION = 12 * Constants.FRAME_SPEED;
292 | private static final float BLACK_RESTORE_FRACTION_START = 139 * Constants.FRAME_SPEED;
293 | private static final float BLACK_RESTORE_FRACTION_END = Constants.LAST_FRAME_FRACTION;
294 |
295 | private static final float RED_REDUCE_FRACTION_START = 50 * Constants.FRAME_SPEED;
296 | private static final float RED_REDUCE_FRACTION_END = 60 * Constants.FRAME_SPEED;
297 | private static final float RED_ENLARGE_FRACTION_START = 125 * Constants.FRAME_SPEED;
298 | private static final float RED_ENLARGE_FRACTION_END = 139 * Constants.FRAME_SPEED;
299 |
300 |
301 | private static final float SIZE_FRACTION = 0.6f;
302 |
303 | private static final float YELLOW_DEFAULT_SIZE = 0.25f;
304 | private static final float YELLOW_LARGE_SIZE = 1f;
305 |
306 | private static final float BLACK_DEFAULT_SIZE = 0.5f;
307 | private static final float BLACK_SMALL_SIZE = 0.1f;
308 |
309 | private static final float RED_DEFAULT_SIZE = 1f;
310 | private static final float RED_SMALL_SIZE = 0.5f;
311 |
312 | private static final float ZERO_SIZE = 0f;
313 |
314 | private final Paint bgPaint;
315 | private final Paint yellowPaint;
316 | private float blackWidth;
317 | private float width;
318 | private float yellowWidth;
319 |
320 | public RedRing(Paint paint, Paint yellowPaint, Paint bgPaint) {
321 | super(paint);
322 | this.bgPaint = bgPaint;
323 | this.yellowPaint = yellowPaint;
324 | }
325 |
326 | @Override
327 | protected float getSizeFraction() {
328 | return SIZE_FRACTION;
329 | }
330 |
331 | @Override
332 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
333 | width = computeRedSizeFraction(ddt) * getBounds().width();
334 | blackWidth = computeBlackSizeFraction(ddt) * getBounds().width();
335 | yellowWidth = computeYellowSizeFraction(ddt) * getBounds().width();
336 | }
337 |
338 | private float computeRedSizeFraction(float ddt) {
339 | if (DrawableUtils.between(ddt, FRACTION_START, RED_REDUCE_FRACTION_START)) {
340 | return RED_DEFAULT_SIZE;
341 | }
342 | if (DrawableUtils.between(ddt, RED_REDUCE_FRACTION_START, RED_REDUCE_FRACTION_END)) {
343 | float t = DrawableUtils.normalize(ddt, RED_REDUCE_FRACTION_START, RED_REDUCE_FRACTION_END);
344 | return DrawableUtils.reduce(RED_DEFAULT_SIZE, RED_SMALL_SIZE, t);
345 | }
346 | if (DrawableUtils.between(ddt, RED_REDUCE_FRACTION_END, RED_ENLARGE_FRACTION_START)) {
347 | return RED_SMALL_SIZE;
348 | }
349 | if (DrawableUtils.between(ddt, RED_ENLARGE_FRACTION_START, RED_ENLARGE_FRACTION_END)) {
350 | float t = DrawableUtils.normalize(ddt, RED_ENLARGE_FRACTION_START, RED_ENLARGE_FRACTION_END);
351 | return DrawableUtils.enlarge(RED_SMALL_SIZE, RED_DEFAULT_SIZE, t);
352 | }
353 | return RED_DEFAULT_SIZE;
354 | }
355 |
356 | private float computeBlackSizeFraction(float ddt) {
357 | if (DrawableUtils.between(ddt, FRACTION_START, BLACK_REDUCED_FRACTION)) {
358 | return BLACK_DEFAULT_SIZE;
359 | }
360 | if (DrawableUtils.between(ddt, BLACK_REDUCED_FRACTION, BLACK_RESTORE_FRACTION_START)) {
361 | return BLACK_SMALL_SIZE;
362 | }
363 | if (DrawableUtils.between(ddt, BLACK_RESTORE_FRACTION_START, BLACK_RESTORE_FRACTION_END)) {
364 | float t = DrawableUtils.normalize(ddt, BLACK_RESTORE_FRACTION_START, BLACK_RESTORE_FRACTION_END);
365 | return DrawableUtils.enlarge(BLACK_SMALL_SIZE, BLACK_DEFAULT_SIZE, t);
366 | }
367 | return ZERO_SIZE;
368 | }
369 |
370 | private float computeYellowSizeFraction(float ddt) {
371 | if (DrawableUtils.between(ddt, FRACTION_START, YELLOW_ENLARGE_FRACTION_START)) {
372 | return YELLOW_DEFAULT_SIZE;
373 | }
374 | if (DrawableUtils.between(ddt, YELLOW_ENLARGE_FRACTION_START, YELLOW_ENLARGE_FRACTION_END)) {
375 | float t = DrawableUtils.normalize(ddt, YELLOW_ENLARGE_FRACTION_START, YELLOW_ENLARGE_FRACTION_END);
376 | return DrawableUtils.enlarge(YELLOW_DEFAULT_SIZE, YELLOW_LARGE_SIZE, t);
377 | }
378 | if (DrawableUtils.between(ddt, YELLOW_ENLARGE_FRACTION_END, YELLOW_MEDIUM_ENLARGE_FRACTION_START)) {
379 | return ZERO_SIZE;
380 | }
381 | if (DrawableUtils.between(ddt, YELLOW_MEDIUM_ENLARGE_FRACTION_START, YELLOW_MEDIUM_ENLARGE_FRACTION_END)) {
382 | float t = DrawableUtils.normalize(ddt, YELLOW_MEDIUM_ENLARGE_FRACTION_START, YELLOW_MEDIUM_ENLARGE_FRACTION_END);
383 | return DrawableUtils.enlarge(ZERO_SIZE, YELLOW_DEFAULT_SIZE, t);
384 | }
385 | if (DrawableUtils.between(ddt, YELLOW_MEDIUM_ENLARGE_FRACTION_END, YELLOW_MEDIUM_REDUCE_FRACTION_START)) {
386 | return YELLOW_DEFAULT_SIZE;
387 | }
388 | if (DrawableUtils.between(ddt, YELLOW_MEDIUM_REDUCE_FRACTION_START, YELLOW_MEDIUM_REDUCE_FRACTION_END)) {
389 | float t = DrawableUtils.normalize(ddt, YELLOW_MEDIUM_REDUCE_FRACTION_START, YELLOW_MEDIUM_REDUCE_FRACTION_END);
390 | return DrawableUtils.reduce(YELLOW_DEFAULT_SIZE, ZERO_SIZE, t);
391 | }
392 | if (DrawableUtils.between(ddt, YELLOW_MEDIUM_REDUCE_FRACTION_END, YELLOW_RESTORE_FRACTION_START)) {
393 | return ZERO_SIZE;
394 | }
395 | if (DrawableUtils.between(ddt, YELLOW_RESTORE_FRACTION_START, YELLOW_RESTORE_FRACTION_END)) {
396 | float t = DrawableUtils.normalize(ddt, YELLOW_RESTORE_FRACTION_START, YELLOW_RESTORE_FRACTION_END);
397 | return DrawableUtils.enlarge(ZERO_SIZE, YELLOW_DEFAULT_SIZE, t);
398 | }
399 | return ZERO_SIZE;
400 | }
401 |
402 | @Override
403 | public void draw(@NonNull Canvas canvas) {
404 | float cx = getBounds().centerX();
405 | float cy = getBounds().centerY();
406 | canvas.drawCircle(cx, cy, width / 2f, getPaint());
407 | if (blackWidth > 0) {
408 | canvas.drawCircle(cx, cy, blackWidth / 2f, bgPaint);
409 | }
410 | if (yellowWidth > 0) {
411 | canvas.drawCircle(cx, cy, yellowWidth / 2f, yellowPaint);
412 | }
413 | }
414 | }
415 | }
416 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/ThirdLayer.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.graphics.RectF;
6 | import android.support.annotation.NonNull;
7 |
8 | /**
9 | * Third layer of animation.
10 | */
11 | class ThirdLayer extends Layer {
12 |
13 | private final DrawableObject[] objects;
14 |
15 | public ThirdLayer(Paint redPaint, Paint greenPaint, Paint bgPaint) {
16 | objects = new DrawableObject[3];
17 | objects[0] = new RedRing(redPaint, bgPaint);
18 | objects[1] = new GreenRing(greenPaint, bgPaint);
19 | objects[2] = new RedCircle(redPaint, bgPaint);
20 | }
21 |
22 | @Override
23 | public void update(@NonNull RectF bounds, float dt) {
24 | for (DrawableObject object : objects) {
25 | object.update(bounds, dt);
26 | }
27 | }
28 |
29 | @Override
30 | public void draw(@NonNull Canvas canvas) {
31 | for (DrawableObject object : objects) {
32 | object.draw(canvas);
33 | }
34 | }
35 |
36 | @Override
37 | public void reset() {
38 | for (DrawableObject object : objects) {
39 | if (object instanceof Resetable) {
40 | ((Resetable) object).reset();
41 | }
42 | }
43 | }
44 |
45 | private static final class GreenRing extends DrawableObjectImpl {
46 |
47 | private static final float SIZE_FRACTION = 0.75f;
48 | private static final float GREEN_DEFAULT_SIZE = 0.6f;
49 | private static final float GREEN_LARGE_SIZE = 0.8f;
50 | private static final float GREEN_SMALL_SIZE = 0.4f;
51 | private static final float BLACK_DEFAULT_SIZE = 0.3f;
52 | private static final float BLACK_LARGE_SIZE = 0.4f;
53 | private static final float BLACK_ARC_DEFAULT_SIZE = 0.5f;
54 | private static final float BLACK_ARC_SMALL_SIZE = 0f;
55 | private static final float START_ANGLE = -90;
56 | private static final float END_ANGLE = -480;
57 | private static final float START_SWEEP_ANGLE = 260;
58 | private static final float END_SWEEP_ANGLE = 360;
59 |
60 | private static final float BLACK_ENLARGE_FRACTION_START = 3 * Constants.FRAME_SPEED;
61 | private static final float BLACK_ENLARGE_FRACTION_END = 7 * Constants.FRAME_SPEED;
62 |
63 | private static final float GREEN_ENLARGE_FRACTION_START = 7 * Constants.FRAME_SPEED;
64 | private static final float GREEN_ENLARGE_FRACTION_END = 21 * Constants.FRAME_SPEED;
65 |
66 | private static final float SWITCH_TO_ARC_FRACTION = 58 * Constants.FRAME_SPEED;
67 |
68 | private static final float ARC_ROTATION_FRACTION_START = 64 * Constants.FRAME_SPEED;
69 | private static final float ARC_ROTATION_FRACTION_END = 106 * Constants.FRAME_SPEED;
70 |
71 | private static final float ARC_SIZE_CHANGE_FRACTION_START = 87 * Constants.FRAME_SPEED;
72 | private static final float ARC_SIZE_CHANGE_FRACTION_END = 106 * Constants.FRAME_SPEED;
73 |
74 | private static final float ARC_MERGING_FRACTION_START = 93 * Constants.FRAME_SPEED;
75 | private static final float ARC_MERGING_FRACTION_END = 109 * Constants.FRAME_SPEED;
76 |
77 | private static final float RESTORE_FRACTION_START = 136 * Constants.FRAME_SPEED;
78 | private static final float RESTORE_FRACTION_END = 150 * Constants.FRAME_SPEED;
79 |
80 | private Paint bgPaint;
81 | private float greenSize;
82 | private float blackSize;
83 | boolean drawArc;
84 | private final RectF rect;
85 | private float angle;
86 | private float sweepAngle;
87 |
88 | public GreenRing(Paint paint, Paint bgPaint) {
89 | super(paint);
90 | this.bgPaint = bgPaint;
91 | this.rect = new RectF();
92 | }
93 |
94 | @Override
95 | protected float getSizeFraction() {
96 | return SIZE_FRACTION;
97 | }
98 |
99 | @Override
100 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
101 | greenSize = computeGreenSizeFraction(ddt) * getBounds().width();
102 | blackSize = computeBlackSizeFraction(ddt) * getBounds().width();
103 | if (drawArc) {
104 | float cx = getBounds().centerX();
105 | float cy = getBounds().centerY();
106 | float halfSize = greenSize / 2f;
107 | rect.set(cx - halfSize, cy - halfSize, cx + halfSize, cy + halfSize);
108 | if (ddt <= ARC_ROTATION_FRACTION_START)
109 | angle = START_ANGLE;
110 | else if (ddt >= ARC_ROTATION_FRACTION_END)
111 | angle = END_ANGLE;
112 | if (ddt <= ARC_MERGING_FRACTION_START)
113 | sweepAngle = START_SWEEP_ANGLE;
114 | else if (ddt >= ARC_MERGING_FRACTION_END)
115 | sweepAngle = END_SWEEP_ANGLE;
116 | if (DrawableUtils.between(ddt, ARC_ROTATION_FRACTION_START, ARC_ROTATION_FRACTION_END)) {
117 | float t = DrawableUtils.normalize(ddt, ARC_ROTATION_FRACTION_START, ARC_ROTATION_FRACTION_END);
118 | angle = START_ANGLE + t * (END_ANGLE - START_ANGLE);
119 | }
120 | if (DrawableUtils.between(ddt, ARC_MERGING_FRACTION_START, ARC_MERGING_FRACTION_END)) {
121 | float t = DrawableUtils.normalize(ddt, ARC_MERGING_FRACTION_START, ARC_MERGING_FRACTION_END);
122 | sweepAngle = START_SWEEP_ANGLE + t * (END_SWEEP_ANGLE - START_SWEEP_ANGLE);
123 | }
124 | }
125 | }
126 |
127 | private float computeBlackSizeFraction(float ddt) {
128 | if (DrawableUtils.between(ddt, Constants.FIRST_FRAME_FRACTION, BLACK_ENLARGE_FRACTION_START)) {
129 | return 0;
130 | }
131 | if (DrawableUtils.between(ddt, BLACK_ENLARGE_FRACTION_START, BLACK_ENLARGE_FRACTION_END)) {
132 | float t = DrawableUtils.normalize(ddt, BLACK_ENLARGE_FRACTION_START, BLACK_ENLARGE_FRACTION_END);
133 | return DrawableUtils.enlarge(BLACK_DEFAULT_SIZE, BLACK_LARGE_SIZE, t);
134 | }
135 | if (DrawableUtils.between(ddt, BLACK_ENLARGE_FRACTION_END, GREEN_ENLARGE_FRACTION_END)) {
136 | return BLACK_LARGE_SIZE;
137 | }
138 | if (DrawableUtils.between(ddt, SWITCH_TO_ARC_FRACTION, ARC_SIZE_CHANGE_FRACTION_START)) {
139 | return BLACK_ARC_DEFAULT_SIZE;
140 | }
141 | if (DrawableUtils.between(ddt, ARC_SIZE_CHANGE_FRACTION_START, ARC_SIZE_CHANGE_FRACTION_END)) {
142 | float t = DrawableUtils.normalize(ddt, ARC_SIZE_CHANGE_FRACTION_START, ARC_SIZE_CHANGE_FRACTION_END);
143 | return DrawableUtils.reduce(BLACK_ARC_DEFAULT_SIZE, BLACK_ARC_SMALL_SIZE, t);
144 | }
145 | return 0;
146 | }
147 |
148 | private float computeGreenSizeFraction(float ddt) {
149 | drawArc = ddt >= SWITCH_TO_ARC_FRACTION;
150 | if (DrawableUtils.between(ddt, Constants.FIRST_FRAME_FRACTION, GREEN_ENLARGE_FRACTION_START)) {
151 | return GREEN_DEFAULT_SIZE;
152 | }
153 | if (DrawableUtils.between(ddt, GREEN_ENLARGE_FRACTION_START, GREEN_ENLARGE_FRACTION_END)) {
154 | float t = DrawableUtils.normalize(ddt, GREEN_ENLARGE_FRACTION_START, GREEN_ENLARGE_FRACTION_END);
155 | return DrawableUtils.enlarge(GREEN_DEFAULT_SIZE, GREEN_LARGE_SIZE, t);
156 | }
157 | if (DrawableUtils.between(ddt, GREEN_ENLARGE_FRACTION_END, ARC_SIZE_CHANGE_FRACTION_START)) {
158 | return GREEN_LARGE_SIZE;
159 | }
160 | if (DrawableUtils.between(ddt, ARC_SIZE_CHANGE_FRACTION_START, ARC_SIZE_CHANGE_FRACTION_END)) {
161 | float t = DrawableUtils.normalize(ddt, ARC_SIZE_CHANGE_FRACTION_START, ARC_SIZE_CHANGE_FRACTION_END);
162 | return DrawableUtils.reduce(GREEN_LARGE_SIZE, GREEN_SMALL_SIZE, t);
163 | }
164 | if (DrawableUtils.between(ddt, ARC_SIZE_CHANGE_FRACTION_END, RESTORE_FRACTION_START)) {
165 | return GREEN_SMALL_SIZE;
166 | }
167 | if (DrawableUtils.between(ddt, RESTORE_FRACTION_START, RESTORE_FRACTION_END)) {
168 | float t = DrawableUtils.normalize(ddt, RESTORE_FRACTION_START, RESTORE_FRACTION_END);
169 | return DrawableUtils.enlarge(GREEN_SMALL_SIZE, GREEN_DEFAULT_SIZE, t);
170 | }
171 | return GREEN_DEFAULT_SIZE;
172 | }
173 |
174 | @Override
175 | public void draw(@NonNull Canvas canvas) {
176 | if (drawArc) {
177 | canvas.drawArc(rect, angle, sweepAngle, true, getPaint());
178 | } else {
179 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), greenSize / 2f, getPaint());
180 | }
181 | if (blackSize > 0) {
182 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), blackSize / 2f, bgPaint);
183 | }
184 | }
185 | }
186 |
187 | private static final class RedRing extends DrawableObjectImpl {
188 |
189 | private static final float SIZE_FRACTION = 0.75f;
190 | private static final float START_ANGLE = 0;
191 | private static final float END_ANGLE = 580;
192 | private static final float SWEEP_START_ANGLE = 0;
193 | private static final float SWEEP_END_ANGLE = 410;
194 | private static final float RED_DEFAULT_SIZE = 0.7f;
195 | private static final float RED_SMALL_SIZE = 0.4f;
196 | private static final float BLACK_DEFAULT_SIZE = RED_DEFAULT_SIZE - 0.1f;
197 | private static final float BLACK_SMALL_SIZE = RED_SMALL_SIZE - 0.1f;
198 |
199 | private static final float ROTATION_FRACTION_START = 90 * Constants.FRAME_SPEED;
200 | private static final float ROTATION_FRACTION_END = 134 * Constants.FRAME_SPEED;
201 |
202 | private static final float SIZE_CHANGE_FRACTION_START = 134 * Constants.FRAME_SPEED;
203 | private static final float SIZE_CHANGE_FRACTION_END = 145 * Constants.FRAME_SPEED;
204 |
205 | private Paint bgPaint;
206 | private float redSize;
207 | private float blackSize;
208 | private float angle;
209 | private float sweepAngle;
210 | private RectF rect;
211 |
212 | public RedRing(Paint paint, Paint bgPaint) {
213 | super(paint);
214 | this.bgPaint = bgPaint;
215 | this.rect = new RectF();
216 | }
217 |
218 | @Override
219 | protected float getSizeFraction() {
220 | return SIZE_FRACTION;
221 | }
222 |
223 | @Override
224 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
225 | redSize = computeRedSizeFraction(ddt) * getBounds().width();
226 | blackSize = computeBlackSizeFraction(ddt) * getBounds().width();
227 | if (ddt <= ROTATION_FRACTION_START) {
228 | angle = START_ANGLE;
229 | sweepAngle = SWEEP_START_ANGLE;
230 | } else if (ddt >= ROTATION_FRACTION_END) {
231 | angle = END_ANGLE;
232 | sweepAngle = SWEEP_END_ANGLE;
233 | } else {
234 | float t = DrawableUtils.normalize(ddt, ROTATION_FRACTION_START, ROTATION_FRACTION_END);
235 | angle = START_ANGLE + t * (END_ANGLE - START_ANGLE);
236 | sweepAngle = SWEEP_START_ANGLE + t * (SWEEP_END_ANGLE - SWEEP_START_ANGLE);
237 | }
238 | if (redSize > 0) {
239 | float cx = getBounds().centerX();
240 | float cy = getBounds().centerY();
241 | float halfSize = redSize / 2f;
242 | rect.set(cx - halfSize, cy - halfSize, cx + halfSize, cy + halfSize);
243 | }
244 | }
245 |
246 | private float computeBlackSizeFraction(float ddt) {
247 | if (DrawableUtils.between(ddt, Constants.FIRST_FRAME_FRACTION, ROTATION_FRACTION_START)) {
248 | return 0;
249 | }
250 | if (DrawableUtils.between(ddt, ROTATION_FRACTION_START, ROTATION_FRACTION_END)) {
251 | return BLACK_DEFAULT_SIZE;
252 | }
253 | if (DrawableUtils.between(ddt, SIZE_CHANGE_FRACTION_START, SIZE_CHANGE_FRACTION_END)) {
254 | float t = DrawableUtils.normalize(ddt, SIZE_CHANGE_FRACTION_START, SIZE_CHANGE_FRACTION_END);
255 | return DrawableUtils.reduce(BLACK_DEFAULT_SIZE, BLACK_SMALL_SIZE, t);
256 | }
257 | return 0;
258 | }
259 |
260 | private float computeRedSizeFraction(float ddt) {
261 | if (DrawableUtils.between(ddt, Constants.FIRST_FRAME_FRACTION, ROTATION_FRACTION_START)) {
262 | return 0;
263 | }
264 | if (DrawableUtils.between(ddt, ROTATION_FRACTION_START, ROTATION_FRACTION_END)) {
265 | return RED_DEFAULT_SIZE;
266 | }
267 | if (DrawableUtils.between(ddt, SIZE_CHANGE_FRACTION_START, SIZE_CHANGE_FRACTION_END)) {
268 | float t = DrawableUtils.normalize(ddt, SIZE_CHANGE_FRACTION_START, SIZE_CHANGE_FRACTION_END);
269 | return DrawableUtils.reduce(RED_DEFAULT_SIZE, RED_SMALL_SIZE, t);
270 | }
271 | return 0;
272 | }
273 |
274 | @Override
275 | public void draw(@NonNull Canvas canvas) {
276 | if (redSize > 0) {
277 | canvas.drawArc(rect, angle, sweepAngle, true, getPaint());
278 | }
279 | if (blackSize > 0) {
280 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), blackSize / 2f, bgPaint);
281 | }
282 | }
283 | }
284 |
285 | private static final class RedCircle extends DrawableObjectImpl {
286 |
287 | private static final float SIZE_FRACTION = 0.75f;
288 | private static final float RED_DEFAULT_SIZE = 0.3f;
289 | private static final float RED_LARGER_SIZE = 0.4f;
290 | private static final float RED_LARGEST_SIZE = 0.8f;
291 | private static final float BLACK_DEFAULT_SIZE = 0;
292 | private static final float BLACK_LARGE_SIZE = 0.4f;
293 |
294 |
295 | private static final float ENLARGE_1_FRACTION_START = 4 * Constants.FRAME_SPEED;
296 | private static final float ENLARGE_1_FRACTION_END = 15 * Constants.FRAME_SPEED;
297 |
298 | private static final float ENLARGE_2_FRACTION_START = 17 * Constants.FRAME_SPEED;
299 | private static final float ENLARGE_2_FRACTION_END = 30 * Constants.FRAME_SPEED;
300 |
301 | private static final float BLACK_ENLARGE_FRACTION_START = 19 * Constants.FRAME_SPEED;
302 | private static final float BLACK_ENLARGE_FRACTION_END = 30 * Constants.FRAME_SPEED;
303 |
304 | private static final float VISIBILITY_FRACTION = 39 * Constants.FRAME_SPEED;
305 |
306 | private static final float ENLARGE_3_FRACTION_START = 144 * Constants.FRAME_SPEED;
307 | private static final float ENLARGE_3_FRACTION_END = Constants.LAST_FRAME_FRACTION;
308 |
309 | private Paint bgPaint;
310 | private float redSize;
311 | private float blackSize;
312 |
313 | public RedCircle(Paint paint, Paint bgPaint) {
314 | super(paint);
315 | this.bgPaint = bgPaint;
316 | }
317 |
318 | @Override
319 | protected float getSizeFraction() {
320 | return SIZE_FRACTION;
321 | }
322 |
323 | @Override
324 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
325 | redSize = computeRedSizeFraction(ddt) * getBounds().width();
326 | blackSize = computeBlackSizeFraction(ddt) * getBounds().width();
327 | }
328 |
329 | private float computeBlackSizeFraction(float ddt) {
330 | if (DrawableUtils.between(ddt, BLACK_ENLARGE_FRACTION_START, BLACK_ENLARGE_FRACTION_END)) {
331 | float t = DrawableUtils.normalize(ddt, BLACK_ENLARGE_FRACTION_START, BLACK_ENLARGE_FRACTION_END);
332 | return DrawableUtils.enlarge(BLACK_DEFAULT_SIZE, BLACK_LARGE_SIZE, t);
333 | }
334 | if (DrawableUtils.between(ddt, BLACK_ENLARGE_FRACTION_END, VISIBILITY_FRACTION)) {
335 | return BLACK_LARGE_SIZE;
336 | }
337 | return BLACK_DEFAULT_SIZE;
338 | }
339 |
340 | private float computeRedSizeFraction(float ddt) {
341 | if (DrawableUtils.between(ddt, Constants.FIRST_FRAME_FRACTION, ENLARGE_1_FRACTION_START)) {
342 | return RED_DEFAULT_SIZE;
343 | }
344 | if (DrawableUtils.between(ddt, ENLARGE_1_FRACTION_START, ENLARGE_1_FRACTION_END)) {
345 | float t = DrawableUtils.normalize(ddt, ENLARGE_1_FRACTION_START, ENLARGE_1_FRACTION_END);
346 | return DrawableUtils.enlarge(RED_DEFAULT_SIZE, RED_LARGER_SIZE, t);
347 | }
348 | if (DrawableUtils.between(ddt, ENLARGE_1_FRACTION_END, ENLARGE_2_FRACTION_START)) {
349 | return RED_LARGER_SIZE;
350 | }
351 | if (DrawableUtils.between(ddt, ENLARGE_2_FRACTION_START, ENLARGE_2_FRACTION_END)) {
352 | float t = DrawableUtils.normalize(ddt, ENLARGE_2_FRACTION_START, ENLARGE_2_FRACTION_END);
353 | return DrawableUtils.enlarge(RED_LARGER_SIZE, RED_LARGEST_SIZE, t);
354 | }
355 | if (DrawableUtils.between(ddt, ENLARGE_2_FRACTION_END, VISIBILITY_FRACTION)) {
356 | return RED_LARGEST_SIZE;
357 | }
358 | if (DrawableUtils.between(ddt, VISIBILITY_FRACTION, ENLARGE_3_FRACTION_START)) {
359 | return 0;
360 | }
361 | if (DrawableUtils.between(ddt, ENLARGE_3_FRACTION_START, ENLARGE_3_FRACTION_END)) {
362 | float t = DrawableUtils.normalize(ddt, ENLARGE_3_FRACTION_START, ENLARGE_3_FRACTION_END);
363 | return DrawableUtils.enlarge(0, RED_DEFAULT_SIZE, t);
364 | }
365 | return 0;
366 | }
367 |
368 | @Override
369 | public void draw(@NonNull Canvas canvas) {
370 | if (redSize > 0) {
371 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), redSize / 2f, getPaint());
372 | }
373 | if (blackSize > 0) {
374 | canvas.drawCircle(getBounds().centerX(), getBounds().centerY(), blackSize / 2f, bgPaint);
375 | }
376 | }
377 | }
378 | }
379 |
--------------------------------------------------------------------------------
/library/src/main/java/com/cleveroad/androidmanimation/YellowRectangle.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.graphics.RectF;
6 | import android.support.annotation.NonNull;
7 |
8 | /**
9 | * Yellow rounded rectangle class.
10 | */
11 | final class YellowRectangle extends DrawableObjectImpl {
12 |
13 |
14 | private static final float SIZE_FRACTION = 0.6f;
15 |
16 | private static final float VISIBILITY_FRACTION_START = 16 * Constants.FRAME_SPEED;
17 | private static final float VISIBILITY_FRACTION_END = 137 * Constants.FRAME_SPEED;
18 |
19 | private static final float ENLARGE_FRACTION_START = 19 * Constants.FRAME_SPEED;
20 | private static final float ENLARGE_FRACTION_END = 36 * Constants.FRAME_SPEED;
21 |
22 | private static final float REDUCE_FRACTION_1_START = 36 * Constants.FRAME_SPEED;
23 | private static final float REDUCE_FRACTION_1_END = 56 * Constants.FRAME_SPEED;
24 |
25 | private static final float SWAP_FRACTION = 58 * Constants.FRAME_SPEED;
26 |
27 | private static final float REDUCE_FRACTION_2_START = 58 * Constants.FRAME_SPEED;
28 | private static final float REDUCE_FRACTION_2_END = 70 * Constants.FRAME_SPEED;
29 |
30 | private static final float REDUCE_FRACTION_3_START = 90 * Constants.FRAME_SPEED;
31 | private static final float REDUCE_FRACTION_3_END = 130 * Constants.FRAME_SPEED;
32 |
33 | private static final float REDUCE_FRACTION_4_START = 131 * Constants.FRAME_SPEED;
34 | private static final float REDUCE_FRACTION_4_END = 137 * Constants.FRAME_SPEED;
35 |
36 | private static final float MOVEMENT_FRACTION_START = 79 * Constants.FRAME_SPEED;
37 | private static final float MOVEMENT_FRACTION_END = 130 * Constants.FRAME_SPEED;
38 |
39 | private static final float START_ANGLE = (float) (Math.PI / 2);
40 | private static final float END_ANGLE = (float) (2.5 * Math.PI);
41 |
42 | private static final float SMALLEST_SIZE = 0.6f;
43 | private static final float SMALL_SIZE = 0.7f;
44 |
45 | private float cx1, cy1, cx2, cy2, cx3, cy3;
46 | private RectF rect;
47 | private boolean draw;
48 | private float radius;
49 | private boolean drawCircle;
50 | private float cx, cy;
51 |
52 | public YellowRectangle(Paint paint) {
53 | super(paint);
54 | this.rect = new RectF();
55 | }
56 |
57 | @Override
58 | protected float getSizeFraction() {
59 | return SIZE_FRACTION;
60 | }
61 |
62 | public void setFirstValues(float cx1, float cy1) {
63 | this.cx1 = cx1;
64 | this.cy1 = cy1;
65 | }
66 |
67 | public void setSecondValues(float cx2, float cy2) {
68 | this.cx2 = cx2;
69 | this.cy2 = cy2;
70 | }
71 |
72 | public void setThirdValues(float cx3, float cy3) {
73 | this.cx3 = cx3;
74 | this.cy3 = cy3;
75 | }
76 |
77 | public void updateRadius(float size) {
78 | this.radius = size * SIZE_FRACTION / 2f;
79 | }
80 |
81 | @Override
82 | protected void updateImpl(@NonNull RectF bounds, float ddt) {
83 | draw = DrawableUtils.between(ddt, VISIBILITY_FRACTION_START, VISIBILITY_FRACTION_END);
84 | if (!draw) {
85 | return;
86 | }
87 | drawCircle = ddt >= SWAP_FRACTION;
88 | if (DrawableUtils.between(ddt, VISIBILITY_FRACTION_START, ENLARGE_FRACTION_END)) {
89 | float l, r, t, b;
90 | l = cx1 - radius;
91 | t = cy1 - radius;
92 | r = cx1 + radius;
93 | b = cy1 + radius;
94 | if (ddt >= ENLARGE_FRACTION_START) {
95 | float time = DrawableUtils.normalize(ddt, ENLARGE_FRACTION_START, ENLARGE_FRACTION_END);
96 | r = DrawableUtils.enlarge(r, r + (cx2 - cx1), time);
97 | }
98 | rect.set(l, t, r, b);
99 | }
100 | if (DrawableUtils.between(ddt, REDUCE_FRACTION_1_START, REDUCE_FRACTION_1_END)) {
101 | float l, r, t, b;
102 | l = cx2 - radius;
103 | t = cy2 - radius;
104 | r = cx2 + radius;
105 | b = cy2 + radius;
106 | float time = DrawableUtils.normalize(ddt, REDUCE_FRACTION_1_START, REDUCE_FRACTION_1_END);
107 | l = DrawableUtils.enlarge(l - (cx2 - cx1), l, time);
108 | rect.set(l, t, r, b);
109 | }
110 | if (drawCircle) {
111 | cx = cx2;
112 | cy = cy2;
113 | rect.set(0, 0, radius * 2, radius * 2);
114 | if (DrawableUtils.between(ddt, REDUCE_FRACTION_2_START, REDUCE_FRACTION_2_END)) {
115 | float t = DrawableUtils.normalize(ddt, REDUCE_FRACTION_2_START, REDUCE_FRACTION_2_END);
116 | float size = DrawableUtils.reduce(radius * 2, radius * SMALL_SIZE, t);
117 | rect.set(0, 0, size, size);
118 | }
119 | if (DrawableUtils.between(ddt, REDUCE_FRACTION_2_END,REDUCE_FRACTION_3_START)) {
120 | rect.set(0, 0, radius * SMALL_SIZE, radius * SMALL_SIZE);
121 | }
122 | if (DrawableUtils.between(ddt, REDUCE_FRACTION_3_START, REDUCE_FRACTION_3_END)) {
123 | float t = DrawableUtils.normalize(ddt, REDUCE_FRACTION_3_START, REDUCE_FRACTION_3_END);
124 | float size = DrawableUtils.reduce(radius * SMALL_SIZE, radius * SMALLEST_SIZE, t);
125 | rect.set(0, 0, size, size);
126 | }
127 | if (DrawableUtils.between(ddt, REDUCE_FRACTION_3_END, REDUCE_FRACTION_4_START)) {
128 | rect.set(0, 0, radius * SMALLEST_SIZE, radius * SMALLEST_SIZE);
129 | }
130 | if (DrawableUtils.between(ddt, REDUCE_FRACTION_4_START, REDUCE_FRACTION_4_END)) {
131 | float t = DrawableUtils.normalize(ddt, REDUCE_FRACTION_4_START, REDUCE_FRACTION_4_END);
132 | float size = DrawableUtils.reduce(radius * SMALLEST_SIZE, 0, t);
133 | rect.set(0, 0, size, size);
134 | }
135 | if (DrawableUtils.between(ddt, MOVEMENT_FRACTION_START, MOVEMENT_FRACTION_END)) {
136 | float t = DrawableUtils.normalize(ddt, MOVEMENT_FRACTION_START, MOVEMENT_FRACTION_END);
137 | float height = getBounds().height() / 2f;
138 | float cos = (float) Math.sin(START_ANGLE + t * (END_ANGLE - START_ANGLE));
139 | cx = cx2 + t * (cx3 - cx2);
140 | cy = cy2 + height * (1 - Math.abs(cos));
141 | } else if (ddt >= MOVEMENT_FRACTION_END) {
142 | cx = cx3;
143 | cy = cy3;
144 | }
145 | }
146 | }
147 |
148 | @Override
149 | public void draw(@NonNull Canvas canvas) {
150 | if (draw) {
151 | if (drawCircle) {
152 | canvas.drawCircle(cx, cy, rect.width() / 2f, getPaint());
153 | } else {
154 | canvas.drawRoundRect(rect, radius, radius, getPaint());
155 | }
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/lav_view_loading_animation.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/library/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3469e9
4 | #d20d24
5 | #009924
6 | #eeb110
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values/public.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Android M Animation Library
3 |
4 |
--------------------------------------------------------------------------------
/library/src/test/java/com/cleveroad/androidmanimation/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.cleveroad.androidmanimation;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library'
2 |
--------------------------------------------------------------------------------