├── .gitignore ├── .idea ├── codeStyleSettings.xml ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── kotlinc.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── myhexaville │ │ └── iconanimations │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── myhexaville │ │ │ └── iconanimations │ │ │ ├── BlankFragment.java │ │ │ ├── CustomTab.java │ │ │ ├── FABFragment.java │ │ │ ├── MainActivity.java │ │ │ ├── gooey_fab │ │ │ ├── GooeyFab.java │ │ │ ├── GooeyFabCompat.java │ │ │ └── GooeyFabCompatImpl.java │ │ │ └── progress_circle_layout │ │ │ ├── OnCircleAnimationListener.java │ │ │ ├── ProgressCircleLayout.java │ │ │ └── ProgressCircleView.java │ └── res │ │ ├── anim │ │ ├── slide_down.xml │ │ └── slide_down_and_scale.xml │ │ ├── animator │ │ ├── fade_in.xml │ │ ├── fade_out.xml │ │ ├── gooey_path_anim.xml │ │ ├── gooey_path_anim2_2.xml │ │ ├── move.xml │ │ ├── rotate.xml │ │ ├── rotate_2.xml │ │ ├── rotate_2_reverse.xml │ │ ├── top_transition.xml │ │ └── top_transition_reverse.xml │ │ ├── drawable │ │ ├── animated_vector_drawable.xml │ │ ├── avd.xml │ │ ├── avd_gooey.xml │ │ ├── avd_gooey_reverse.xml │ │ ├── cake.xml │ │ ├── cast.xml │ │ ├── circle.xml │ │ ├── circle_blue.xml │ │ ├── circle_diff.xml │ │ ├── circle_orange.xml │ │ ├── circle_red.xml │ │ ├── circle_teal.xml │ │ ├── circle_yellow.xml │ │ ├── gooey_reverse.xml │ │ ├── heart_rate.xml │ │ ├── ic_filter_hdr_black_24dp.xml │ │ ├── pencil.xml │ │ ├── plus.xml │ │ ├── ripple.xml │ │ ├── scrim.xml │ │ ├── sign_in_btn.xml │ │ ├── sign_in_btn_shape.xml │ │ ├── vector_circle.xml │ │ └── vector_gooey_fab.xml │ │ ├── layout │ │ ├── activity_events.xml │ │ ├── activity_main.xml │ │ ├── activity_sign_in.xml │ │ ├── content_scrolling.xml │ │ ├── fab_layout.xml │ │ ├── fab_layout_compat.xml │ │ ├── fragment_blank.xml │ │ ├── fragment_fab.xml │ │ ├── progress_circle_layout.xml │ │ ├── tab.xml │ │ └── tab2.xml │ │ ├── menu │ │ └── menu_scrolling.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 │ │ ├── transition │ │ └── enter_event.xml │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── arrays.xml │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── myhexaville │ └── iconanimations │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── 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 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/codeStyleSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 229 | 231 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android Animations 2 | This is a repo which has animation samples from several posts from my blog
3 | Here're some examples 4 | 5 | ![ezgif com-crop 2](https://cloud.githubusercontent.com/assets/13784275/21082838/104a29ea-bfe4-11e6-89f7-d7539e089422.gif) 6 |
7 | ![we](https://i1.wp.com/www.myhexaville.com/wp-content/uploads/2017/01/ezgif.com-crop-4.gif?resize=401%2C339) 8 |
9 | ![wee](https://i0.wp.com/myhexaville.com/wp-content/uploads/2017/01/ezgif.com-crop-11.gif?resize=94%2C155) 10 |
11 | ![wee](http://myhexaville.com/wp-content/uploads/2017/11/giphy.gif?resize=94%2C155) 12 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | dataBinding { 7 | enabled true 8 | } 9 | defaultConfig { 10 | vectorDrawables.useSupportLibrary = true 11 | applicationId "com.myhexaville.iconanimations" 12 | minSdkVersion 21 13 | targetSdkVersion 25 14 | versionCode 1 15 | versionName "1.0" 16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | compile fileTree(dir: 'libs', include: ['*.jar']) 28 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 29 | exclude group: 'com.android.support', module: 'support-annotations' 30 | }) 31 | compile 'com.android.support:appcompat-v7:25.1.0' 32 | compile 'com.android.support:design:25.1.0' 33 | compile 'com.android.support:palette-v7:25.1.0' 34 | compile 'com.android.support:support-v4:25.1.0' 35 | compile 'com.github.bumptech.glide:glide:3.7.0' 36 | testCompile 'junit:junit:4.12' 37 | } 38 | -------------------------------------------------------------------------------- /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 /home/ihor/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/myhexaville/iconanimations/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.myhexaville.iconanimations; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.myhexaville.iconanimations", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/myhexaville/iconanimations/BlankFragment.java: -------------------------------------------------------------------------------- 1 | package com.myhexaville.iconanimations; 2 | 3 | 4 | import android.databinding.DataBindingUtil; 5 | import android.graphics.drawable.AnimatedVectorDrawable; 6 | import android.graphics.drawable.Drawable; 7 | import android.os.Bundle; 8 | import android.support.v4.app.Fragment; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.view.animation.AccelerateDecelerateInterpolator; 13 | import android.view.animation.AccelerateInterpolator; 14 | import android.view.animation.DecelerateInterpolator; 15 | import android.view.animation.LinearInterpolator; 16 | 17 | import com.myhexaville.iconanimations.databinding.FragmentBlankBinding; 18 | 19 | 20 | public class BlankFragment extends Fragment { 21 | private FragmentBlankBinding mBinding; 22 | 23 | public BlankFragment() { 24 | // Required empty public constructor 25 | } 26 | 27 | 28 | @Override 29 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 30 | Bundle savedInstanceState) { 31 | mBinding = DataBindingUtil 32 | .inflate(inflater, R.layout.fragment_blank, container, false); 33 | 34 | mBinding.circleLinear.setInterpolator(new LinearInterpolator()); 35 | mBinding.circleAccelerate.setInterpolator(new AccelerateInterpolator()); 36 | mBinding.circleDecelerate.setInterpolator(new DecelerateInterpolator()); 37 | mBinding.circleAccelerateDecelerate.setInterpolator(new AccelerateDecelerateInterpolator()); 38 | 39 | mBinding.btn.setOnClickListener(new View.OnClickListener() { 40 | @Override 41 | public void onClick(View v) { 42 | mBinding.circleLinear.showAnimation(); 43 | mBinding.circleAccelerate.showAnimation(); 44 | mBinding.circleDecelerate.showAnimation(); 45 | mBinding.circleAccelerateDecelerate.showAnimation(); 46 | } 47 | }); 48 | 49 | 50 | 51 | return mBinding.getRoot(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/myhexaville/iconanimations/CustomTab.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 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 | package com.myhexaville.iconanimations; 18 | 19 | import android.content.Context; 20 | import android.view.LayoutInflater; 21 | import android.widget.FrameLayout; 22 | 23 | /** 24 | * Created by ihor on 2016-12-11. 25 | */ 26 | public class CustomTab extends FrameLayout { 27 | private boolean mIsRevealing; 28 | 29 | public CustomTab(Context context, int position) { 30 | super(context); 31 | 32 | LayoutInflater li = LayoutInflater.from(context); 33 | if (position == 0) { 34 | li.inflate(R.layout.tab, this, true); 35 | } else { 36 | li.inflate(R.layout.tab2, this, true); 37 | } 38 | } 39 | 40 | public boolean isIsRevealing() { 41 | return mIsRevealing; 42 | } 43 | 44 | public void setIsRevealing(boolean mIsRevealing) { 45 | this.mIsRevealing = mIsRevealing; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/myhexaville/iconanimations/FABFragment.java: -------------------------------------------------------------------------------- 1 | package com.myhexaville.iconanimations; 2 | 3 | 4 | import android.databinding.DataBindingUtil; 5 | import android.graphics.drawable.AnimatedVectorDrawable; 6 | import android.graphics.drawable.Drawable; 7 | import android.os.Bundle; 8 | import android.support.graphics.drawable.AnimatedVectorDrawableCompat; 9 | import android.support.graphics.drawable.VectorDrawableCompat; 10 | import android.support.v4.app.Fragment; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.widget.ImageView; 15 | 16 | import com.myhexaville.iconanimations.databinding.FragmentFabBinding; 17 | 18 | 19 | public class FABFragment extends Fragment { 20 | private static final String LOG_TAG = "FABFragment"; 21 | private FragmentFabBinding mBinding; 22 | 23 | public FABFragment() { 24 | // Required empty public constructor 25 | } 26 | 27 | 28 | @Override 29 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 30 | Bundle savedInstanceState) { 31 | mBinding = DataBindingUtil 32 | .inflate(inflater, R.layout.fragment_fab, container, false); 33 | mBinding.fab2.setOnClickListener(new View.OnClickListener() { 34 | @Override 35 | public void onClick(View v) { 36 | Drawable d = mBinding.fab2.getDrawable(); 37 | if (d instanceof AnimatedVectorDrawable) { 38 | ((AnimatedVectorDrawable)d ).start(); 39 | } else if (d instanceof AnimatedVectorDrawableCompat) { 40 | ((AnimatedVectorDrawableCompat) d).start(); 41 | } 42 | } 43 | }); 44 | 45 | mBinding.heartRate.setOnClickListener(new View.OnClickListener() { 46 | @Override 47 | public void onClick(View view) { 48 | ImageView v = (ImageView) view; 49 | Drawable d = v.getDrawable(); 50 | if (d instanceof AnimatedVectorDrawable) { 51 | AnimatedVectorDrawable avd = (AnimatedVectorDrawable) d; 52 | avd.start(); 53 | } else if (d instanceof AnimatedVectorDrawableCompat) { 54 | AnimatedVectorDrawableCompat avd = (AnimatedVectorDrawableCompat) d; 55 | avd.start(); 56 | } 57 | } 58 | }); 59 | return mBinding.getRoot(); 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/myhexaville/iconanimations/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.myhexaville.iconanimations; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.annotation.SuppressLint; 6 | import android.content.Intent; 7 | import android.content.res.ColorStateList; 8 | import android.databinding.DataBindingUtil; 9 | import android.graphics.Color; 10 | import android.graphics.drawable.AnimatedVectorDrawable; 11 | import android.graphics.drawable.Drawable; 12 | import android.os.Build; 13 | import android.os.Bundle; 14 | import android.os.Handler; 15 | import android.support.graphics.drawable.AnimatedVectorDrawableCompat; 16 | import android.support.v4.app.Fragment; 17 | import android.support.v4.app.FragmentStatePagerAdapter; 18 | import android.support.v4.view.ViewPager; 19 | import android.support.v7.app.AppCompatActivity; 20 | import android.util.Log; 21 | import android.util.TypedValue; 22 | import android.view.MotionEvent; 23 | import android.view.View; 24 | import android.view.ViewAnimationUtils; 25 | import android.widget.RelativeLayout; 26 | 27 | import com.myhexaville.iconanimations.databinding.ActivityMainBinding; 28 | 29 | import static android.view.MotionEvent.ACTION_DOWN; 30 | 31 | public class MainActivity extends AppCompatActivity { 32 | private static final String LOG_TAG = "MainActivity"; 33 | private static final int FIRST_COLOR = Color.parseColor("#39dec5"); 34 | private static final int SECOND_COLOR = Color.parseColor("#4648df"); 35 | private int currentSelected = 0; 36 | 37 | 38 | // this ugly part comes from Custom Tab receiving only ACTION_DOWN, when to be sure 39 | // to animate we need ACTION_UP (tab selected) 40 | // that's why I start animation when page is selected and check if it was caused 41 | // by swiping - no reveal animation to show 42 | // by clicking - show reveal animation 43 | private int mTabClicked = -1; 44 | private float x; 45 | private float y; 46 | 47 | 48 | private ActivityMainBinding mBinding; 49 | 50 | @Override 51 | protected void onCreate(Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); 54 | setSupportActionBar(mBinding.toolbar); 55 | 56 | setupToolbarDimens(); 57 | 58 | setupPager(); 59 | 60 | } 61 | 62 | private void setupPager() { 63 | mBinding.pager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) { 64 | @Override 65 | public Fragment getItem(int position) { 66 | if (position == 0) { 67 | return new BlankFragment(); 68 | } else { 69 | return new FABFragment(); 70 | } 71 | } 72 | 73 | @Override 74 | public int getCount() { 75 | return 2; 76 | } 77 | }); 78 | 79 | mBinding.tabs.setupWithViewPager(mBinding.pager); 80 | 81 | setupTouchEvents(); 82 | } 83 | 84 | private void setupTouchEvents() { 85 | mBinding.tabs.getTabAt(0).setCustomView(new CustomTab(this, 0)); 86 | mBinding.tabs.getTabAt(0).getCustomView().setOnTouchListener(new View.OnTouchListener() { 87 | @Override 88 | public boolean onTouch(View view, MotionEvent motionEvent) { 89 | if (motionEvent.getAction() == ACTION_DOWN 90 | && mBinding.pager.getCurrentItem() != 0) { 91 | mTabClicked = 0; 92 | x = motionEvent.getRawX(); 93 | y = motionEvent.getRawY(); 94 | } 95 | return false; 96 | } 97 | }); 98 | 99 | mBinding.tabs.getTabAt(1).setCustomView(new CustomTab(this, 1)); 100 | mBinding.tabs.getTabAt(1).getCustomView().setOnTouchListener(new View.OnTouchListener() { 101 | @Override 102 | public boolean onTouch(View view, MotionEvent motionEvent) { 103 | if (motionEvent.getAction() == ACTION_DOWN 104 | && mBinding.pager.getCurrentItem() != 1) { 105 | mTabClicked = 1; 106 | x = motionEvent.getRawX(); 107 | y = motionEvent.getRawY(); 108 | } 109 | return false; 110 | } 111 | }); 112 | 113 | mBinding.pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 114 | @Override 115 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 116 | if (mTabClicked != -1) { 117 | mTabClicked = -1; 118 | } 119 | } 120 | 121 | @Override 122 | public void onPageSelected(int position) { 123 | if (position == mTabClicked) { 124 | ((CustomTab) mBinding.tabs.getTabAt(position).getCustomView()).setIsRevealing(true); 125 | reveal(position); 126 | } else if (position == 0 127 | && !((CustomTab) mBinding.tabs.getTabAt(0).getCustomView()).isIsRevealing()) { 128 | mBinding.background.setBackgroundColor(FIRST_COLOR); 129 | } else if (position == 1 130 | && !((CustomTab) mBinding.tabs.getTabAt(1).getCustomView()).isIsRevealing()) { 131 | mBinding.background.setBackgroundColor(SECOND_COLOR); 132 | } 133 | } 134 | 135 | @Override 136 | public void onPageScrollStateChanged(int state) { 137 | 138 | } 139 | }); 140 | } 141 | 142 | @SuppressLint("NewApi") 143 | public void animatePencil(View view) { 144 | Drawable d = mBinding.icon.getDrawable(); 145 | if (Build.VERSION.SDK_INT >= 21 && d instanceof AnimatedVectorDrawable) { 146 | ((AnimatedVectorDrawable) d).start(); 147 | } else if (d instanceof AnimatedVectorDrawableCompat) { 148 | ((AnimatedVectorDrawableCompat) d).start(); 149 | } 150 | } 151 | 152 | public void reveal(final int tabPosition) { 153 | mBinding.reveal.setVisibility(View.VISIBLE); 154 | int cx = mBinding.reveal.getWidth(); 155 | int cy = mBinding.reveal.getHeight(); 156 | 157 | float finalRadius = Math.max(cx, cy) * 1.2f; 158 | Animator reveal = ViewAnimationUtils 159 | .createCircularReveal(mBinding.reveal, (int) x, (int) y, 0f, finalRadius); 160 | 161 | reveal.addListener(new AnimatorListenerAdapter() { 162 | @Override 163 | public void onAnimationEnd(Animator animator) { 164 | if (tabPosition == 0) { 165 | mBinding.background.setBackgroundColor(FIRST_COLOR); 166 | ((CustomTab) mBinding.tabs.getTabAt(0).getCustomView()).setIsRevealing(false); 167 | } else { 168 | mBinding.background.setBackgroundColor(SECOND_COLOR); 169 | ((CustomTab) mBinding.tabs.getTabAt(1).getCustomView()).setIsRevealing(false); 170 | } 171 | mBinding.reveal.setVisibility(View.INVISIBLE); 172 | mTabClicked = -1; 173 | } 174 | }); 175 | 176 | if (tabPosition == 0) { 177 | mBinding.reveal.setBackgroundColor(FIRST_COLOR); 178 | } else { 179 | mBinding.reveal.setBackgroundColor(SECOND_COLOR); 180 | } 181 | reveal.start(); 182 | } 183 | 184 | private void setupToolbarDimens() { 185 | int h = getStatusBarHeight() + getActionBarSIze(); 186 | Log.d(LOG_TAG, "setupToolbarDimens: " + h); 187 | RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( 188 | RelativeLayout.LayoutParams.MATCH_PARENT, 189 | RelativeLayout.LayoutParams.WRAP_CONTENT 190 | ); 191 | 192 | params.setMargins(0, getStatusBarHeight(), 0, 0); 193 | 194 | mBinding.toolbar.setLayoutParams(params); 195 | 196 | 197 | RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams( 198 | RelativeLayout.LayoutParams.MATCH_PARENT, 199 | getStatusBarHeight() + getActionBarSIze() * 2 200 | ); 201 | mBinding.background.setLayoutParams(params2); 202 | mBinding.reveal.setLayoutParams(params2); 203 | } 204 | 205 | public int getStatusBarHeight() { 206 | int result = 0; 207 | int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); 208 | if (resourceId > 0) { 209 | result = getResources().getDimensionPixelSize(resourceId); 210 | } 211 | return result; 212 | } 213 | 214 | public int getActionBarSIze() { 215 | int result = 0; 216 | TypedValue tv = new TypedValue(); 217 | if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { 218 | result = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics()); 219 | } 220 | return result; 221 | } 222 | 223 | } 224 | 225 | -------------------------------------------------------------------------------- /app/src/main/java/com/myhexaville/iconanimations/gooey_fab/GooeyFab.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 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 | package com.myhexaville.iconanimations.gooey_fab; 18 | 19 | import android.animation.AnimatorSet; 20 | import android.animation.ObjectAnimator; 21 | import android.animation.StateListAnimator; 22 | import android.annotation.TargetApi; 23 | import android.content.Context; 24 | import android.graphics.Outline; 25 | import android.graphics.drawable.Drawable; 26 | import android.os.Build; 27 | import android.os.Handler; 28 | import android.support.graphics.drawable.AnimatedVectorDrawableCompat; 29 | import android.support.v4.view.animation.FastOutLinearInInterpolator; 30 | import android.util.AttributeSet; 31 | import android.util.Log; 32 | import android.view.View; 33 | import android.view.ViewOutlineProvider; 34 | import android.view.animation.Interpolator; 35 | import android.widget.FrameLayout; 36 | 37 | import com.myhexaville.iconanimations.R; 38 | 39 | import static android.os.Build.VERSION_CODES.LOLLIPOP; 40 | 41 | public class GooeyFab extends FrameLayout { 42 | private static final String LOG_TAG = "GooeyFab"; 43 | static final Interpolator ANIM_INTERPOLATOR = new FastOutLinearInInterpolator(); 44 | static final int[] FOCUSED_ENABLED_STATE_SET = {android.R.attr.state_focused, 45 | android.R.attr.state_enabled}; 46 | static final long PRESSED_ANIM_DURATION = 100; 47 | static final long PRESSED_ANIM_DELAY = 100; 48 | 49 | static final int ANIM_STATE_NONE = 0; 50 | static final int ANIM_STATE_HIDING = 1; 51 | static final int ANIM_STATE_SHOWING = 2; 52 | 53 | private int mHeight; 54 | private boolean mIsAnimating; 55 | private boolean mIsExpanded; 56 | 57 | 58 | public GooeyFab(Context context) { 59 | super(context); 60 | } 61 | 62 | public GooeyFab(Context context, AttributeSet attrs) { 63 | super(context, attrs); 64 | init(); 65 | } 66 | 67 | public GooeyFab(Context context, AttributeSet attrs, int defStyleAttr) { 68 | super(context, attrs, defStyleAttr); 69 | init(); 70 | } 71 | 72 | public GooeyFab(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 73 | super(context, attrs, defStyleAttr, defStyleRes); 74 | init(); 75 | } 76 | 77 | @Override 78 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 79 | super.onSizeChanged(w, h, oldw, oldh); 80 | 81 | mHeight = h; 82 | 83 | if (Build.VERSION.SDK_INT >= LOLLIPOP) { 84 | setOutlineProvider(new CustomOutline(w, h)); 85 | } 86 | } 87 | 88 | private void init() { 89 | final int fabRestElevation = getContext().getResources().getDimensionPixelSize(R.dimen.fab_elevation_rest); 90 | setOnClickListener(new OnClickListener() { 91 | @Override 92 | public void onClick(View v) { 93 | 94 | } 95 | }); 96 | onElevationsChanged(fabRestElevation, 20f); 97 | 98 | inflate(getContext(), R.layout.fab_layout, this); 99 | View v = findViewById(R.id.ripple); 100 | v.setClipToOutline(true); 101 | v.setOnClickListener(new OnClickListener() { 102 | @Override 103 | public void onClick(final View v) { 104 | if (!mIsAnimating) { 105 | mIsAnimating = true; 106 | 107 | onLargeFabClicked(); 108 | v.animate().scaleY(1.1f) 109 | .setDuration(187) 110 | .start(); 111 | 112 | new Handler().postDelayed(new Runnable() { 113 | @Override 114 | public void run() { 115 | v.animate().scaleY(1f) 116 | .setDuration(187) 117 | .start(); 118 | } 119 | }, 187); 120 | } 121 | } 122 | }); 123 | 124 | setBackground( 125 | AnimatedVectorDrawableCompat 126 | .create(getContext(), R.drawable.avd_gooey)); 127 | 128 | // setOnTouchListener(new View.OnTouchListener() { 129 | // @Override 130 | // public boolean onTouch(View v, MotionEvent event) { 131 | // if (event.getAction() == MotionEvent.ACTION_UP) { 132 | // if (!isClickedOnLargeFab(event)) { 133 | // onSmallFabClicked(); 134 | // } 135 | // } 136 | // return true; 137 | // } 138 | // }); 139 | } 140 | 141 | private void onLargeFabClicked() { 142 | Drawable d = getBackground(); 143 | if (d instanceof AnimatedVectorDrawableCompat) { 144 | Log.d(LOG_TAG, "gooey: 2"); 145 | AnimatedVectorDrawableCompat avd = (AnimatedVectorDrawableCompat) d; 146 | avd.start(); 147 | } 148 | 149 | setNextAvd(); 150 | } 151 | 152 | private void setNextAvd() { 153 | new Handler().postDelayed(new Runnable() { 154 | @Override 155 | public void run() { 156 | mIsExpanded = !mIsExpanded; 157 | mIsAnimating = false; 158 | 159 | if (mIsExpanded) { 160 | setBackground( 161 | AnimatedVectorDrawableCompat 162 | .create(getContext(), R.drawable.avd_gooey_reverse)); 163 | } else { 164 | setBackground( 165 | AnimatedVectorDrawableCompat 166 | .create(getContext(), R.drawable.avd_gooey)); 167 | } 168 | } 169 | }, 500); 170 | } 171 | 172 | public int getFabSize() { 173 | return getContext().getResources().getDimensionPixelSize(R.dimen.fab_size); 174 | } 175 | 176 | @TargetApi(LOLLIPOP) 177 | private class CustomOutline extends ViewOutlineProvider { 178 | 179 | int width; 180 | 181 | int height; 182 | 183 | CustomOutline(int width, int height) { 184 | this.width = width; 185 | this.height = height; 186 | } 187 | 188 | @Override 189 | public void getOutline(View view, Outline outline) { 190 | outline.setOval( 191 | 0, 192 | mHeight - getFabSize(), 193 | width, 194 | height); 195 | } 196 | } 197 | 198 | void onElevationsChanged(final float elevation, final float pressedTranslationZ) { 199 | final StateListAnimator stateListAnimator = new StateListAnimator(); 200 | 201 | 202 | // Animate elevation and translationZ to our values when pressed 203 | AnimatorSet set = new AnimatorSet(); 204 | set.play(ObjectAnimator.ofFloat(this, "elevation", elevation).setDuration(0)) 205 | .with(ObjectAnimator.ofFloat(this, View.TRANSLATION_Z, pressedTranslationZ) 206 | .setDuration(PRESSED_ANIM_DURATION)); 207 | set.setInterpolator(ANIM_INTERPOLATOR); 208 | stateListAnimator.addState(PRESSED_ENABLED_STATE_SET, set); 209 | 210 | // Same deal for when we're focused 211 | set = new AnimatorSet(); 212 | set.play(ObjectAnimator.ofFloat(this, "elevation", elevation).setDuration(0)) 213 | .with(ObjectAnimator.ofFloat(this, View.TRANSLATION_Z, pressedTranslationZ) 214 | .setDuration(PRESSED_ANIM_DURATION)); 215 | set.setInterpolator(ANIM_INTERPOLATOR); 216 | stateListAnimator.addState(FOCUSED_ENABLED_STATE_SET, set); 217 | 218 | // Animate translationZ to 0 if not pressed 219 | set = new AnimatorSet(); 220 | // Use an AnimatorSet to set a start delay since there is a bug with ValueAnimator that 221 | // prevents it from being cancelled properly when used with a StateListAnimator. 222 | AnimatorSet anim = new AnimatorSet(); 223 | anim.play(ObjectAnimator.ofFloat(this, View.TRANSLATION_Z, 0f) 224 | .setDuration(PRESSED_ANIM_DURATION)) 225 | .after(PRESSED_ANIM_DURATION); 226 | set.play(ObjectAnimator.ofFloat(this, "elevation", elevation).setDuration(0)) 227 | .with(anim); 228 | set.setInterpolator(ANIM_INTERPOLATOR); 229 | stateListAnimator.addState(ENABLED_STATE_SET, set); 230 | 231 | // Animate everything to 0 when disabled 232 | set = new AnimatorSet(); 233 | set.play(ObjectAnimator.ofFloat(this, "elevation", 0f).setDuration(0)) 234 | .with(ObjectAnimator.ofFloat(this, View.TRANSLATION_Z, 0f).setDuration(0)); 235 | set.setInterpolator(ANIM_INTERPOLATOR); 236 | stateListAnimator.addState(EMPTY_STATE_SET, set); 237 | 238 | setStateListAnimator(stateListAnimator); 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /app/src/main/java/com/myhexaville/iconanimations/gooey_fab/GooeyFabCompat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 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 | package com.myhexaville.iconanimations.gooey_fab; 18 | 19 | import android.annotation.TargetApi; 20 | import android.content.Context; 21 | import android.content.res.TypedArray; 22 | import android.graphics.Outline; 23 | import android.graphics.drawable.Drawable; 24 | import android.os.Build; 25 | import android.os.Handler; 26 | import android.util.AttributeSet; 27 | import android.view.View; 28 | import android.view.ViewOutlineProvider; 29 | import android.widget.FrameLayout; 30 | import android.widget.LinearLayout; 31 | 32 | import com.myhexaville.iconanimations.R; 33 | 34 | import java.util.ArrayList; 35 | import java.util.List; 36 | 37 | import static android.os.Build.VERSION_CODES.LOLLIPOP; 38 | import static android.view.Gravity.BOTTOM; 39 | import static android.view.Gravity.CENTER; 40 | import static android.view.Gravity.CENTER_HORIZONTAL; 41 | import static com.myhexaville.iconanimations.gooey_fab.GooeyFabCompatImpl.POSITION_LARGE_FAB; 42 | // not pre L yet 43 | public class GooeyFabCompat extends LinearLayout { 44 | private static final String LOG_TAG = "GooeyFabCompat"; 45 | private int mSmallFabCount = 1; 46 | private int mWidth; 47 | private int mHeight; 48 | private boolean mIsAnimating; 49 | private Drawable[] mIcons; 50 | 51 | 52 | public GooeyFabCompat(Context context) { 53 | super(context); 54 | } 55 | 56 | public GooeyFabCompat(Context context, AttributeSet attrs) { 57 | super(context, attrs); 58 | init(context, attrs); 59 | } 60 | 61 | public GooeyFabCompat(Context context, AttributeSet attrs, int defStyleAttr) { 62 | super(context, attrs, defStyleAttr); 63 | init(context, attrs); 64 | } 65 | 66 | public GooeyFabCompat(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 67 | super(context, attrs, defStyleAttr, defStyleRes); 68 | init(context, attrs); 69 | } 70 | 71 | private void init(Context c, AttributeSet attrs) { 72 | getAttributes(c, attrs); 73 | setupLayoutParams(); 74 | addFabs(c); 75 | } 76 | 77 | @Override 78 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 79 | super.onSizeChanged(w, h, oldw, oldh); 80 | mWidth = w; 81 | mHeight = h; 82 | } 83 | 84 | private void setupLayoutParams() { 85 | setOrientation(VERTICAL); 86 | setGravity(CENTER); 87 | } 88 | 89 | private void addFabs(Context c) { 90 | final GooeyFabCompatImpl largeFab = new GooeyFabCompatImpl(c, true, POSITION_LARGE_FAB); 91 | 92 | final List smallFabs = new ArrayList<>(); 93 | addView(largeFab); 94 | largeFab.setIcon(mIcons[0]); 95 | for (int i = 0; i < mSmallFabCount; i++) { 96 | GooeyFabCompatImpl f = new GooeyFabCompatImpl(c, false, i); 97 | f.setIcon(mIcons[i + 1]); 98 | smallFabs.add(f); 99 | addView(f, 0); 100 | f.setOnClickListener(new OnClickListener() { 101 | @Override 102 | public void onClick(View v) { 103 | 104 | } 105 | }); 106 | } 107 | 108 | largeFab.setOnClickListener(new OnClickListener() { 109 | @Override 110 | public void onClick(View v) { 111 | if (!mIsAnimating) { 112 | mIsAnimating = true; 113 | largeFab.showAnimation(); 114 | for (GooeyFabCompatImpl smallFab : smallFabs) { 115 | smallFab.showAnimation(); 116 | } 117 | new Handler().postDelayed(new Runnable() { 118 | @Override 119 | public void run() { 120 | mIsAnimating = false; 121 | } 122 | }, 300); 123 | } 124 | } 125 | }); 126 | } 127 | 128 | private void getAttributes(Context c, AttributeSet attrs) { 129 | TypedArray a = c.getTheme().obtainStyledAttributes( 130 | attrs, 131 | R.styleable.GooeyFabCompat, 132 | 0, 0); 133 | final int id = a.getResourceId(R.styleable.GooeyFabCompat_fabIcons, 0); 134 | TypedArray icons = getResources().obtainTypedArray(id); 135 | try { 136 | // animation currently looks good only for one mini fab. Fix is coming in the next versions 137 | // mSmallFabCount = a.getInt(R.styleable.GooeyFabCompat_numberOfSmallFab, 0); 138 | mIcons = new Drawable[mSmallFabCount + 1]; 139 | for (int i = 0; i < mIcons.length; i++) { 140 | mIcons[i] = icons.getDrawable(i); 141 | } 142 | } finally { 143 | a.recycle(); 144 | icons.recycle(); 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/com/myhexaville/iconanimations/gooey_fab/GooeyFabCompatImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 The Android Open Source Project 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 | package com.myhexaville.iconanimations.gooey_fab; 18 | 19 | import android.animation.AnimatorSet; 20 | import android.animation.ObjectAnimator; 21 | import android.animation.StateListAnimator; 22 | import android.animation.ValueAnimator; 23 | import android.annotation.TargetApi; 24 | import android.content.Context; 25 | import android.graphics.Canvas; 26 | import android.graphics.Color; 27 | import android.graphics.Outline; 28 | import android.graphics.Paint; 29 | import android.graphics.RectF; 30 | import android.graphics.drawable.Drawable; 31 | import android.os.Build; 32 | import android.os.Handler; 33 | import android.support.v4.view.animation.FastOutLinearInInterpolator; 34 | import android.view.View; 35 | import android.view.ViewOutlineProvider; 36 | import android.view.animation.Interpolator; 37 | import android.widget.FrameLayout; 38 | import android.widget.ImageView; 39 | 40 | import com.myhexaville.iconanimations.R; 41 | 42 | import static android.graphics.Paint.Style.FILL; 43 | import static android.os.Build.VERSION_CODES.LOLLIPOP; 44 | import static android.view.Gravity.BOTTOM; 45 | import static android.view.Gravity.CENTER; 46 | import static android.view.Gravity.CENTER_HORIZONTAL; 47 | import static android.widget.ListPopupWindow.WRAP_CONTENT; 48 | 49 | /** 50 | * Created with love by ihor on 2017-01-27. 51 | */ 52 | final class GooeyFabCompatImpl extends FrameLayout { 53 | private static final String LOG_TAG = "GooeyFabCompatImpl"; 54 | static final Interpolator ANIM_INTERPOLATOR = new FastOutLinearInInterpolator(); 55 | static final int[] FOCUSED_ENABLED_STATE_SET = {android.R.attr.state_focused, 56 | android.R.attr.state_enabled}; 57 | static final long PRESSED_ANIM_DURATION = 100; 58 | 59 | private ImageView mIcon; 60 | static final int POSITION_LARGE_FAB = -1; 61 | private final int mStartTanslationY; 62 | private final int mAnimationTanslationY; 63 | private Paint mPaint; 64 | private int mWidth; 65 | private int mHeight; 66 | private boolean mIsLargeFab; 67 | 68 | private int mPositionFromBottom; 69 | private boolean mIsExpanded; 70 | private float mCenterY; 71 | private float mGooeyPart; 72 | private View mRipple; 73 | 74 | public GooeyFabCompatImpl(Context context, boolean isLarge, int positionFromBottom) { 75 | super(context); 76 | mIsLargeFab = isLarge; 77 | mPositionFromBottom = positionFromBottom; 78 | int position = mPositionFromBottom + 1; 79 | mStartTanslationY = getFabHeight() * position + (getBottomMargin() * position) + fourDp(); 80 | mAnimationTanslationY = getFabWidth() * position + (getBottomMargin() * position); 81 | init(); 82 | } 83 | 84 | @Override 85 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 86 | super.onSizeChanged(w, h, oldw, oldh); 87 | mWidth = w; 88 | mHeight = h; 89 | 90 | mCenterY = getCenterY(); 91 | 92 | if (Build.VERSION.SDK_INT >= LOLLIPOP) { 93 | setOutlineProvider(new CustomOutline()); 94 | } 95 | } 96 | 97 | private float getCenterY() { 98 | return mIsLargeFab 99 | ? getGooeyPartHeight() + (getFabWidth() / 2) 100 | : mHeight / 2; 101 | } 102 | 103 | @Override 104 | protected void onDraw(Canvas canvas) { 105 | super.onDraw(canvas); 106 | 107 | RectF gooeyPart = new RectF(0, 108 | mCenterY - getArcAbsolute(), 109 | mWidth, 110 | mCenterY + getArcAbsolute()); 111 | 112 | RectF backgroundCircle = new RectF(0, 113 | mCenterY - getFabWidth() / 2, 114 | mWidth, 115 | mCenterY + getFabWidth() / 2); 116 | 117 | canvas.drawArc( 118 | gooeyPart, 119 | 0, 120 | mIsLargeFab ? -180 : 180, 121 | false, 122 | mPaint 123 | ); 124 | 125 | canvas.drawArc( 126 | backgroundCircle, 127 | 0, 128 | 360, 129 | false, 130 | mPaint 131 | ); 132 | } 133 | 134 | public void showAnimation() { 135 | if (!mIsLargeFab) { 136 | if (!mIsExpanded) { 137 | mIcon.setAlpha(0f); 138 | } 139 | 140 | animate().translationYBy(mIsExpanded 141 | ? mAnimationTanslationY 142 | : -mAnimationTanslationY) 143 | .setDuration(250) 144 | .start(); 145 | 146 | mIcon.animate().alpha(!mIsExpanded ? 1f : 0f).setDuration(500).start(); 147 | mGooeyPart = getGooeyPartHeight(); 148 | invalidate(); 149 | } else { 150 | mIcon.animate().rotationBy(mIsExpanded ? -45 : 45).setDuration(187).start(); 151 | ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(187); 152 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 153 | @Override 154 | public void onAnimationUpdate(ValueAnimator animation) { 155 | float v = (float) animation.getAnimatedValue(); 156 | mGooeyPart = getGooeyPartHeight() * v; 157 | invalidate(); 158 | } 159 | }); 160 | animator.start(); 161 | } 162 | 163 | new Handler().postDelayed(new Runnable() { 164 | @Override 165 | public void run() { 166 | ValueAnimator animator = ValueAnimator.ofFloat(1f, 0f).setDuration(187); 167 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 168 | @Override 169 | public void onAnimationUpdate(ValueAnimator animation) { 170 | float v = (float) animation.getAnimatedValue(); 171 | mGooeyPart = getGooeyPartHeight() * v; 172 | invalidate(); 173 | } 174 | }); 175 | animator.start(); 176 | } 177 | }, 187); 178 | 179 | new Handler().postDelayed(new Runnable() { 180 | @Override 181 | public void run() { 182 | mIsExpanded = !mIsExpanded; 183 | } 184 | }, 250); 185 | 186 | } 187 | 188 | private void init() { 189 | inflate(); 190 | addRipple(); 191 | setWillNotDraw(false); 192 | setSize(); 193 | setPaint(); 194 | moveToStartingPosition(); 195 | setParams(); 196 | addIcon(); 197 | } 198 | 199 | private void inflate() { 200 | inflate(getContext(), R.layout.fab_layout_compat, this); 201 | mRipple = findViewById(R.id.ripple); 202 | } 203 | 204 | private void addRipple() { 205 | LayoutParams params = new LayoutParams(getFabWidth(), getFabWidth()); 206 | if (mIsLargeFab) { 207 | params.gravity = BOTTOM; 208 | } else { 209 | params.gravity = CENTER; 210 | } 211 | mRipple.setLayoutParams(params); 212 | if (isLollipopOrAbove()) { 213 | mRipple.setClipToOutline(true); 214 | } 215 | } 216 | 217 | private void addIcon() { 218 | mIcon = new ImageView(getContext()); 219 | LayoutParams params = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT); 220 | if (mIsLargeFab) { 221 | params.gravity = BOTTOM | CENTER_HORIZONTAL; 222 | params.bottomMargin = dpToPixels(16); 223 | } else { 224 | params.gravity = CENTER; 225 | 226 | } 227 | mIcon.setLayoutParams(params); 228 | addView(mIcon); 229 | } 230 | 231 | private void setPaint() { 232 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 233 | mPaint.setColor(Color.parseColor("#008080")); 234 | mPaint.setStyle(FILL); 235 | } 236 | 237 | private void setSize() { 238 | FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(getFabWidth(), getFabHeight()); 239 | layoutParams.bottomMargin = getBottomMargin(); 240 | setLayoutParams(layoutParams); 241 | } 242 | 243 | private void setParams() { 244 | if (isLollipopOrAbove()) { 245 | onElevationsChanged(getFabElevation(true), dpToPixels(3)); 246 | } 247 | } 248 | 249 | private void moveToStartingPosition() { 250 | if (!mIsLargeFab) { 251 | setTranslationY(mStartTanslationY); 252 | } 253 | } 254 | 255 | private int getFabWidth() { 256 | return getContext().getResources().getDimensionPixelSize( 257 | mIsLargeFab 258 | ? R.dimen.fab_size 259 | : R.dimen.fab_size_small); 260 | } 261 | 262 | private int getFabHeight() { 263 | if (mIsLargeFab) { 264 | return getFabWidth() + getGooeyPartHeight(); 265 | } else { 266 | return getFabWidth() + getGooeyPartHeight() * 2; 267 | } 268 | } 269 | 270 | private int getBottomMargin() { 271 | if (mIsLargeFab) { 272 | return 0; 273 | } else { 274 | return getContext().getResources().getDimensionPixelSize(R.dimen.small_fab_margin_bottom); 275 | } 276 | } 277 | 278 | private int getFabElevation(boolean isRest) { 279 | return getContext().getResources().getDimensionPixelSize( 280 | isRest 281 | ? R.dimen.fab_elevation_rest 282 | : R.dimen.fab_elevation_pressed); 283 | } 284 | 285 | private int getGooeyPartHeight() { 286 | return getContext().getResources() 287 | .getDimensionPixelSize( 288 | mIsLargeFab 289 | ? R.dimen.fab_gooey_part 290 | : R.dimen.fab_gooey_part_small); 291 | } 292 | 293 | @TargetApi(LOLLIPOP) 294 | private class CustomOutline extends ViewOutlineProvider { 295 | 296 | CustomOutline() { 297 | } 298 | 299 | @Override 300 | public void getOutline(View view, Outline outline) { 301 | int top = mIsLargeFab ? getGooeyPartHeight() : (int) (mCenterY - getFabWidth() / 2); 302 | int bottom = mIsLargeFab ? mHeight : (int) (mCenterY + getFabWidth() / 2); 303 | 304 | outline.setOval( 305 | 0, 306 | top, 307 | mWidth, 308 | bottom); 309 | } 310 | } 311 | 312 | private float getArcAbsolute() { 313 | return getFabWidth() / 2 + mGooeyPart; 314 | } 315 | 316 | void setIcon(Drawable icon) { 317 | mIcon.setImageDrawable(icon); 318 | } 319 | 320 | private int fourDp() { 321 | return getResources().getDimensionPixelSize(R.dimen.fab_gooey_part_small); 322 | } 323 | 324 | private int dpToPixels(int i) { 325 | return (int) (getResources().getDisplayMetrics().density * i); 326 | } 327 | 328 | @TargetApi(21) 329 | void onElevationsChanged(final float elevation, final float pressedTranslationZ) { 330 | final StateListAnimator stateListAnimator = new StateListAnimator(); 331 | 332 | 333 | // Animate elevation and translationZ to our values when pressed 334 | AnimatorSet set = new AnimatorSet(); 335 | set.play(ObjectAnimator.ofFloat(this, "elevation", elevation).setDuration(0)) 336 | .with(ObjectAnimator.ofFloat(this, View.TRANSLATION_Z, pressedTranslationZ) 337 | .setDuration(PRESSED_ANIM_DURATION)); 338 | set.setInterpolator(ANIM_INTERPOLATOR); 339 | stateListAnimator.addState(PRESSED_ENABLED_STATE_SET, set); 340 | 341 | // Same deal for when we're focused 342 | set = new AnimatorSet(); 343 | set.play(ObjectAnimator.ofFloat(this, "elevation", elevation).setDuration(0)) 344 | .with(ObjectAnimator.ofFloat(this, View.TRANSLATION_Z, pressedTranslationZ) 345 | .setDuration(PRESSED_ANIM_DURATION)); 346 | set.setInterpolator(ANIM_INTERPOLATOR); 347 | stateListAnimator.addState(FOCUSED_ENABLED_STATE_SET, set); 348 | 349 | // Animate translationZ to 0 if not pressed 350 | set = new AnimatorSet(); 351 | // Use an AnimatorSet to set a start delay since there is a bug with ValueAnimator that 352 | // prevents it from being cancelled properly when used with a StateListAnimator. 353 | AnimatorSet anim = new AnimatorSet(); 354 | anim.play(ObjectAnimator.ofFloat(this, View.TRANSLATION_Z, 0f) 355 | .setDuration(PRESSED_ANIM_DURATION)) 356 | .after(PRESSED_ANIM_DURATION); 357 | set.play(ObjectAnimator.ofFloat(this, "elevation", elevation).setDuration(0)) 358 | .with(anim); 359 | set.setInterpolator(ANIM_INTERPOLATOR); 360 | stateListAnimator.addState(ENABLED_STATE_SET, set); 361 | 362 | // Animate everything to 0 when disabled 363 | set = new AnimatorSet(); 364 | set.play(ObjectAnimator.ofFloat(this, "elevation", 0f).setDuration(0)) 365 | .with(ObjectAnimator.ofFloat(this, View.TRANSLATION_Z, 0f).setDuration(0)); 366 | set.setInterpolator(ANIM_INTERPOLATOR); 367 | stateListAnimator.addState(EMPTY_STATE_SET, set); 368 | 369 | setStateListAnimator(stateListAnimator); 370 | } 371 | 372 | private boolean isLollipopOrAbove() { 373 | return Build.VERSION.SDK_INT >= 21; 374 | } 375 | } 376 | -------------------------------------------------------------------------------- /app/src/main/java/com/myhexaville/iconanimations/progress_circle_layout/OnCircleAnimationListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 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 | package com.myhexaville.iconanimations.progress_circle_layout; 18 | 19 | public interface OnCircleAnimationListener { 20 | void onCircleAnimation(String currentAnimationValue); 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/myhexaville/iconanimations/progress_circle_layout/ProgressCircleLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 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 | package com.myhexaville.iconanimations.progress_circle_layout; 18 | 19 | import android.content.Context; 20 | import android.content.res.TypedArray; 21 | import android.util.AttributeSet; 22 | import android.util.Log; 23 | import android.view.animation.Interpolator; 24 | import android.widget.FrameLayout; 25 | import android.widget.LinearLayout; 26 | import android.widget.TextView; 27 | 28 | import com.myhexaville.iconanimations.R; 29 | 30 | import static android.widget.LinearLayout.HORIZONTAL; 31 | import static android.widget.LinearLayout.VERTICAL; 32 | 33 | public class ProgressCircleLayout extends FrameLayout { 34 | private ProgressCircleView mCircle; 35 | private LinearLayout mValuesLayout; 36 | private TextView mValue; 37 | private TextView mMetrics; 38 | 39 | private static final String LOG_TAG = "ProgressCircleLayout"; 40 | 41 | public ProgressCircleLayout(Context context) { 42 | super(context); 43 | } 44 | 45 | public ProgressCircleLayout(Context context, AttributeSet attrs) { 46 | super(context, attrs); 47 | Log.d(LOG_TAG, "ProgressCircleLayout: "); 48 | init(context, attrs); 49 | mCircle.init(context, attrs); 50 | } 51 | 52 | public ProgressCircleLayout(Context context, AttributeSet attrs, int defStyleAttr) { 53 | super(context, attrs, defStyleAttr); 54 | init(context, attrs); 55 | mCircle.init(context, attrs); 56 | } 57 | 58 | public ProgressCircleLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 59 | super(context, attrs, defStyleAttr, defStyleRes); 60 | init(context, attrs); 61 | mCircle.init(context, attrs); 62 | } 63 | 64 | private void init(Context c, AttributeSet attrs) { 65 | findViews(); 66 | 67 | setOnCircleAnimationListener(); 68 | 69 | setupValues(c, attrs); 70 | } 71 | 72 | private void setOnCircleAnimationListener() { 73 | mCircle.setOnCircleAnimationListener(new OnCircleAnimationListener() { 74 | @Override 75 | public void onCircleAnimation(String currentAnimationValue) { 76 | if (!mValue.getText().equals(currentAnimationValue)) { 77 | mValue.setText(currentAnimationValue); 78 | } 79 | } 80 | }); 81 | } 82 | 83 | private void findViews() { 84 | inflate(getContext(), R.layout.progress_circle_layout, this); 85 | mCircle = (ProgressCircleView) findViewById(R.id.circle); 86 | mValuesLayout = (LinearLayout) findViewById(R.id.values_layout); 87 | mValue = (TextView) findViewById(R.id.value); 88 | mMetrics = (TextView) findViewById(R.id.metrics); 89 | } 90 | 91 | public void setInterpolator(Interpolator i) { 92 | mCircle.setInterpolator(i); 93 | } 94 | 95 | public void showAnimation() { 96 | mCircle.showAnimation(); 97 | } 98 | 99 | public void setupValues(Context c, AttributeSet attrs) { 100 | TypedArray a = c.getTheme().obtainStyledAttributes( 101 | attrs, 102 | R.styleable.ProgressCircleLayout, 103 | 0, 0); 104 | 105 | try { 106 | int metricsGravity = a.getInt(R.styleable.ProgressCircleLayout_metricsGravity, 0); 107 | String metrics = a.getString(R.styleable.ProgressCircleLayout_metrics); 108 | String value = a.getString(R.styleable.ProgressCircleLayout_currentValue); 109 | 110 | setupValues(metricsGravity, metrics, value); 111 | } finally { 112 | a.recycle(); 113 | } 114 | } 115 | 116 | private void setupValues(int metricsGravity, String metrics, String value) { 117 | if (metricsGravity == 0) { 118 | LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mMetrics.getLayoutParams(); 119 | params.setMargins( 120 | (int) (getContext().getResources().getDisplayMetrics().density * 4), 121 | 0, 122 | 0, 123 | 0); 124 | 125 | mValuesLayout.setOrientation(HORIZONTAL); 126 | } else { 127 | mValuesLayout.setOrientation(VERTICAL); 128 | } 129 | 130 | mValue.setText(value); 131 | mMetrics.setText(metrics); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /app/src/main/java/com/myhexaville/iconanimations/progress_circle_layout/ProgressCircleView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 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 | package com.myhexaville.iconanimations.progress_circle_layout; 18 | 19 | import android.content.Context; 20 | import android.content.res.ColorStateList; 21 | import android.content.res.TypedArray; 22 | import android.graphics.Canvas; 23 | import android.graphics.Color; 24 | import android.graphics.Paint; 25 | import android.util.AttributeSet; 26 | import android.util.Log; 27 | import android.util.TypedValue; 28 | import android.view.View; 29 | import android.view.animation.AccelerateDecelerateInterpolator; 30 | import android.view.animation.Interpolator; 31 | 32 | import com.myhexaville.iconanimations.R; 33 | 34 | final class ProgressCircleView extends View { 35 | private static final String LOG_TAG = "ProgressCircleView"; 36 | private static final int DEFAULT_ANIMATION_TIME = 1000; 37 | private Interpolator mInterpolator; 38 | private OnCircleAnimationListener mListener; 39 | 40 | 41 | private int mStartValue; 42 | private int mCurrentValue; 43 | private int mEndValue; 44 | 45 | private float mStrokeWidth; 46 | private int mAnimationDuration; 47 | private int mBackCircleColor; 48 | private int mForegroundCircleColor; 49 | 50 | private boolean mAnimateOnDisplay; 51 | 52 | private float mAnimationSpeed; 53 | private Paint mBackCirclePaint; 54 | private Paint mForegroundCirclePaint; 55 | private float mCurrentAngle; 56 | 57 | private int mEndAngle; 58 | private long mAnimationStartTime; 59 | 60 | public ProgressCircleView(Context context) { 61 | super(context); 62 | mInterpolator = new AccelerateDecelerateInterpolator(); 63 | } 64 | 65 | public ProgressCircleView(Context context, AttributeSet attrs) { 66 | super(context, attrs); 67 | } 68 | 69 | public ProgressCircleView(Context context, AttributeSet attrs, int defStyleAttr) { 70 | super(context, attrs, defStyleAttr); 71 | } 72 | 73 | public ProgressCircleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 74 | super(context, attrs, defStyleAttr, defStyleRes); 75 | } 76 | 77 | public void init(Context context, AttributeSet attrs) { 78 | mInterpolator = new AccelerateDecelerateInterpolator(); 79 | 80 | readAttributesAndSetupFields(context, attrs); 81 | 82 | setupPaint(); 83 | } 84 | 85 | 86 | @Override 87 | protected void onDraw(final Canvas canvas) { 88 | super.onDraw(canvas); 89 | if (mAnimationStartTime == 0) { 90 | mAnimationStartTime = System.currentTimeMillis(); 91 | } 92 | 93 | canvas.drawCircle( 94 | getWidth() / 2, 95 | getHeight() / 2, 96 | getWidth() / 2 - mStrokeWidth / 2, 97 | mBackCirclePaint); 98 | 99 | 100 | canvas.drawArc( 101 | 0 + mStrokeWidth / 2, 102 | 0 + mStrokeWidth / 2, 103 | getWidth() - mStrokeWidth / 2, 104 | getHeight() - mStrokeWidth / 2, 105 | -90, 106 | mAnimateOnDisplay ? getCurrentFrameAngle() : mEndAngle, 107 | false, 108 | mForegroundCirclePaint 109 | ); 110 | 111 | if (mAnimateOnDisplay && mCurrentAngle < mEndAngle) { 112 | invalidate(); 113 | } 114 | } 115 | 116 | public void showAnimation() { 117 | mAnimateOnDisplay = true; 118 | mCurrentAngle = 0f; 119 | mAnimationStartTime = 0; 120 | invalidate(); 121 | } 122 | 123 | 124 | private void readAttributesAndSetupFields(Context context, AttributeSet attrs) { 125 | TypedArray a = context.getTheme().obtainStyledAttributes( 126 | attrs, 127 | R.styleable.ProgressCircleLayout, 128 | 0, 0); 129 | 130 | try { 131 | applyAttributes(context, a); 132 | 133 | setEndAngle(); 134 | 135 | setAnimationSpeed(); 136 | 137 | log(); 138 | } finally { 139 | a.recycle(); 140 | } 141 | } 142 | 143 | private void applyAttributes(Context context, TypedArray a) { 144 | mStartValue = a.getInt(R.styleable.ProgressCircleLayout_startValue, 0); 145 | mCurrentValue = a.getInt(R.styleable.ProgressCircleLayout_currentValue, 0); 146 | mEndValue = a.getInt(R.styleable.ProgressCircleLayout_endValue, 0); 147 | 148 | mAnimateOnDisplay = a.getBoolean(R.styleable.ProgressCircleLayout_animateOnDisplay, true); 149 | 150 | mAnimationDuration = a.getInt(R.styleable.ProgressCircleLayout_animationDuration, DEFAULT_ANIMATION_TIME); 151 | 152 | readBackCircleColorFromAttributes(a); 153 | 154 | readForegroundColorFromAttributes(context, a); 155 | 156 | mStrokeWidth = a.getDimension(R.styleable.ProgressCircleLayout_strokeWidth, getDefaultStrokeWidth(context)); 157 | } 158 | 159 | private void readForegroundColorFromAttributes(Context context, TypedArray a) { 160 | ColorStateList fc = a.getColorStateList(R.styleable.ProgressCircleLayout_foregroundCircleColor); 161 | if (fc != null) { 162 | mForegroundCircleColor = fc.getDefaultColor(); 163 | } else { 164 | mForegroundCircleColor = getAccentColor(context); 165 | } 166 | } 167 | 168 | private void readBackCircleColorFromAttributes(TypedArray a) { 169 | ColorStateList bc = a.getColorStateList(R.styleable.ProgressCircleLayout_backgroundCircleColor); 170 | if (bc != null) { 171 | mBackCircleColor = bc.getDefaultColor(); 172 | } else { 173 | mBackCircleColor = Color.parseColor("16000000"); 174 | } 175 | } 176 | 177 | private void setAnimationSpeed() { 178 | float seconds = (float) mAnimationDuration / 1000; 179 | int i = (int) (seconds * 60); 180 | mAnimationSpeed = (float) mEndAngle / i; 181 | } 182 | 183 | private void setEndAngle() { 184 | int totalLength = mEndValue - mStartValue; 185 | int pathGone = mCurrentValue - mStartValue; 186 | float v = ((float) pathGone / totalLength); 187 | mEndAngle = (int) (360 * v); 188 | } 189 | 190 | private void log() { 191 | Log.d(LOG_TAG, "readAttributesAndSetupFields: start value " + mStartValue); 192 | Log.d(LOG_TAG, "readAttributesAndSetupFields: current value " + mCurrentValue); 193 | Log.d(LOG_TAG, "readAttributesAndSetupFields: end value " + mEndValue); 194 | Log.d(LOG_TAG, "readAttributesAndSetupFields: end angle " + mEndAngle); 195 | Log.d(LOG_TAG, "readAttributesAndSetupFields: animation speed " + mAnimationSpeed); 196 | Log.d(LOG_TAG, "readAttributesAndSetupFields: animation time " + mAnimationDuration); 197 | } 198 | 199 | private void setupPaint() { 200 | setupBackCirclePaint(); 201 | 202 | setupFrontCirclePaint(); 203 | } 204 | 205 | private void setupFrontCirclePaint() { 206 | mForegroundCirclePaint = new Paint(); 207 | 208 | mForegroundCirclePaint.setColor(mForegroundCircleColor); 209 | mForegroundCirclePaint.setStyle(Paint.Style.STROKE); 210 | mForegroundCirclePaint.setStrokeCap(Paint.Cap.ROUND); 211 | mForegroundCirclePaint.setStrokeWidth(mStrokeWidth); 212 | } 213 | 214 | private void setupBackCirclePaint() { 215 | mBackCirclePaint = new Paint(); 216 | 217 | mBackCirclePaint.setColor(mBackCircleColor); 218 | mBackCirclePaint.setStyle(Paint.Style.STROKE); 219 | 220 | mBackCirclePaint.setStrokeWidth(mStrokeWidth); 221 | } 222 | 223 | private float getCurrentFrameAngle() { 224 | long now = System.currentTimeMillis(); 225 | float pathGone = ((float) (now - mAnimationStartTime) / (mAnimationDuration)); 226 | float interpolatedPathGone = mInterpolator.getInterpolation(pathGone); 227 | 228 | if (pathGone < 1.0f) { 229 | mCurrentAngle = mEndAngle * interpolatedPathGone; 230 | mListener.onCircleAnimation(getCurrentAnimationFrameValue(interpolatedPathGone)); 231 | } else { 232 | mCurrentAngle = mEndAngle; 233 | mListener.onCircleAnimation(getCurrentAnimationFrameValue(1.0f)); 234 | 235 | } 236 | 237 | return mCurrentAngle; 238 | } 239 | 240 | void setOnCircleAnimationListener(OnCircleAnimationListener l) { 241 | mListener = l; 242 | } 243 | 244 | private int getAccentColor(Context context) { 245 | TypedValue typedValue = new TypedValue(); 246 | 247 | TypedArray a = context.obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorAccent}); 248 | int color = a.getColor(0, 0); 249 | 250 | a.recycle(); 251 | 252 | return color; 253 | } 254 | 255 | private int getDefaultStrokeWidth(Context context) { 256 | return (int) (context.getResources().getDisplayMetrics().density * 10); 257 | } 258 | 259 | public void setInterpolator(Interpolator i) { 260 | mInterpolator = i; 261 | } 262 | 263 | public String getCurrentAnimationFrameValue(float interpolatedPathGone) { 264 | int value = Math.round(((mCurrentValue - mStartValue) * interpolatedPathGone)) + mStartValue; 265 | 266 | return String.valueOf(value); 267 | } 268 | } 269 | 270 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_down.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_down_and_scale.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/animator/fade_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/animator/fade_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/animator/gooey_path_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/animator/gooey_path_anim2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/animator/move.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/animator/rotate.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/animator/rotate_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/animator/rotate_2_reverse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/animator/top_transition.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 20 | 21 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/animator/top_transition_reverse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 20 | 21 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/animated_vector_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 17 | 18 | 19 | 20 | 21 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/avd.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/avd_gooey.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 12 | 13 | 16 | 17 | 20 | 21 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/avd_gooey_reverse.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 12 | 13 | 16 | 17 | 20 | 21 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/cake.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/cast.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle_blue.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle_diff.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle_orange.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle_red.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle_teal.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle_yellow.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gooey_reverse.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 21 | 22 | 28 | 32 | 33 | 34 | 35 | 39 | 45 | 46 | 53 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/heart_rate.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 14 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 34 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_filter_hdr_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/pencil.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 18 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/plus.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/scrim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/sign_in_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/sign_in_btn_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/vector_circle.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 11 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/vector_gooey_fab.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 21 | 22 | 28 | 32 | 33 | 34 | 35 | 39 | 45 | 46 | 52 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_events.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 13 | 14 | 21 | 22 | 32 | 33 | 44 | 45 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 259 | 260 | 264 | 265 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 16 | 17 | 22 | 23 | 28 | 29 | 41 | 42 | 47 | 48 | 49 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_sign_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | 30 | 31 | 39 | 40 | 46 | 47 | 48 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_scrolling.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fab_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fab_layout_compat.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_blank.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 19 | 20 | 24 | 25 | 40 | 41 | 42 | 51 | 52 | 56 | 57 | 72 | 73 | 74 | 82 | 83 | 87 | 88 | 103 | 104 | 105 | 115 | 116 | 120 | 121 | 136 | 137 | 138 |