├── .gitignore
├── .idea
└── copyright
│ └── profiles_settings.xml
├── 365.gif
├── README.md
├── build.gradle
├── demo.apk
├── demo
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── kurt
│ │ └── demo
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── example
│ │ └── kurt
│ │ └── demo
│ │ ├── Determinate.java
│ │ ├── Indeterminate.java
│ │ ├── MainActivity.java
│ │ └── ProgressHelper.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_fab_play.png
│ ├── layout
│ ├── activity_main.xml
│ ├── card.xml
│ ├── determinate.xml
│ └── indeterminate.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── example.gif
├── fabbutton
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── mbanje
│ │ └── kurt
│ │ └── fabbutton
│ │ ├── AnimationUtils.java
│ │ ├── CircleImageView.java
│ │ ├── FabButton.java
│ │ ├── FabUtil.java
│ │ ├── ProgressRingView.java
│ │ ├── ViewGroupUtils.java
│ │ └── ViewGroupUtilsHoneycomb.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_fab_complete.png
│ ├── drawable-mdpi
│ └── ic_fab_complete.png
│ ├── drawable-xhdpi
│ └── ic_fab_complete.png
│ ├── drawable-xxhdpi
│ └── ic_fab_complete.png
│ ├── layout
│ └── widget_fab_button.xml
│ └── values
│ ├── attrs.xml
│ └── dimens.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /.idea
8 | *.iml
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/365.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckurtm/FabButton/cd12dee2890c7b0efdc5d21ae4ddffa4bc1aa8ea/365.gif
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## FabProgress
2 | Android Circular floating action button with intergrated progress indicator ring
3 | [As per material design docs](http://www.google.com/design/spec/components/progress-activity.html#progress-activity-types-of-indicators)
4 |
5 | ## Demo:
6 |
7 | [Demo apk](demo.apk)
8 |
9 | 
10 | 
11 |
12 | ## HOW TO ADD TO YOUR PROJECT
13 | [  ](https://bintray.com/ckurtm/maven/FabButton/_latestVersion)
14 |
15 | Gradle:
16 | ```groovy
17 | dependencies {
18 | compile 'mbanje.kurt:fabbutton:1.2.4@aar'
19 | }
20 | ```
21 |
22 | ## Usage
23 |
24 | - Use FabButton: (check the demo app included)
25 | ```xml
26 |
44 | ```
45 | ## Apps using library
46 |
47 | [![alt text][2]][1]
48 |
49 | [1]: https://play.google.com/store/apps/details?id=com.peirr.workout.play
50 | [2]: https://developer.android.com/images/brand/en_app_rgb_wo_45.png (365 Body workout)
51 |
52 | ## License
53 |
54 | The MIT License (MIT)
55 |
56 | Permission is hereby granted, free of charge, to any person obtaining a copy
57 | of this software and associated documentation files (the "Software"), to deal
58 | in the Software without restriction, including without limitation the rights
59 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
60 | copies of the Software, and to permit persons to whom the Software is
61 | furnished to do so, subject to the following conditions:
62 |
63 | The above copyright notice and this permission notice shall be included in
64 | all copies or substantial portions of the Software.
65 |
66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
67 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
68 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
69 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
70 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
71 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
72 | THE SOFTWARE.
73 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.compileVersion = 26
5 | ext.targetVersion = 26
6 | ext.toolsVersion = '26.0.1'
7 |
8 | ext.googleLibraryVersion = '26.1.0'
9 |
10 | repositories {
11 | jcenter()
12 | mavenCentral()
13 | google()
14 | }
15 | dependencies {
16 | classpath 'com.android.tools.build:gradle:3.0.0-beta6'
17 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
18 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
19 | }
20 | }
21 |
22 | allprojects {
23 | repositories {
24 | jcenter()
25 | google()
26 | }
27 | }
--------------------------------------------------------------------------------
/demo.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckurtm/FabButton/cd12dee2890c7b0efdc5d21ae4ddffa4bc1aa8ea/demo.apk
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion compileVersion
5 | buildToolsVersion toolsVersion
6 |
7 | defaultConfig {
8 | applicationId "com.mbanje.fabprogress"
9 | minSdkVersion 16
10 | targetSdkVersion targetVersion
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 |
16 | debug {
17 | minifyEnabled false
18 | }
19 |
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation "com.android.support:appcompat-v7:${googleLibraryVersion}"
29 | implementation "com.android.support:design:${googleLibraryVersion}"
30 | implementation "com.android.support:cardview-v7:${googleLibraryVersion}"
31 | implementation project(':fabbutton')
32 | // compile 'mbanje.kurt:fabbutton:1.2.4@aar'
33 | }
34 |
--------------------------------------------------------------------------------
/demo/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 /usr/local/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 |
--------------------------------------------------------------------------------
/demo/src/androidTest/java/com/example/kurt/demo/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.example.kurt.demo;
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 | }
--------------------------------------------------------------------------------
/demo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
24 |
25 |
28 |
29 |
32 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/example/kurt/demo/Determinate.java:
--------------------------------------------------------------------------------
1 | package com.example.kurt.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.design.widget.CollapsingToolbarLayout;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.support.v7.widget.Toolbar;
7 | import android.view.View;
8 |
9 | import mbanje.kurt.fabbutton.FabButton;
10 |
11 | /**
12 | * Created by kurt on 08 06 2015 .
13 | */
14 | public class Determinate extends AppCompatActivity {
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.determinate);
20 | final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
21 | final FabButton button = (FabButton) findViewById(R.id.determinate);
22 |
23 | setSupportActionBar(toolbar);
24 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
25 |
26 | CollapsingToolbarLayout collapsingToolbar =
27 | (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
28 | collapsingToolbar.setTitle("Determinate");
29 |
30 | final ProgressHelper helper = new ProgressHelper(button,this);
31 |
32 | button.setOnClickListener(new View.OnClickListener() {
33 | @Override
34 | public void onClick(View v) {
35 | helper.startDeterminate();
36 | }
37 | });
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/example/kurt/demo/Indeterminate.java:
--------------------------------------------------------------------------------
1 | package com.example.kurt.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.design.widget.CollapsingToolbarLayout;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.support.v7.widget.Toolbar;
7 | import android.view.View;
8 |
9 | import mbanje.kurt.fabbutton.FabButton;
10 |
11 | /**
12 | * Created by kurt on 08 06 2015 .
13 | */
14 | public class Indeterminate extends AppCompatActivity {
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.indeterminate);
20 | final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
21 | final FabButton button = (FabButton) findViewById(R.id.determinate);
22 | setSupportActionBar(toolbar);
23 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
24 |
25 | CollapsingToolbarLayout collapsingToolbar =
26 | (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
27 | collapsingToolbar.setTitle("Indeterminate");
28 |
29 | final ProgressHelper helper = new ProgressHelper(button,this);
30 |
31 | button.setOnClickListener(new View.OnClickListener() {
32 | @Override
33 | public void onClick(View v) {
34 | helper.startIndeterminate();
35 | }
36 | });
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/example/kurt/demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.kurt.demo;
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 |
9 | public class MainActivity extends AppCompatActivity {
10 |
11 | @Override
12 | protected void onCreate(Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | setContentView(R.layout.activity_main);
15 |
16 | findViewById(R.id.determinate).setOnClickListener(new View.OnClickListener() {
17 | @Override
18 | public void onClick(View v) {
19 | startActivity(new Intent(MainActivity.this,Determinate.class));
20 | }
21 | });
22 |
23 | findViewById(R.id.indeterminate).setOnClickListener(new View.OnClickListener() {
24 | @Override
25 | public void onClick(View v) {
26 | startActivity(new Intent(MainActivity.this, Indeterminate.class));
27 | }
28 | });
29 |
30 |
31 | }
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/example/kurt/demo/ProgressHelper.java:
--------------------------------------------------------------------------------
1 | package com.example.kurt.demo;
2 |
3 | import android.app.Activity;
4 | import android.os.Handler;
5 |
6 | import mbanje.kurt.fabbutton.FabButton;
7 |
8 | /**
9 | * Created by kurt on 08 06 2015 .
10 | */
11 | public class ProgressHelper {
12 |
13 | private int currentProgress = 0;
14 | private Handler handle=new Handler();
15 | private final FabButton button;
16 | private final Activity activity;
17 |
18 | public ProgressHelper(FabButton button, Activity activity) {
19 | this.button = button;
20 | this.activity = activity;
21 | }
22 |
23 | private Runnable getRunnable(final Activity activity){
24 | return new Runnable() {
25 | @Override
26 | public void run() {
27 | currentProgress += 1;
28 | activity.runOnUiThread(new Runnable() {
29 | @Override
30 | public void run() {
31 | button.setProgress(currentProgress);
32 | if(currentProgress <= 100){
33 | handle.postDelayed(getRunnable(activity),50);
34 | }
35 | }
36 | });
37 | }
38 | };
39 | }
40 |
41 | public void startIndeterminate() {
42 | button.showProgress(true);
43 | }
44 |
45 | public void startDeterminate() {
46 | button.resetIcon();
47 | button.showShadow(false);
48 | currentProgress = 0;
49 | button.showProgress(true);
50 | button.setProgress(currentProgress);
51 | getRunnable(activity).run();
52 | }
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/ic_fab_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckurtm/FabButton/cd12dee2890c7b0efdc5d21ae4ddffa4bc1aa8ea/demo/src/main/res/drawable-hdpi/ic_fab_play.png
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
24 |
25 |
30 |
31 |
39 |
40 |
48 |
49 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/card.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/determinate.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
31 |
32 |
41 |
42 |
49 |
50 |
56 |
57 |
58 |
59 |
60 |
61 |
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
104 |
105 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/indeterminate.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
31 |
32 |
41 |
42 |
49 |
50 |
56 |
57 |
58 |
59 |
60 |
61 |
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
103 |
104 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFF5F5F5
4 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | FabButton
3 | Determinate
4 | Indeterminate
5 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
13 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckurtm/FabButton/cd12dee2890c7b0efdc5d21ae4ddffa4bc1aa8ea/example.gif
--------------------------------------------------------------------------------
/fabbutton/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/fabbutton/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2015 Kurt Mbanje
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | apply plugin: 'com.android.library'
25 | apply plugin: 'com.github.dcendents.android-maven'
26 | apply plugin: 'com.jfrog.bintray'
27 |
28 | def groupName = "mbanje.kurt"
29 | def siteUrl = 'https://github.com/ckurtm/FabButton'
30 | def gitUrl = 'https://github.com/ckurtm/FabButton.git'
31 |
32 | version = "1.2.5"
33 | group = 'mbanje.kurt'
34 |
35 | Properties properties = new Properties()
36 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
37 |
38 | android {
39 | compileSdkVersion compileVersion
40 | buildToolsVersion toolsVersion
41 |
42 | lintOptions {
43 | abortOnError false
44 | }
45 |
46 | defaultConfig {
47 | minSdkVersion 14
48 | targetSdkVersion targetVersion
49 | versionCode 11
50 | versionName version
51 | }
52 | buildTypes {
53 | release {
54 | minifyEnabled false
55 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
56 | }
57 | }
58 | }
59 |
60 | bintray {
61 | user = properties.getProperty("bintray.user")
62 | key = properties.getProperty("bintray.key")
63 | configurations = ['archives']
64 | pkg {
65 | repo = "maven"
66 | name = "FabButton"
67 | websiteUrl = siteUrl
68 | vcsUrl = gitUrl
69 | licenses = ["Apache-2.0"]
70 | publicDownloadNumbers = true
71 |
72 | }
73 | }
74 |
75 | install {
76 | repositories.mavenInstaller {
77 | pom.project {
78 | description 'Android Floating ActionButton with a progress indicator ring'
79 | name "FabButton"
80 | url siteUrl
81 | inceptionYear '2015'
82 | packaging 'aar'
83 | licenses {
84 | license {
85 | name 'The MIT License (MIT)'
86 | url 'https://opensource.org/licenses/MIT'
87 | }
88 | }
89 | scm {
90 | connection gitUrl
91 | url siteUrl
92 |
93 | }
94 | developers {
95 | developer {
96 | name 'Kurt Mbanje'
97 | }
98 | }
99 | }
100 | }
101 | }
102 |
103 | dependencies {
104 | implementation "com.android.support:design:$googleLibraryVersion"
105 | }
106 |
107 | task sourcesJar(type: Jar) {
108 | from android.sourceSets.main.java.srcDirs
109 | classifier = 'sources'
110 | }
111 |
112 | task javadoc(type: Javadoc) {
113 | source = android.sourceSets.main.java.srcDirs
114 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
115 | }
116 |
117 | task javadocJar(type: Jar, dependsOn: javadoc) {
118 | classifier = 'javadoc'
119 | from javadoc.destinationDir
120 | }
121 | artifacts {
122 | archives javadocJar
123 | archives sourcesJar
124 | }
125 |
126 | task findConventions << {
127 | println project.getConvention()
128 | }
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/fabbutton/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 /usr/local/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 |
--------------------------------------------------------------------------------
/fabbutton/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/fabbutton/src/main/java/mbanje/kurt/fabbutton/AnimationUtils.java:
--------------------------------------------------------------------------------
1 | package mbanje.kurt.fabbutton;
2 |
3 | import android.support.v4.view.animation.FastOutSlowInInterpolator;
4 | import android.view.animation.Animation;
5 | import android.view.animation.DecelerateInterpolator;
6 | import android.view.animation.Interpolator;
7 | import android.view.animation.LinearInterpolator;
8 |
9 | /**
10 | * Created by kurt on 2015/06/08.
11 | */
12 | public class AnimationUtils {
13 | public static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
14 | public static final Interpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();
15 | public static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
16 |
17 | AnimationUtils() {
18 | }
19 |
20 | static float lerp(float startValue, float endValue, float fraction) {
21 | return startValue + fraction * (endValue - startValue);
22 | }
23 |
24 | static int lerp(int startValue, int endValue, float fraction) {
25 | return startValue + Math.round(fraction * (float) (endValue - startValue));
26 | }
27 |
28 | public static class AnimationListenerAdapter implements Animation.AnimationListener {
29 | public AnimationListenerAdapter() {
30 | }
31 |
32 | public void onAnimationStart(Animation animation) {
33 | }
34 |
35 | public void onAnimationEnd(Animation animation) {
36 | }
37 |
38 | public void onAnimationRepeat(Animation animation) {
39 | }
40 | }
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/fabbutton/src/main/java/mbanje/kurt/fabbutton/CircleImageView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2015 Kurt Mbanje
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package mbanje.kurt.fabbutton;
26 |
27 | import android.animation.Animator;
28 | import android.animation.AnimatorListenerAdapter;
29 | import android.animation.ObjectAnimator;
30 | import android.content.Context;
31 | import android.content.res.TypedArray;
32 | import android.graphics.Bitmap;
33 | import android.graphics.BitmapFactory;
34 | import android.graphics.Canvas;
35 | import android.graphics.Color;
36 | import android.graphics.Paint;
37 | import android.graphics.drawable.BitmapDrawable;
38 | import android.graphics.drawable.Drawable;
39 | import android.graphics.drawable.TransitionDrawable;
40 | import android.support.v7.widget.AppCompatImageView;
41 | import android.util.AttributeSet;
42 | import android.util.DisplayMetrics;
43 | import android.view.View;
44 |
45 |
46 | public class CircleImageView extends AppCompatImageView {
47 |
48 | public interface OnFabViewListener {
49 | void onProgressVisibilityChanged(boolean visible);
50 | void onProgressCompleted();
51 | }
52 |
53 | private static final int animationDuration = 200;
54 | private int centerY;
55 | private int centerX;
56 | private int viewRadius;
57 | private boolean progressVisible;
58 | private int circleRadius;
59 | private Paint circlePaint;
60 | private OnFabViewListener fabViewListener;
61 | private final int ringAlpha = 75;
62 | private int ringRadius;
63 | private Paint ringPaint;
64 | private float currentRingWidth;
65 | private float ringWidthRatio = 0.14f; //of a possible 1f;
66 | private Drawable drawables[] = new Drawable[2];
67 | private TransitionDrawable crossfader;
68 |
69 | private int ringWidth;
70 | private ObjectAnimator ringAnimator;
71 |
72 | float shadowDy = 3.5f;
73 | float shadowDx = 0f;
74 | float shadowRadius = 10f;
75 | int shadowTransparency = 100;
76 | private boolean showEndBitmap;
77 | private boolean showShadow = true;
78 |
79 | public CircleImageView(Context context) {
80 | super(context);
81 | init(context, null);
82 | }
83 |
84 |
85 | public CircleImageView(Context context, AttributeSet attrs) {
86 | super(context, attrs);
87 | init(context, attrs);
88 | }
89 |
90 | public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
91 | super(context, attrs, defStyle);
92 | init(context, attrs);
93 | }
94 |
95 | public void setFabViewListener(OnFabViewListener fabViewListener) {
96 | this.fabViewListener = fabViewListener;
97 | }
98 |
99 | public void setShowShadow(boolean showShadow) {
100 | if (showShadow) {
101 | circlePaint.setShadowLayer(shadowRadius, shadowDx, shadowDy, Color.argb(shadowTransparency, 0, 0, 0));
102 | } else {
103 | circlePaint.clearShadowLayer();
104 | }
105 | invalidate();
106 | }
107 |
108 | private void init(Context context, AttributeSet attrs) {
109 | this.setFocusable(false);
110 | this.setScaleType(ScaleType.CENTER_INSIDE);
111 | setClickable(true);
112 | circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
113 | circlePaint.setStyle(Paint.Style.FILL);
114 | DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
115 | if (displayMetrics.densityDpi <= 240) {
116 | shadowRadius = 1.0f;
117 | } else if (displayMetrics.densityDpi <= 320) {
118 | shadowRadius = 3.0f;
119 | } else {
120 | shadowRadius = 10.0f;
121 | }
122 | ringPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
123 | ringPaint.setStyle(Paint.Style.STROKE);
124 | setWillNotDraw(false);
125 | setLayerType(View.LAYER_TYPE_SOFTWARE, null);
126 | int color = Color.BLACK;
127 | if (attrs != null) {
128 | final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
129 | color = a.getColor(R.styleable.CircleImageView_android_color, Color.BLACK);
130 | ringWidthRatio = a.getFloat(R.styleable.CircleImageView_fbb_progressWidthRatio, ringWidthRatio);
131 | shadowRadius = a.getFloat(R.styleable.CircleImageView_android_shadowRadius, shadowRadius);
132 | shadowDy = a.getFloat(R.styleable.CircleImageView_android_shadowDy, shadowDy);
133 | shadowDx = a.getFloat(R.styleable.CircleImageView_android_shadowDx, shadowDx);
134 | setShowShadow(a.getBoolean(R.styleable.CircleImageView_fbb_showShadow, true));
135 | a.recycle();
136 | }
137 | setColor(color);
138 | final int pressedAnimationTime = animationDuration;
139 | ringAnimator = ObjectAnimator.ofFloat(this, "currentRingWidth", 0f, 0f);
140 | ringAnimator.setDuration(pressedAnimationTime);
141 | ringAnimator.addListener(new AnimatorListenerAdapter() {
142 | @Override
143 | public void onAnimationEnd(Animator animation) {
144 | if (fabViewListener != null) {
145 | fabViewListener.onProgressVisibilityChanged(progressVisible);
146 | }
147 | }
148 | });
149 | }
150 |
151 | public void setShowEndBitmap(boolean showEndBitmap) {
152 | this.showEndBitmap = showEndBitmap;
153 | }
154 |
155 | /**
156 | * sets the icon that will be shown on the fab icon
157 | *
158 | * @param resource the resource id of the icon
159 | */
160 | public void setIcon(int resource, int endBitmapResource) {
161 | Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), resource);
162 | if (showEndBitmap) {
163 | Bitmap endBitmap = BitmapFactory.decodeResource(getResources(), endBitmapResource);
164 | setIconAnimation(new BitmapDrawable(getResources(), srcBitmap),
165 | new BitmapDrawable(getResources(), endBitmap));
166 | } else {
167 | setImageBitmap(srcBitmap);
168 | }
169 | }
170 |
171 | /**
172 | * sets the icon that will be shown on the fab icon
173 | *
174 | * @param icon the initial icon
175 | * @param endIcon the icon to be displayed when the progress is finished
176 | */
177 | public void setIcon(Drawable icon, Drawable endIcon) {
178 | if (showEndBitmap) {
179 | setIconAnimation(icon, endIcon);
180 | } else {
181 | setImageDrawable(icon);
182 | }
183 | }
184 |
185 | private void setIconAnimation(Drawable icon, Drawable endIcon) {
186 | drawables[0] = icon;
187 | drawables[1] = endIcon;
188 | crossfader = new TransitionDrawable(drawables);
189 | crossfader.setCrossFadeEnabled(true);
190 | setImageDrawable(crossfader);
191 | }
192 |
193 | public void resetIcon() {
194 | crossfader.resetTransition();
195 | }
196 |
197 | /**
198 | * this sets the thickness of the ring as a fraction of the radius of the circle.
199 | *
200 | * @param ringWidthRatio the ratio 0-1
201 | */
202 | public void setRingWidthRatio(float ringWidthRatio) {
203 | this.ringWidthRatio = ringWidthRatio;
204 | }
205 |
206 | @Override
207 | protected void onDraw(Canvas canvas) {
208 | final float ringR = ringRadius + currentRingWidth;
209 | canvas.drawCircle(centerX, centerY, ringR, ringPaint); // the outer ring
210 | canvas.drawCircle(centerX, centerY, circleRadius, circlePaint); //the actual circle
211 | super.onDraw(canvas);
212 | }
213 |
214 | @Override
215 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
216 | super.onSizeChanged(w, h, oldw, oldh);
217 | centerX = w / 2;
218 | centerY = h / 2;
219 | viewRadius = Math.min(w, h) / 2;
220 | ringWidth = Math.round((float) viewRadius * ringWidthRatio);
221 | circleRadius = viewRadius - ringWidth;
222 | ringPaint.setStrokeWidth(ringWidth);
223 | ringPaint.setAlpha(ringAlpha);
224 | ringRadius = circleRadius - ringWidth / 2;
225 | }
226 |
227 | public float getCurrentRingWidth() {
228 | return currentRingWidth;
229 | }
230 |
231 | public void setCurrentRingWidth(float currentRingWidth) {
232 | this.currentRingWidth = currentRingWidth;
233 | this.invalidate();
234 | }
235 |
236 | /**
237 | * sets the color of the circle
238 | *
239 | * @param color the actual color to set to
240 | */
241 | public void setColor(int color) {
242 | circlePaint.setColor(color);
243 | ringPaint.setColor(color);
244 | ringPaint.setAlpha(ringAlpha);
245 | this.invalidate();
246 | }
247 |
248 | /**
249 | * whether to show the ring or not
250 | *
251 | * @param show set flag
252 | */
253 | public void showRing(boolean show) {
254 | progressVisible = show;
255 | if (show) {
256 | ringAnimator.setFloatValues(currentRingWidth, ringWidth);
257 | } else {
258 | ringAnimator.setFloatValues(ringWidth, 0f);
259 | }
260 | ringAnimator.start();
261 | }
262 |
263 | /**
264 | * this animates between the icon set in the imageview and the completed icon. does as crossfade animation
265 | *
266 | * @param show set flag
267 | * @param hideOnComplete if true animate outside ring out after progress complete
268 | */
269 | public void showCompleted(boolean show, boolean hideOnComplete) {
270 | if (show) {
271 | crossfader.startTransition(500);
272 | }
273 | if (hideOnComplete) {
274 | ObjectAnimator hideAnimator = ObjectAnimator.ofFloat(this, "currentRingWidth", 0f, 0f);
275 | hideAnimator.setFloatValues(1);
276 | hideAnimator.setDuration(animationDuration);
277 | hideAnimator.start();
278 |
279 | }
280 | }
281 | }
282 |
--------------------------------------------------------------------------------
/fabbutton/src/main/java/mbanje/kurt/fabbutton/FabButton.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2015 Kurt Mbanje
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package mbanje.kurt.fabbutton;
26 |
27 | import android.content.Context;
28 | import android.content.res.TypedArray;
29 | import android.graphics.Color;
30 | import android.graphics.Rect;
31 | import android.graphics.drawable.Drawable;
32 | import android.support.design.widget.AppBarLayout;
33 | import android.support.design.widget.CoordinatorLayout;
34 | import android.support.design.widget.Snackbar;
35 | import android.support.v4.view.ViewCompat;
36 | import android.support.v4.view.ViewPropertyAnimatorListener;
37 | import android.util.AttributeSet;
38 | import android.view.View;
39 | import android.widget.FrameLayout;
40 |
41 | import java.util.List;
42 |
43 |
44 | /**
45 | * Created by kurt on 21 02 2015 .
46 | */
47 | @CoordinatorLayout.DefaultBehavior(FabButton.Behavior.class)
48 | public class FabButton extends FrameLayout implements CircleImageView.OnFabViewListener {
49 |
50 | private CircleImageView circle;
51 | private ProgressRingView ring;
52 | private float ringWidthRatio = 0.14f; //of a possible 1f;
53 | private boolean indeterminate;
54 | private boolean autostartanim;
55 | private int endBitmapResource;
56 | private boolean showEndBitmap;
57 | private boolean hideProgressOnComplete;
58 |
59 | public FabButton(Context context) {
60 | super(context);
61 | init(context, null, 0);
62 | }
63 |
64 | public FabButton(Context context, AttributeSet attrs) {
65 | super(context, attrs);
66 | init(context, attrs, 0);
67 | }
68 |
69 | public FabButton(Context context, AttributeSet attrs, int defStyle) {
70 | super(context, attrs, defStyle);
71 | init(context, attrs, defStyle);
72 | }
73 |
74 | protected void init(Context context, AttributeSet attrs, int defStyle) {
75 | View v = View.inflate(context, R.layout.widget_fab_button, this);
76 | setClipChildren(false);
77 | circle = (CircleImageView) v.findViewById(R.id.fabbutton_circle);
78 | ring = (ProgressRingView) v.findViewById(R.id.fabbutton_ring);
79 | circle.setFabViewListener(this);
80 | ring.setFabViewListener(this);
81 | int color = Color.BLACK;
82 | int progressColor = Color.BLACK;
83 | int animDuration = 4000;
84 | int icon = -1;
85 | float maxProgress = 0;
86 | float progress = 0;
87 | if (attrs != null) {
88 | final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
89 | color = a.getColor(R.styleable.CircleImageView_android_color, Color.BLACK);
90 | progressColor = a.getColor(R.styleable.CircleImageView_fbb_progressColor, Color.BLACK);
91 | progress = a.getFloat(R.styleable.CircleImageView_android_progress, 0f);
92 | maxProgress = a.getFloat(R.styleable.CircleImageView_android_max, 100f);
93 | indeterminate = a.getBoolean(R.styleable.CircleImageView_android_indeterminate, false);
94 | autostartanim = a.getBoolean(R.styleable.CircleImageView_fbb_autoStart, true);
95 | animDuration = a.getInteger(R.styleable.CircleImageView_android_indeterminateDuration, animDuration);
96 | icon = a.getResourceId(R.styleable.CircleImageView_android_src, icon);
97 | ringWidthRatio = a.getFloat(R.styleable.CircleImageView_fbb_progressWidthRatio, ringWidthRatio);
98 | endBitmapResource = a.getResourceId(R.styleable.CircleImageView_fbb_endBitmap, R.drawable.ic_fab_complete);
99 | showEndBitmap = a.getBoolean(R.styleable.CircleImageView_fbb_showEndBitmap, false);
100 | hideProgressOnComplete = a.getBoolean(R.styleable.CircleImageView_fbb_hideProgressOnComplete, false);
101 | circle.setShowShadow(a.getBoolean(R.styleable.CircleImageView_fbb_showShadow, true));
102 | a.recycle();
103 | }
104 |
105 | circle.setColor(color);
106 | circle.setShowEndBitmap(showEndBitmap);
107 | circle.setRingWidthRatio(ringWidthRatio);
108 | ring.setProgressColor(progressColor);
109 | ring.setProgress(progress);
110 | ring.setMaxProgress(maxProgress);
111 | ring.setAutostartanim(autostartanim);
112 | ring.setAnimDuration(animDuration);
113 | ring.setRingWidthRatio(ringWidthRatio);
114 | ring.setIndeterminate(indeterminate);
115 | if (icon != -1) {
116 | circle.setIcon(icon, endBitmapResource);
117 | }
118 | }
119 |
120 | public void setShadow(boolean showShadow) {
121 | circle.setShowShadow(showShadow);
122 | }
123 |
124 | public void setIcon(int resource, int endIconResource) {
125 | circle.setIcon(resource, endIconResource);
126 | }
127 |
128 | public void showShadow(boolean show) {
129 | circle.setShowShadow(show);
130 | invalidate();
131 | }
132 |
133 | public void setColor(int color) {
134 | circle.setColor(color);
135 | }
136 |
137 | public void setProgressColor(int color) {
138 | ring.setProgressColor(color);
139 | }
140 |
141 | public void setIcon(Drawable icon, Drawable endIcon) {
142 | circle.setIcon(icon, endIcon);
143 | }
144 |
145 | public void resetIcon() {
146 | circle.resetIcon();
147 | }
148 |
149 | /**
150 | * sets the progress to indeterminate or not
151 | *
152 | * @param indeterminate the flag
153 | */
154 | public void setIndeterminate(boolean indeterminate) {
155 | this.indeterminate = indeterminate;
156 | ring.setIndeterminate(indeterminate);
157 | }
158 |
159 | @Override
160 | public void setOnClickListener(OnClickListener listener) {
161 | super.setOnClickListener(listener);
162 | ring.setOnClickListener(listener);
163 | circle.setOnClickListener(listener);
164 | }
165 |
166 | /**
167 | * shows the animation ring
168 | *
169 | * @param show shows animation ring when set to true
170 | */
171 | public void showProgress(boolean show) {
172 | circle.showRing(show);
173 | }
174 |
175 | public void hideProgressOnComplete(boolean hide) {
176 | hideProgressOnComplete = hide;
177 | }
178 |
179 | public void setEnabled(boolean enabled) {
180 | super.setEnabled(enabled);
181 | circle.setEnabled(enabled);
182 | ring.setEnabled(enabled);
183 | }
184 |
185 | /**
186 | * sets current progress
187 | *
188 | * @param progress the current progress to set value too
189 | */
190 | public void setProgress(float progress) {
191 | ring.setProgress(progress);
192 | }
193 |
194 | @Override
195 | public void onProgressVisibilityChanged(boolean visible) {
196 | if (visible) {
197 | ring.setVisibility(View.VISIBLE);
198 | ring.startAnimation();
199 | } else {
200 | ring.stopAnimation(true);
201 | ring.setVisibility(View.GONE);
202 | }
203 | }
204 |
205 | @Override
206 | public void onProgressCompleted() {
207 | circle.showCompleted(showEndBitmap, hideProgressOnComplete);
208 | if (hideProgressOnComplete) {
209 | ring.setVisibility(View.GONE);
210 | }
211 | }
212 |
213 |
214 | public static class Behavior extends CoordinatorLayout.Behavior {
215 | // We only support the FAB <> Snackbar shift movement on Honeycomb and above. This is
216 | // because we can use view translation properties which greatly simplifies the code.
217 |
218 | private Rect mTmpRect;
219 | private boolean mIsAnimatingOut;
220 | private float mTranslationY;
221 |
222 | @Override
223 | public boolean layoutDependsOn(CoordinatorLayout parent, FabButton child,
224 | View dependency) {
225 | // We're dependent on all SnackbarLayouts (if enabled)
226 | return dependency instanceof Snackbar.SnackbarLayout;
227 | }
228 |
229 | @Override
230 | public boolean onDependentViewChanged(CoordinatorLayout parent, FabButton child, View dependency) {
231 | if (dependency instanceof Snackbar.SnackbarLayout) {
232 | updateFabTranslationForSnackbar(parent, child, dependency);
233 | } else if (dependency instanceof AppBarLayout) {
234 | final AppBarLayout appBarLayout = (AppBarLayout) dependency;
235 | if (mTmpRect == null) {
236 | mTmpRect = new Rect();
237 | }
238 |
239 | // First, let's get the visible rect of the dependency
240 | final Rect rect = mTmpRect;
241 | ViewGroupUtils.getDescendantRect(parent, dependency, rect);
242 |
243 | if (rect.bottom <= getMinimumHeightForVisibleOverlappingContent(appBarLayout)) {
244 | // If the anchor's bottom is below the seam, we'll animate our FAB out
245 | if (!mIsAnimatingOut && child.getVisibility() == View.VISIBLE) {
246 | animateOut(child);
247 | }
248 | } else {
249 | // Else, we'll animate our FAB back in
250 | if (child.getVisibility() != View.VISIBLE) {
251 | animateIn(child);
252 | }
253 | }
254 | }
255 |
256 |
257 | return false;
258 | }
259 |
260 | final int getMinimumHeightForVisibleOverlappingContent(AppBarLayout bar) {
261 | int topInset = 0;
262 | int minHeight = ViewCompat.getMinimumHeight(bar);
263 | if (minHeight != 0) {
264 | return minHeight * 2 + topInset;
265 | } else {
266 | int childCount = bar.getChildCount();
267 | return childCount >= 1 ? ViewCompat.getMinimumHeight(bar.getChildAt(childCount - 1)) * 2 + topInset : 0;
268 | }
269 | }
270 |
271 |
272 | private void updateFabTranslationForSnackbar(CoordinatorLayout parent,
273 | FabButton fab, View snackbar) {
274 | final float translationY = getFabTranslationYForSnackbar(parent, fab);
275 | if (translationY != mTranslationY) {
276 | // First, cancel any current animation
277 | ViewCompat.animate(fab).cancel();
278 |
279 | if (Math.abs(translationY - mTranslationY) == snackbar.getHeight()) {
280 | // If we're travelling by the height of the Snackbar then we probably need to
281 | // animate to the value
282 | ViewCompat.animate(fab)
283 | .translationY(translationY)
284 | .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
285 | .setListener(null);
286 | } else {
287 | // Else we'll set use setTranslationY
288 | ViewCompat.setTranslationY(fab, translationY);
289 | }
290 | mTranslationY = translationY;
291 | }
292 | }
293 |
294 | private float getFabTranslationYForSnackbar(CoordinatorLayout parent,
295 | FabButton fab) {
296 | float minOffset = 0;
297 | final List dependencies = parent.getDependencies(fab);
298 | for (int i = 0, z = dependencies.size(); i < z; i++) {
299 | final View view = dependencies.get(i);
300 | if (view instanceof Snackbar.SnackbarLayout && parent.doViewsOverlap(fab, view)) {
301 | minOffset = Math.min(minOffset,
302 | ViewCompat.getTranslationY(view) - view.getHeight());
303 | }
304 | }
305 |
306 | return minOffset;
307 | }
308 |
309 | private void animateIn(FabButton button) {
310 | button.setVisibility(View.VISIBLE);
311 |
312 | ViewCompat.animate(button)
313 | .scaleX(1f)
314 | .scaleY(1f)
315 | .alpha(1f)
316 | .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
317 | .withLayer()
318 | .setListener(null)
319 | .start();
320 | }
321 |
322 | private void animateOut(final FabButton button) {
323 | ViewCompat.animate(button)
324 | .scaleX(0f)
325 | .scaleY(0f)
326 | .alpha(0f)
327 | .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
328 | .withLayer()
329 | .setListener(new ViewPropertyAnimatorListener() {
330 | @Override
331 | public void onAnimationStart(View view) {
332 | mIsAnimatingOut = true;
333 | }
334 |
335 | @Override
336 | public void onAnimationCancel(View view) {
337 | mIsAnimatingOut = false;
338 | }
339 |
340 | @Override
341 | public void onAnimationEnd(View view) {
342 | mIsAnimatingOut = false;
343 | view.setVisibility(View.GONE);
344 | }
345 | }).start();
346 | }
347 | }
348 | }
349 |
--------------------------------------------------------------------------------
/fabbutton/src/main/java/mbanje/kurt/fabbutton/FabUtil.java:
--------------------------------------------------------------------------------
1 | package mbanje.kurt.fabbutton;
2 |
3 | import android.animation.AnimatorSet;
4 | import android.animation.ValueAnimator;
5 | import android.view.View;
6 | import android.view.animation.DecelerateInterpolator;
7 | import android.view.animation.LinearInterpolator;
8 |
9 | /**
10 | * Created by kurt on 21 02 2015 .
11 | */
12 | public class FabUtil {
13 | public static final float INDETERMINANT_MIN_SWEEP = 15f;
14 | public static final int ANIMATION_STEPS = 4;
15 |
16 | /**
17 | * the animation callback interface that should be used by classes that want to listen for events from the library animations
18 | */
19 | public static interface OnFabValueCallback{
20 | public void onIndeterminateValuesChanged(float indeterminateSweep,float indeterminateRotateOffset,float startAngle,float progress);
21 | }
22 |
23 | /**
24 | * Creates the starting angle animator for the circleview
25 | * @param view the view that the animator is to be attached too
26 | * @param from animate from value
27 | * @param to animate to value
28 | * @param callback the callback interface for animations
29 | * @return ValueAnimator instance
30 | */
31 | public static ValueAnimator createStartAngleAnimator(final View view,float from,float to,final OnFabValueCallback callback){
32 | ValueAnimator animator = ValueAnimator.ofFloat(from, to);
33 | animator.setDuration(5000);
34 | animator.setInterpolator(new DecelerateInterpolator(2));
35 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
36 | @Override
37 | public void onAnimationUpdate(ValueAnimator animation) {
38 | float startAngle = (Float) animation.getAnimatedValue();
39 | callback.onIndeterminateValuesChanged(-1,-1,startAngle,-1);
40 | view.invalidate();
41 | }
42 | });
43 | return animator;
44 | }
45 |
46 |
47 | /**
48 | * Creates a progress animator
49 | * @param view the view that the animator is to be attached too
50 | * @param from animate from value
51 | * @param to animate to value
52 | * @param callback the callback interface for animations
53 | * @return ValueAnimator instance
54 | */
55 | public static ValueAnimator createProgressAnimator(final View view,float from,float to,final OnFabValueCallback callback){
56 | ValueAnimator animator = ValueAnimator.ofFloat(from, to);
57 | animator.setDuration(500);
58 | animator.setInterpolator(new LinearInterpolator());
59 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
60 | @Override
61 | public void onAnimationUpdate(ValueAnimator animation) {
62 | float actualProgress = (Float) animation.getAnimatedValue();
63 | callback.onIndeterminateValuesChanged(-1,-1,-1,actualProgress);
64 | view.invalidate();
65 | }
66 | });
67 | return animator;
68 | }
69 |
70 |
71 | /**
72 | * Creates a progress animator
73 | * @param view the view that the animator is to be attached too
74 | * @param step animation steps of the prgress animation
75 | * @param animDuration duration of the animation i.e. 1 cycle
76 | * @param callback the callback interface for animations
77 | * @return AnimatorSet instance
78 | */
79 | public static AnimatorSet createIndeterminateAnimator(final View view,float step,int animDuration, final OnFabValueCallback callback){
80 | final float maxSweep = 360f*(ANIMATION_STEPS-1)/ANIMATION_STEPS + INDETERMINANT_MIN_SWEEP;
81 | final float start = -90f + step*(maxSweep-INDETERMINANT_MIN_SWEEP);
82 | // Extending the front of the arc
83 | ValueAnimator frontEndExtend = ValueAnimator.ofFloat(INDETERMINANT_MIN_SWEEP, maxSweep);
84 | frontEndExtend.setDuration(animDuration/ANIMATION_STEPS/2);
85 | frontEndExtend.setInterpolator(new DecelerateInterpolator(1));
86 | frontEndExtend.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
87 | @Override
88 | public void onAnimationUpdate(ValueAnimator animation) {
89 | float indeterminateSweep = (Float) animation.getAnimatedValue();
90 | callback.onIndeterminateValuesChanged(indeterminateSweep,-1,-1,-1);
91 | view.invalidate();
92 | }
93 | });
94 |
95 | // Overall rotation
96 | ValueAnimator rotateAnimator1 = ValueAnimator.ofFloat(step*720f/ANIMATION_STEPS, (step+.5f)*720f/ANIMATION_STEPS);
97 | rotateAnimator1.setDuration(animDuration/ANIMATION_STEPS/2);
98 | rotateAnimator1.setInterpolator(new LinearInterpolator());
99 | rotateAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
100 | @Override
101 | public void onAnimationUpdate(ValueAnimator animation) {
102 | float indeterminateRotateOffset = (Float) animation.getAnimatedValue();
103 | callback.onIndeterminateValuesChanged(-1,indeterminateRotateOffset,-1,-1);
104 | }
105 | });
106 |
107 | // Retracting the back end of the arc
108 | ValueAnimator backEndRetract = ValueAnimator.ofFloat(start, start+maxSweep-INDETERMINANT_MIN_SWEEP);
109 | backEndRetract.setDuration(animDuration/ANIMATION_STEPS/2);
110 | backEndRetract.setInterpolator(new DecelerateInterpolator(1));
111 | backEndRetract.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
112 | @Override
113 | public void onAnimationUpdate(ValueAnimator animation) {
114 | float startAngle = (Float) animation.getAnimatedValue();
115 | float indeterminateSweep = maxSweep - startAngle + start;
116 | callback.onIndeterminateValuesChanged(indeterminateSweep,-1,startAngle,-1);
117 | view.invalidate();
118 | }
119 | });
120 |
121 | // More overall rotation
122 | ValueAnimator rotateAnimator2 = ValueAnimator.ofFloat((step+.5f)*720f/ANIMATION_STEPS, (step+1)*720f/ANIMATION_STEPS);
123 | rotateAnimator2.setDuration(animDuration/ANIMATION_STEPS/2);
124 | rotateAnimator2.setInterpolator(new LinearInterpolator());
125 | rotateAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
126 | @Override
127 | public void onAnimationUpdate(ValueAnimator animation) {
128 | float indeterminateRotateOffset = (Float) animation.getAnimatedValue();
129 | callback.onIndeterminateValuesChanged(-1,indeterminateRotateOffset,-1,-1);
130 | }
131 | });
132 |
133 | AnimatorSet set = new AnimatorSet();
134 | set.play(frontEndExtend).with(rotateAnimator1);
135 | set.play(backEndRetract).with(rotateAnimator2).after(rotateAnimator1);
136 | return set;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/fabbutton/src/main/java/mbanje/kurt/fabbutton/ProgressRingView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2015 Rahat Ahmed
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package mbanje.kurt.fabbutton;
26 |
27 | import android.animation.Animator;
28 | import android.animation.AnimatorListenerAdapter;
29 | import android.animation.AnimatorSet;
30 | import android.animation.ValueAnimator;
31 | import android.content.Context;
32 | import android.content.res.TypedArray;
33 | import android.graphics.Canvas;
34 | import android.graphics.Color;
35 | import android.graphics.Paint;
36 | import android.graphics.RectF;
37 | import android.util.AttributeSet;
38 | import android.view.View;
39 |
40 |
41 |
42 | public class ProgressRingView extends View implements FabUtil.OnFabValueCallback{
43 | String TAG = ProgressRingView.class.getSimpleName();
44 | private Paint progressPaint;
45 | private int size = 0;
46 | private RectF bounds;
47 | private float boundsPadding = 0.14f;
48 | private int viewRadius;
49 | private float ringWidthRatio = 0.14f; //of a possible 1f;
50 | private boolean indeterminate,autostartanim;
51 | private float progress, maxProgress, indeterminateSweep, indeterminateRotateOffset;
52 | private int ringWidth,midRingWidth,animDuration;
53 | private int progressColor = Color.BLACK;
54 |
55 |
56 | // Animation related stuff
57 | private float startAngle;
58 | private float actualProgress;
59 | private ValueAnimator startAngleRotate;
60 | private ValueAnimator progressAnimator;
61 | private AnimatorSet indeterminateAnimator;
62 |
63 | private CircleImageView.OnFabViewListener fabViewListener;
64 |
65 | public ProgressRingView(Context context) {
66 | super(context);
67 | init(null, 0);
68 | }
69 |
70 | public ProgressRingView(Context context, AttributeSet attrs) {
71 | super(context, attrs);
72 | init(attrs, 0);
73 | }
74 |
75 | public ProgressRingView(Context context, AttributeSet attrs, int defStyle) {
76 | super(context, attrs, defStyle);
77 | init(attrs, defStyle);
78 | }
79 |
80 | protected void init(AttributeSet attrs, int defStyle) {
81 | final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
82 | progress = a.getFloat(R.styleable.CircleImageView_android_progress, 0f);
83 | progressColor = a.getColor(R.styleable.CircleImageView_fbb_progressColor,progressColor);
84 | maxProgress = a.getFloat(R.styleable.CircleImageView_android_max, 100f);
85 | indeterminate = a.getBoolean(R.styleable.CircleImageView_android_indeterminate, false);
86 | autostartanim = a.getBoolean(R.styleable.CircleImageView_fbb_autoStart, true);
87 | animDuration = a.getInteger(R.styleable.CircleImageView_android_indeterminateDuration, 4000);
88 | ringWidthRatio = a.getFloat(R.styleable.CircleImageView_fbb_progressWidthRatio, ringWidthRatio);
89 | a.recycle();
90 | progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
91 | progressPaint.setColor(progressColor);
92 | progressPaint.setStyle(Paint.Style.STROKE);
93 | progressPaint.setStrokeCap(Paint.Cap.BUTT);
94 | if(autostartanim) {
95 | startAnimation();
96 | }
97 | }
98 |
99 |
100 |
101 | @Override
102 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
103 | super.onSizeChanged(w, h, oldw, oldh);
104 | size = Math.min(w,h);
105 | viewRadius = size / 2;
106 | setRingWidth(-1,true);
107 | }
108 |
109 | public void setRingWidthRatio(float ringWidthRatio) {
110 | this.ringWidthRatio = ringWidthRatio;
111 | }
112 |
113 | public void setAutostartanim(boolean autostartanim) {
114 | this.autostartanim = autostartanim;
115 | }
116 |
117 | public void setFabViewListener(CircleImageView.OnFabViewListener fabViewListener) {
118 | this.fabViewListener = fabViewListener;
119 | }
120 |
121 | public void setRingWidth(int width,boolean original){
122 | if(original){
123 | ringWidth = Math.round((float) viewRadius * ringWidthRatio);
124 | }else{
125 | ringWidth = width;
126 | }
127 | midRingWidth = ringWidth/2;
128 | progressPaint.setStrokeWidth(ringWidth);
129 | updateBounds();
130 | }
131 |
132 | private void updateBounds(){
133 | bounds = new RectF(midRingWidth,midRingWidth, size - midRingWidth, size- midRingWidth);
134 | }
135 |
136 |
137 | @Override
138 | protected void onDraw(Canvas canvas) {
139 | // Draw the arc
140 | float sweepAngle = isInEditMode() ? (progress/maxProgress*360) : (actualProgress/maxProgress*360);
141 | if(!indeterminate) {
142 | canvas.drawArc(bounds, startAngle, sweepAngle, false, progressPaint);
143 | }else {
144 | canvas.drawArc(bounds, startAngle + indeterminateRotateOffset, indeterminateSweep, false, progressPaint);
145 | }
146 | }
147 |
148 |
149 | /**
150 | * Sets the progress of the progress bar.
151 | * @param currentProgress the current progress you want to set
152 | */
153 | public void setProgress(final float currentProgress) {
154 | this.progress = currentProgress;
155 | // Reset the determinate animation to approach the new progress
156 | if(!indeterminate){
157 | if(progressAnimator != null && progressAnimator.isRunning()) {
158 | progressAnimator.cancel();
159 | }
160 | progressAnimator = FabUtil.createProgressAnimator(this,actualProgress,currentProgress,this);
161 | progressAnimator.start();
162 | }
163 | invalidate();
164 |
165 | }
166 |
167 |
168 | public void setMaxProgress(float maxProgress) {
169 | this.maxProgress = maxProgress;
170 | }
171 |
172 |
173 | public void setIndeterminate(boolean indeterminate) {
174 | this.indeterminate = indeterminate;
175 | }
176 |
177 | public void setAnimDuration(int animDuration) {
178 | this.animDuration = animDuration;
179 | }
180 |
181 |
182 | public void setProgressColor(int progressColor) {
183 | this.progressColor = progressColor;
184 | progressPaint.setColor(progressColor);
185 | }
186 |
187 |
188 |
189 | /**
190 | * Starts the progress bar animation.
191 | * (This is an alias of resetAnimation() so it does the same thing.)
192 | */
193 | public void startAnimation() {
194 | resetAnimation();
195 | }
196 |
197 |
198 | public void stopAnimation(boolean hideProgress){
199 | if(startAngleRotate != null && startAngleRotate.isRunning()) {
200 | startAngleRotate.cancel();
201 | }
202 | if(progressAnimator != null && progressAnimator.isRunning()) {
203 | progressAnimator.cancel();
204 | }
205 | if(indeterminateAnimator != null && indeterminateAnimator.isRunning()) {
206 | indeterminateAnimator.cancel();
207 | }
208 | if(hideProgress){
209 | setRingWidth(0, false);
210 | }else{
211 | setRingWidth(0,true);
212 | }
213 | invalidate();
214 | }
215 | /**
216 | * Resets the animation.
217 | */
218 | public void resetAnimation() {
219 | stopAnimation(false);
220 | // Determinate animation
221 | if(!indeterminate){
222 | // The cool 360 swoop animation at the start of the animation
223 | startAngle = -90f;
224 | startAngleRotate = FabUtil.createStartAngleAnimator(this,-90f,270f,this);
225 | startAngleRotate.start();
226 | // The linear animation shown when progress is updated
227 | actualProgress = 0f;
228 | progressAnimator = FabUtil.createProgressAnimator(this, actualProgress, progress, this);
229 | progressAnimator.start();
230 | }else { // Indeterminate animation
231 | startAngle = -90f;
232 | indeterminateSweep = FabUtil.INDETERMINANT_MIN_SWEEP;
233 | // Build the whole AnimatorSet
234 | indeterminateAnimator = new AnimatorSet();
235 | AnimatorSet prevSet = null, nextSet;
236 | for(int k=0;k= 11) {
29 | IMPL = new ViewGroupUtils.ViewGroupUtilsImplHoneycomb();
30 | } else {
31 | IMPL = new ViewGroupUtils.ViewGroupUtilsImplBase();
32 | }
33 |
34 | }
35 |
36 | private static class ViewGroupUtilsImplHoneycomb implements ViewGroupUtils.ViewGroupUtilsImpl {
37 | private ViewGroupUtilsImplHoneycomb() {
38 | }
39 |
40 | public void offsetDescendantRect(ViewGroup parent, View child, Rect rect) {
41 | ViewGroupUtilsHoneycomb.offsetDescendantRect(parent, child, rect);
42 | }
43 | }
44 |
45 | private static class ViewGroupUtilsImplBase implements ViewGroupUtils.ViewGroupUtilsImpl {
46 | private ViewGroupUtilsImplBase() {
47 | }
48 |
49 | public void offsetDescendantRect(ViewGroup parent, View child, Rect rect) {
50 | parent.offsetDescendantRectToMyCoords(child, rect);
51 | }
52 | }
53 |
54 | private interface ViewGroupUtilsImpl {
55 | void offsetDescendantRect(ViewGroup var1, View var2, Rect var3);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/fabbutton/src/main/java/mbanje/kurt/fabbutton/ViewGroupUtilsHoneycomb.java:
--------------------------------------------------------------------------------
1 | package mbanje.kurt.fabbutton;
2 |
3 | import android.graphics.Matrix;
4 | import android.graphics.Rect;
5 | import android.graphics.RectF;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.view.ViewParent;
9 |
10 | /**
11 | * Created by kurt on 2015/06/08.
12 | */
13 | class ViewGroupUtilsHoneycomb {
14 | private static final ThreadLocal sMatrix = new ThreadLocal<>();
15 | private static final ThreadLocal sRectF = new ThreadLocal<>();
16 | private static final Matrix IDENTITY = new Matrix();
17 |
18 | public static void offsetDescendantRect(ViewGroup group, View child, Rect rect) {
19 | Matrix m = sMatrix.get();
20 | if (m == null) {
21 | m = new Matrix();
22 | sMatrix.set(m);
23 | } else {
24 | m.set(IDENTITY);
25 | }
26 |
27 | offsetDescendantMatrix(group, child, m);
28 |
29 | RectF rectF = sRectF.get();
30 | if (rectF == null) {
31 | rectF = new RectF();
32 | }
33 | rectF.set(rect);
34 | m.mapRect(rectF);
35 | rect.set((int) (rectF.left + 0.5f), (int) (rectF.top + 0.5f),
36 | (int) (rectF.right + 0.5f), (int) (rectF.bottom + 0.5f));
37 | }
38 |
39 | static void offsetDescendantMatrix(ViewParent target, View view, Matrix m) {
40 | final ViewParent parent = view.getParent();
41 | if (parent instanceof View && parent != target) {
42 | final View vp = (View) parent;
43 | offsetDescendantMatrix(target, vp, m);
44 | m.preTranslate(-vp.getScrollX(), -vp.getScrollY());
45 | }
46 |
47 | m.preTranslate(view.getLeft(), view.getTop());
48 |
49 | if (!view.getMatrix().isIdentity()) {
50 | m.preConcat(view.getMatrix());
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/fabbutton/src/main/res/drawable-hdpi/ic_fab_complete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckurtm/FabButton/cd12dee2890c7b0efdc5d21ae4ddffa4bc1aa8ea/fabbutton/src/main/res/drawable-hdpi/ic_fab_complete.png
--------------------------------------------------------------------------------
/fabbutton/src/main/res/drawable-mdpi/ic_fab_complete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckurtm/FabButton/cd12dee2890c7b0efdc5d21ae4ddffa4bc1aa8ea/fabbutton/src/main/res/drawable-mdpi/ic_fab_complete.png
--------------------------------------------------------------------------------
/fabbutton/src/main/res/drawable-xhdpi/ic_fab_complete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckurtm/FabButton/cd12dee2890c7b0efdc5d21ae4ddffa4bc1aa8ea/fabbutton/src/main/res/drawable-xhdpi/ic_fab_complete.png
--------------------------------------------------------------------------------
/fabbutton/src/main/res/drawable-xxhdpi/ic_fab_complete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckurtm/FabButton/cd12dee2890c7b0efdc5d21ae4ddffa4bc1aa8ea/fabbutton/src/main/res/drawable-xxhdpi/ic_fab_complete.png
--------------------------------------------------------------------------------
/fabbutton/src/main/res/layout/widget_fab_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
30 |
31 |
39 |
40 |
51 |
--------------------------------------------------------------------------------
/fabbutton/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/fabbutton/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 80dp
3 |
4 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ckurtm/FabButton/cd12dee2890c7b0efdc5d21ae4ddffa4bc1aa8ea/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Sep 20 14:29:12 EEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':fabbutton', ':demo'
2 |
--------------------------------------------------------------------------------