From 03317d5b4ecb6d77cbd1eaeb69c8a3d08f2b97db Mon Sep 17 00:00:00 2001 From: igor-sos Date: Wed, 6 May 2026 01:22:24 +0700 Subject: [PATCH] User_2 --- Material-Animations/.gitignore | 35 + Material-Animations/LICENSE.md | 21 + Material-Animations/README.md | 648 + Material-Animations/app/.gitignore | 1 + Material-Animations/app/build.gradle | 29 + Material-Animations/app/proguard-rules.pro | 17 + .../material_animations/ApplicationTest.java | 13 + .../app/src/main/AndroidManifest.xml | 44 + .../AnimationsActivity1.java | 98 + .../AnimationsActivity2.java | 145 + .../BaseDetailActivity.java | 37 + .../material_animations/MainActivity.java | 59 + .../material_animations/RevealActivity.java | 291 + .../lgvalle/material_animations/Sample.java | 38 + .../SamplesRecyclerAdapter.java | 98 + .../SharedElementActivity.java | 48 + .../SharedElementFragment1.java | 77 + .../SharedElementFragment2.java | 33 + .../TransitionActivity1.java | 112 + .../TransitionActivity2.java | 58 + .../TransitionActivity3.java | 61 + .../material_animations/TransitionHelper.java | 73 + .../app/src/main/res/drawable/circle_24dp.xml | 9 + .../app/src/main/res/drawable/square.xml | 14 + .../main/res/layout/activity_animations1.xml | 78 + .../main/res/layout/activity_animations2.xml | 82 + .../res/layout/activity_animations_scene0.xml | 12 + .../res/layout/activity_animations_scene1.xml | 34 + .../res/layout/activity_animations_scene2.xml | 34 + .../res/layout/activity_animations_scene3.xml | 34 + .../res/layout/activity_animations_scene4.xml | 34 + .../app/src/main/res/layout/activity_main.xml | 32 + .../src/main/res/layout/activity_reveal.xml | 98 + .../res/layout/activity_sharedelement.xml | 45 + .../activity_sharedelement_fragment1.xml | 34 + .../activity_sharedelement_fragment2.xml | 45 + .../main/res/layout/activity_transition1.xml | 89 + .../main/res/layout/activity_transition2.xml | 60 + .../main/res/layout/activity_transition3.xml | 62 + .../app/src/main/res/layout/row_sample.xml | 37 + .../app/src/main/res/layout/square.xml | 9 + .../app/src/main/res/menu/menu_main.xml | 6 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3418 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2206 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4842 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7718 bytes .../changebounds_with_arcmotion.xml | 14 + .../app/src/main/res/transition/explode.xml | 6 + .../res/transition/slide_and_changebounds.xml | 6 + .../slide_and_changebounds_sequential.xml | 7 + ...gebounds_sequential_with_interpolators.xml | 7 + .../main/res/transition/slide_from_bottom.xml | 6 + .../app/src/main/res/values-w820dp/dimens.xml | 6 + .../app/src/main/res/values/colors.xml | 72 + .../app/src/main/res/values/dimens.xml | 17 + .../app/src/main/res/values/strings.xml | 19 + .../app/src/main/res/values/styles.xml | 114 + Material-Animations/build.gradle | 19 + .../gradle/wrapper/gradle-wrapper.properties | 6 + Material-Animations/gradlew.bat | 90 + .../screenshots/A_startActivity_B.png | Bin 0 -> 31678 bytes Material-Animations/screenshots/B_back_A.png | Bin 0 -> 30900 bytes .../screenshots/a_b_shared_element.png | Bin 0 -> 53680 bytes Material-Animations/screenshots/example1.gif | Bin 0 -> 620454 bytes Material-Animations/screenshots/example2.gif | Bin 0 -> 819814 bytes Material-Animations/screenshots/example3.gif | Bin 0 -> 289205 bytes .../screenshots/reveal_blue.gif | Bin 0 -> 125543 bytes .../screenshots/reveal_green.gif | Bin 0 -> 63131 bytes .../screenshots/reveal_red.gif | Bin 0 -> 62552 bytes .../screenshots/reveal_yellow.gif | Bin 0 -> 85437 bytes .../screenshots/scene-transition.gif | Bin 0 -> 211841 bytes .../screenshots/scenes_anim.gif | Bin 0 -> 595199 bytes .../screenshots/shared_element.png | Bin 0 -> 20511 bytes .../screenshots/shared_element_anim.gif | Bin 0 -> 808421 bytes .../screenshots/shared_element_no_overlap.gif | Bin 0 -> 350327 bytes .../screenshots/shared_element_overlap.gif | Bin 0 -> 629397 bytes .../screenshots/shared_reveal_anim.gif | Bin 0 -> 270508 bytes .../transition-shared-elements.gif | Bin 0 -> 419581 bytes .../transition-shared-elements2.gif | Bin 0 -> 464297 bytes .../screenshots/transition_A_to_B.png | Bin 0 -> 11547 bytes .../screenshots/transition_B_to_A.png | Bin 0 -> 10878 bytes .../screenshots/transition_explode.gif | Bin 0 -> 803535 bytes .../screenshots/transition_fade.gif | Bin 0 -> 824454 bytes .../screenshots/transition_fade2.gif | Bin 0 -> 369013 bytes .../screenshots/transition_slide.gif | Bin 0 -> 814589 bytes .../screenshots/view_layout_anim.gif | Bin 0 -> 382497 bytes Material-Animations/settings.gradle | 1 + gron | 1 + hug | 1 + remote-librares.txt | 3 + socket.io/.github/ISSUE_TEMPLATE.md | 32 + socket.io/.github/PULL_REQUEST_TEMPLATE.md | 18 + socket.io/.gitignore | 14 + socket.io/.travis.yml | 14 + socket.io/LICENSE | 22 + socket.io/Readme.md | 243 + socket.io/docs/API.md | 880 + socket.io/docs/README.md | 15 + socket.io/docs/emit.md | 64 + socket.io/examples/chat/README.md | 25 + socket.io/examples/chat/index.js | 76 + socket.io/examples/chat/package.json | 15 + socket.io/examples/chat/public/index.html | 28 + socket.io/examples/chat/public/main.js | 282 + socket.io/examples/chat/public/style.css | 149 + socket.io/examples/cluster-haproxy/README.md | 31 + .../cluster-haproxy/docker-compose.yml | 51 + .../cluster-haproxy/haproxy/Dockerfile | 2 + .../cluster-haproxy/haproxy/haproxy.cfg | 31 + .../cluster-haproxy/server/Dockerfile | 15 + .../examples/cluster-haproxy/server/index.js | 87 + .../cluster-haproxy/server/package.json | 17 + .../cluster-haproxy/server/public/index.html | 28 + .../cluster-haproxy/server/public/main.js | 286 + .../cluster-haproxy/server/public/style.css | 149 + socket.io/examples/cluster-httpd/README.md | 31 + .../examples/cluster-httpd/docker-compose.yml | 51 + .../examples/cluster-httpd/httpd/Dockerfile | 2 + .../examples/cluster-httpd/httpd/httpd.conf | 52 + .../examples/cluster-httpd/server/Dockerfile | 15 + .../examples/cluster-httpd/server/index.js | 82 + .../cluster-httpd/server/package.json | 17 + .../cluster-httpd/server/public/index.html | 28 + .../cluster-httpd/server/public/main.js | 286 + .../cluster-httpd/server/public/style.css | 149 + socket.io/examples/cluster-nginx/README.md | 31 + .../examples/cluster-nginx/docker-compose.yml | 51 + .../examples/cluster-nginx/nginx/Dockerfile | 3 + .../examples/cluster-nginx/nginx/nginx.conf | 35 + .../examples/cluster-nginx/server/Dockerfile | 15 + .../examples/cluster-nginx/server/index.js | 82 + .../cluster-nginx/server/package.json | 17 + .../cluster-nginx/server/public/index.html | 28 + .../cluster-nginx/server/public/main.js | 286 + .../cluster-nginx/server/public/style.css | 149 + socket.io/examples/custom-parsers/README.md | 50 + .../examples/custom-parsers/package.json | 21 + .../examples/custom-parsers/public/index.html | 13 + .../examples/custom-parsers/src/client1.js | 8 + .../examples/custom-parsers/src/client2.js | 11 + .../examples/custom-parsers/src/client3.js | 11 + .../examples/custom-parsers/src/client4.js | 11 + .../custom-parsers/src/custom-parser.js | 125 + .../examples/custom-parsers/src/server.js | 55 + .../custom-parsers/support/webpack.config.js | 15 + .../examples/webpack-build-server/README.md | 18 + .../webpack-build-server/lib/index.js | 16 + .../webpack-build-server/package.json | 15 + .../support/webpack.config.js | 9 + socket.io/examples/webpack-build/README.md | 20 + socket.io/examples/webpack-build/index.html | 13 + socket.io/examples/webpack-build/lib/index.js | 12 + socket.io/examples/webpack-build/package.json | 21 + .../examples/webpack-build/support/noop.js | 2 + .../webpack-build/support/webpack.config.js | 8 + .../support/webpack.config.json-parser.js | 33 + .../support/webpack.config.slim.js | 31 + socket.io/examples/whiteboard/README.md | 17 + socket.io/examples/whiteboard/index.js | 16 + socket.io/examples/whiteboard/package.json | 19 + .../examples/whiteboard/public/index.html | 23 + socket.io/examples/whiteboard/public/main.js | 100 + .../examples/whiteboard/public/style.css | 44 + socket.io/lib/client.js | 273 + socket.io/lib/index.js | 522 + socket.io/lib/namespace.js | 296 + socket.io/lib/parent-namespace.js | 39 + socket.io/lib/socket.js | 572 + socket.io/package.json | 0 socket.io/test/fixtures/big.jpg | Bin 0 -> 4712052 bytes socket.io/test/fixtures/big.json | 174066 +++++++++++++++ socket.io/test/fixtures/server-close.js | 11 + socket.io/test/socket.io.js | 2459 + socket.io/test/support/doge.jpg | Bin 0 -> 32796 bytes 174 files changed, 186238 insertions(+) create mode 100644 Material-Animations/.gitignore create mode 100644 Material-Animations/LICENSE.md create mode 100644 Material-Animations/README.md create mode 100644 Material-Animations/app/.gitignore create mode 100644 Material-Animations/app/build.gradle create mode 100644 Material-Animations/app/proguard-rules.pro create mode 100644 Material-Animations/app/src/androidTest/java/com/lgvalle/material_animations/ApplicationTest.java create mode 100644 Material-Animations/app/src/main/AndroidManifest.xml create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/AnimationsActivity1.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/AnimationsActivity2.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/BaseDetailActivity.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/MainActivity.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/RevealActivity.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/Sample.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/SamplesRecyclerAdapter.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementActivity.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementFragment1.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementFragment2.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity1.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity2.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity3.java create mode 100644 Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionHelper.java create mode 100644 Material-Animations/app/src/main/res/drawable/circle_24dp.xml create mode 100644 Material-Animations/app/src/main/res/drawable/square.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_animations1.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_animations2.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_animations_scene0.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_animations_scene1.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_animations_scene2.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_animations_scene3.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_animations_scene4.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_main.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_reveal.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_sharedelement.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_sharedelement_fragment1.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_sharedelement_fragment2.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_transition1.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_transition2.xml create mode 100644 Material-Animations/app/src/main/res/layout/activity_transition3.xml create mode 100644 Material-Animations/app/src/main/res/layout/row_sample.xml create mode 100644 Material-Animations/app/src/main/res/layout/square.xml create mode 100644 Material-Animations/app/src/main/res/menu/menu_main.xml create mode 100644 Material-Animations/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 Material-Animations/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 Material-Animations/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 Material-Animations/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 Material-Animations/app/src/main/res/transition/changebounds_with_arcmotion.xml create mode 100644 Material-Animations/app/src/main/res/transition/explode.xml create mode 100644 Material-Animations/app/src/main/res/transition/slide_and_changebounds.xml create mode 100644 Material-Animations/app/src/main/res/transition/slide_and_changebounds_sequential.xml create mode 100644 Material-Animations/app/src/main/res/transition/slide_and_changebounds_sequential_with_interpolators.xml create mode 100644 Material-Animations/app/src/main/res/transition/slide_from_bottom.xml create mode 100644 Material-Animations/app/src/main/res/values-w820dp/dimens.xml create mode 100644 Material-Animations/app/src/main/res/values/colors.xml create mode 100644 Material-Animations/app/src/main/res/values/dimens.xml create mode 100644 Material-Animations/app/src/main/res/values/strings.xml create mode 100644 Material-Animations/app/src/main/res/values/styles.xml create mode 100644 Material-Animations/build.gradle create mode 100644 Material-Animations/gradle/wrapper/gradle-wrapper.properties create mode 100644 Material-Animations/gradlew.bat create mode 100644 Material-Animations/screenshots/A_startActivity_B.png create mode 100644 Material-Animations/screenshots/B_back_A.png create mode 100644 Material-Animations/screenshots/a_b_shared_element.png create mode 100644 Material-Animations/screenshots/example1.gif create mode 100644 Material-Animations/screenshots/example2.gif create mode 100644 Material-Animations/screenshots/example3.gif create mode 100644 Material-Animations/screenshots/reveal_blue.gif create mode 100644 Material-Animations/screenshots/reveal_green.gif create mode 100644 Material-Animations/screenshots/reveal_red.gif create mode 100644 Material-Animations/screenshots/reveal_yellow.gif create mode 100644 Material-Animations/screenshots/scene-transition.gif create mode 100644 Material-Animations/screenshots/scenes_anim.gif create mode 100644 Material-Animations/screenshots/shared_element.png create mode 100644 Material-Animations/screenshots/shared_element_anim.gif create mode 100644 Material-Animations/screenshots/shared_element_no_overlap.gif create mode 100644 Material-Animations/screenshots/shared_element_overlap.gif create mode 100644 Material-Animations/screenshots/shared_reveal_anim.gif create mode 100644 Material-Animations/screenshots/transition-shared-elements.gif create mode 100644 Material-Animations/screenshots/transition-shared-elements2.gif create mode 100644 Material-Animations/screenshots/transition_A_to_B.png create mode 100644 Material-Animations/screenshots/transition_B_to_A.png create mode 100644 Material-Animations/screenshots/transition_explode.gif create mode 100644 Material-Animations/screenshots/transition_fade.gif create mode 100644 Material-Animations/screenshots/transition_fade2.gif create mode 100644 Material-Animations/screenshots/transition_slide.gif create mode 100644 Material-Animations/screenshots/view_layout_anim.gif create mode 100644 Material-Animations/settings.gradle create mode 160000 gron create mode 160000 hug create mode 100644 remote-librares.txt create mode 100644 socket.io/.github/ISSUE_TEMPLATE.md create mode 100644 socket.io/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 socket.io/.gitignore create mode 100644 socket.io/.travis.yml create mode 100644 socket.io/LICENSE create mode 100644 socket.io/Readme.md create mode 100644 socket.io/docs/API.md create mode 100644 socket.io/docs/README.md create mode 100644 socket.io/docs/emit.md create mode 100644 socket.io/examples/chat/README.md create mode 100644 socket.io/examples/chat/index.js create mode 100644 socket.io/examples/chat/package.json create mode 100644 socket.io/examples/chat/public/index.html create mode 100644 socket.io/examples/chat/public/main.js create mode 100644 socket.io/examples/chat/public/style.css create mode 100644 socket.io/examples/cluster-haproxy/README.md create mode 100644 socket.io/examples/cluster-haproxy/docker-compose.yml create mode 100644 socket.io/examples/cluster-haproxy/haproxy/Dockerfile create mode 100644 socket.io/examples/cluster-haproxy/haproxy/haproxy.cfg create mode 100644 socket.io/examples/cluster-haproxy/server/Dockerfile create mode 100644 socket.io/examples/cluster-haproxy/server/index.js create mode 100644 socket.io/examples/cluster-haproxy/server/package.json create mode 100644 socket.io/examples/cluster-haproxy/server/public/index.html create mode 100644 socket.io/examples/cluster-haproxy/server/public/main.js create mode 100644 socket.io/examples/cluster-haproxy/server/public/style.css create mode 100644 socket.io/examples/cluster-httpd/README.md create mode 100644 socket.io/examples/cluster-httpd/docker-compose.yml create mode 100644 socket.io/examples/cluster-httpd/httpd/Dockerfile create mode 100644 socket.io/examples/cluster-httpd/httpd/httpd.conf create mode 100644 socket.io/examples/cluster-httpd/server/Dockerfile create mode 100644 socket.io/examples/cluster-httpd/server/index.js create mode 100644 socket.io/examples/cluster-httpd/server/package.json create mode 100644 socket.io/examples/cluster-httpd/server/public/index.html create mode 100644 socket.io/examples/cluster-httpd/server/public/main.js create mode 100644 socket.io/examples/cluster-httpd/server/public/style.css create mode 100644 socket.io/examples/cluster-nginx/README.md create mode 100644 socket.io/examples/cluster-nginx/docker-compose.yml create mode 100644 socket.io/examples/cluster-nginx/nginx/Dockerfile create mode 100644 socket.io/examples/cluster-nginx/nginx/nginx.conf create mode 100644 socket.io/examples/cluster-nginx/server/Dockerfile create mode 100644 socket.io/examples/cluster-nginx/server/index.js create mode 100644 socket.io/examples/cluster-nginx/server/package.json create mode 100644 socket.io/examples/cluster-nginx/server/public/index.html create mode 100644 socket.io/examples/cluster-nginx/server/public/main.js create mode 100644 socket.io/examples/cluster-nginx/server/public/style.css create mode 100644 socket.io/examples/custom-parsers/README.md create mode 100644 socket.io/examples/custom-parsers/package.json create mode 100644 socket.io/examples/custom-parsers/public/index.html create mode 100644 socket.io/examples/custom-parsers/src/client1.js create mode 100644 socket.io/examples/custom-parsers/src/client2.js create mode 100644 socket.io/examples/custom-parsers/src/client3.js create mode 100644 socket.io/examples/custom-parsers/src/client4.js create mode 100644 socket.io/examples/custom-parsers/src/custom-parser.js create mode 100644 socket.io/examples/custom-parsers/src/server.js create mode 100644 socket.io/examples/custom-parsers/support/webpack.config.js create mode 100644 socket.io/examples/webpack-build-server/README.md create mode 100644 socket.io/examples/webpack-build-server/lib/index.js create mode 100644 socket.io/examples/webpack-build-server/package.json create mode 100644 socket.io/examples/webpack-build-server/support/webpack.config.js create mode 100644 socket.io/examples/webpack-build/README.md create mode 100644 socket.io/examples/webpack-build/index.html create mode 100644 socket.io/examples/webpack-build/lib/index.js create mode 100644 socket.io/examples/webpack-build/package.json create mode 100644 socket.io/examples/webpack-build/support/noop.js create mode 100644 socket.io/examples/webpack-build/support/webpack.config.js create mode 100644 socket.io/examples/webpack-build/support/webpack.config.json-parser.js create mode 100644 socket.io/examples/webpack-build/support/webpack.config.slim.js create mode 100644 socket.io/examples/whiteboard/README.md create mode 100644 socket.io/examples/whiteboard/index.js create mode 100644 socket.io/examples/whiteboard/package.json create mode 100644 socket.io/examples/whiteboard/public/index.html create mode 100644 socket.io/examples/whiteboard/public/main.js create mode 100644 socket.io/examples/whiteboard/public/style.css create mode 100644 socket.io/lib/client.js create mode 100644 socket.io/lib/index.js create mode 100644 socket.io/lib/namespace.js create mode 100644 socket.io/lib/parent-namespace.js create mode 100644 socket.io/lib/socket.js create mode 100644 socket.io/package.json create mode 100644 socket.io/test/fixtures/big.jpg create mode 100644 socket.io/test/fixtures/big.json create mode 100644 socket.io/test/fixtures/server-close.js create mode 100644 socket.io/test/socket.io.js create mode 100644 socket.io/test/support/doge.jpg diff --git a/Material-Animations/.gitignore b/Material-Animations/.gitignore new file mode 100644 index 0000000..eeee0d3 --- /dev/null +++ b/Material-Animations/.gitignore @@ -0,0 +1,35 @@ +# built application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ +gen-external-apklibs/ + +# Local configuration file (sdk path, etc) +local.properties + +# intellij & maven +.classpath +.project +.settings/ +.idea/ +*.iml +*.iws +.DS_Store +log/ +target/ +tmp/ +out/ + +# Gradle +.gradle +build/** +libraries/build/** diff --git a/Material-Animations/LICENSE.md b/Material-Animations/LICENSE.md new file mode 100644 index 0000000..6bf9d91 --- /dev/null +++ b/Material-Animations/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Luis G. Valle + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Material-Animations/README.md b/Material-Animations/README.md new file mode 100644 index 0000000..950e7c8 --- /dev/null +++ b/Material-Animations/README.md @@ -0,0 +1,648 @@ +# UNMAINTAINED +No maintainance is intended. +The content is still valid as a reference but it won't contain the latest new stuff + +[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Material--Animations-brightgreen.svg?style=flat)](http://android-arsenal.com/details/3/1880) + +[Android Transition Framework][transition-framework] can be used for **three** main things: + +1. Animate activity layout content when transitioning from one activity to another. +2. Animate shared elements (Hero views) in transitions between activities. +3. Animate view changes within same activity. + + +## 1. Transitions between Activities + +Animate existing activity layout **content** + +![A Start B][transition_a_to_b] + +When transitioning from `Activity A` to `Activity B` content layout is animated according to defined transition. There are three predefined transitions available on `android.transition.Transition` you can use: **Explode**, **Slide** and **Fade**. +All these transitions track changes to the visibility of target views in activity layout and animate those views to follow transition rules. + +[Explode][explode_link] | [Slide][slide_link] | [Fade][fade_link] +--- | --- | --- +![transition_explode] | ![transition_slide] | ![transition_fade] + + +You can define these transitions **declarative** using XML or **programmatically**. For the Fade Transition sample, it would look like this: + +### Declarative +Transitions are defined on XML files in `res/transition` + +> res/transition/activity_fade.xml + +```xml + + + +``` + +> res/transition/activity_slide.xml + +```xml + + + +``` + +To use these transitions you need to inflate them using `TransitionInflater` + +> MainActivity.java + +```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_transition); + setupWindowAnimations(); + } + + private void setupWindowAnimations() { + Slide slide = TransitionInflater.from(this).inflateTransition(R.transition.activity_slide); + getWindow().setExitTransition(slide); + } + +``` + +> TransitionActivity.java + +```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_transition); + setupWindowAnimations(); + } + + private void setupWindowAnimations() { + Fade fade = TransitionInflater.from(this).inflateTransition(R.transition.activity_fade); + getWindow().setEnterTransition(fade); + } + +``` + +### Programmatically + +> MainActivity.java + +```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_transition); + setupWindowAnimations(); + } + + private void setupWindowAnimations() { + Slide slide = new Slide(); + slide.setDuration(1000); + getWindow().setExitTransition(slide); + } + +``` + +> TransitionActivity.java + +```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_transition); + setupWindowAnimations(); + } + + private void setupWindowAnimations() { + Fade fade = new Fade(); + fade.setDuration(1000); + getWindow().setEnterTransition(fade); + } + +``` + +#### Any of those produce this result: + +![transition_fade] + + +### What is happening step by step: + +1. Activity A starts Activity B + +2. Transition Framework finds A Exit Transition (slide) and apply it to all visible views. +3. Transition Framework finds B Enter Transition (fade) and apply it to all visible views. +4. **On Back Pressed** Transition Framework executes Enter and Exit reverse animations respectively (If we had defined output `returnTransition` and `reenterTransition`, these have been executed instead) + +### ReturnTransition & ReenterTransition + +Return and Reenter Transitions are the reverse animations for Enter and Exit respectively. + + * EnterTransition <--> ReturnTransition + * ExitTransition <--> ReenterTransition + +If Return or Reenter are not defined, Android will execute a reversed version of Enter and Exit Transitions. But if you do define them, you can have different transitions for entering and exiting an activity. + +![b back a][transition_b_to_a] + +We can modify previous Fade sample and define a `ReturnTransition` for `TransitionActivity`, in this case, a **Slide** transition. This way, when returning from B to A, instead of seeing a Fade out (reversed Enter Transition) we will see a **Slide out** transition + +> TransitionActivity.java + +```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_transition); + setupWindowAnimations(); + } + + private void setupWindowAnimations() { + Fade fade = new Fade(); + fade.setDuration(1000); + getWindow().setEnterTransition(fade); + + Slide slide = new Slide(); + slide.setDuration(1000); + getWindow().setReturnTransition(slide); + } + +``` + + +Observe that if no Return Transition is defined then a reversed Enter Transition is executed. +If a Return Transition is defined that one is executed instead. + +Without Return Transition | With Return Transition +--- | --- +Enter: `Fade In` | Enter: `Fade In` +Exit: `Fade Out` | Exit: `Slide out` +![transition_fade] | ![transition_fade2] + + +## 2. Shared elements between Activities + +The idea behind this is having two different views in two different layouts and link them somehow with an animation. + +Transition framework will then do _whatever animations it consider necessary_ to show the user a transition from one view to another. + +Keep this always in mind: the view **is not really moving** from one layout to another. They are two independent views. + + +![A Start B with shared][shared_element] + + +### a) Enable Window Content Transition + +This is something you need to set up once on your app `styles.xml`. + +> values/styles.xml + +```xml + +``` + +Here you can also specify default enter, exit and shared element transitions for the whole app if you want + +```xml + +``` + + + +### b) Define a common transition name + +To make the trick you need to give both, origin and target views, the same **`android:transitionName`**. They may have different ids or properties, but `android:transitionName` must be the same. + +> layout/activity_a.xml + +```xml + +``` + +> layout/activity_b.xml + +```xml + +``` + +### c) Start an activity with a shared element + +Use the `ActivityOptions.makeSceneTransitionAnimation()` method to define shared element origin view and transition name. + +> MainActivity.java + +```java + +blueIconImageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(MainActivity.this, SharedElementActivity.class); + + View sharedView = blueIconImageView; + String transitionName = getString(R.string.blue_name); + + ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName); + startActivity(i, transitionActivityOptions.toBundle()); + } +}); + +``` + + +Just that code will produce this beautiful transition animation: + +![a to b with shared element][shared_element_anim] + +As you can see, Transition framework is creating and executing an animation to create the illusion that views are moving and changing shape from one activity to the other + +## Shared elements between fragments + +Shared element transition works with Fragments in a very similar way as it does with activities. + +Steps **a)** and **b)** are exactly the **same**. Only **c)** changes + +### a) Enable Window Content Transition + +> values/styles.xml + +```xml + +``` + +### b) Define a common transition name + +> layout/fragment_a.xml + +```xml + +``` + +> layout/fragment_b.xml + +```xml + +``` + +### c) Start a fragment with a shared element + +To do this you need to include shared element transition information as part of the **`FragmentTransaction`** process. + +```java +FragmentB fragmentB = FragmentB.newInstance(sample); + +// Defines enter transition for all fragment views +Slide slideTransition = new Slide(Gravity.RIGHT); +slideTransition.setDuration(1000); +sharedElementFragment2.setEnterTransition(slideTransition); + +// Defines enter transition only for shared element +ChangeBounds changeBoundsTransition = TransitionInflater.from(this).inflateTransition(R.transition.change_bounds); +fragmentB.setSharedElementEnterTransition(changeBoundsTransition); + +getFragmentManager().beginTransaction() + .replace(R.id.content, fragmentB) + .addSharedElement(blueView, getString(R.string.blue_name)) + .commit(); +``` + +And this is the final result: + +![shared_element_no_overlap] + +## Allow Transition Overlap + +You can define if enter and exit transitions can overlap each other. + +From [Android documentation](http://developer.android.com/intl/ko/reference/android/app/Fragment.html#getAllowEnterTransitionOverlap()): +> When **true**, the enter transition will start as soon as possible. +> +> When **false**, the enter transition will wait until the exit transition completes before starting. + +This works for both Fragments and Activities shared element transitions. + +```java +FragmentB fragmentB = FragmentB.newInstance(sample); + +// Defines enter transition for all fragment views +Slide slideTransition = new Slide(Gravity.RIGHT); +slideTransition.setDuration(1000); +sharedElementFragment2.setEnterTransition(slideTransition); + +// Defines enter transition only for shared element +ChangeBounds changeBoundsTransition = TransitionInflater.from(this).inflateTransition(R.transition.change_bounds); +fragmentB.setSharedElementEnterTransition(changeBoundsTransition); + +// Prevent transitions for overlapping +fragmentB.setAllowEnterTransitionOverlap(overlap); +fragmentB.setAllowReturnTransitionOverlap(overlap); + +getFragmentManager().beginTransaction() + .replace(R.id.content, fragmentB) + .addSharedElement(blueView, getString(R.string.blue_name)) + .commit(); +``` + +It is very easy to spot the difference in this example: + +Overlap True | Overlap False +--- | --- +Fragment_2 appears on top of Fragment_1 | Fragment_2 waits until Fragment_1 is gone +![shared_element_overlap] | ![shared_element_no_overlap] + + + +## 3. Animate view layout elements + +### Scenes +Transition Framework can also be used to animate element changes within current activity layout. + +Transitions happen between scenes. A scene is just a regular layout which **defines a static state of our UI**. You can transition from one scene to another and Transition Framework will animate views in between. + +```java +scene1 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene1, this); +scene2 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene2, this); +scene3 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene3, this); +scene4 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene4, this); + +(...) + +@Override +public void onClick(View v) { + switch (v.getId()) { + case R.id.button1: + TransitionManager.go(scene1, new ChangeBounds()); + break; + case R.id.button2: + TransitionManager.go(scene2, TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds)); + break; + case R.id.button3: + TransitionManager.go(scene3, TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds_sequential)); + break; + case R.id.button4: + TransitionManager.go(scene4, TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds_sequential_with_interpolators)); + break; + } +} +``` + +That code would produce transition between four scenes in the same activity. Each transition has a different animation defined. + +Transition Framework will take all visible views in current scene and calculate whatever necessary animations are needed to arrange those views according to next scene. + +![scenes_anim] + + +### Layout changes + +Transition Framework can also be used to animate layout property changes in a view. You just need to make whatever changes you want and it will perform necessary animations for you + +#### a) Begin Delayed Transition + +With just this line of code we are telling the framework we are going to perform some UI changes that it will need to animate. + +```java +TransitionManager.beginDelayedTransition(sceneRoot); +``` +#### b) Change view layout properties + + +```java +ViewGroup.LayoutParams params = greenIconView.getLayoutParams(); +params.width = 200; +greenIconView.setLayoutParams(params); + +``` + +Changing view width attribute to make it smaller will trigger a `layoutMeasure`. At that point the Transition framework will record start and ending values and will create an animation to transition from one to another. + + +![view layout animation][view_layout_anim] + + +## 4. (Bonus) Shared elements + Circular Reveal +Circular Reveal is just an animation to show or hide a group of UI elements. It is available since API 21 in `ViewAnimationUtils` class. + + +Circular Reveal animation can be used in combination of Shared Element Transition to create meaningful animations that smoothly teach the user what is happening in the app. + +![reveal_shared_anim] + +What is happening in this example step by step is: + +* Orange circle is a shared element transitioning from `MainActivity` to `RevealActivity`. +* On `RevealActivity` there is a listener to listen for shared element transition end. When that happens it does two things: + * Execute a Circular Reveal animation for the Toolbar + * Execute a scale up animation on `RevealActivity` views using plain old `ViewPropertyAnimator` + + +> Listen to shared element enter transition end + +```java +Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion); +getWindow().setSharedElementEnterTransition(transition); +transition.addListener(new Transition.TransitionListener() { + @Override + public void onTransitionEnd(Transition transition) { + animateRevealShow(toolbar); + animateButtonsIn(); + } + + (...) + +}); + +``` + +> Reveal Toolbar + +```java +private void animateRevealShow(View viewRoot) { + int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; + int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; + int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight()); + + Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius); + viewRoot.setVisibility(View.VISIBLE); + anim.setDuration(1000); + anim.setInterpolator(new AccelerateInterpolator()); + anim.start(); +} +``` + +> Scale up activity layout views + +```java +private void animateButtonsIn() { + for (int i = 0; i < bgViewGroup.getChildCount(); i++) { + View child = bgViewGroup.getChildAt(i); + child.animate() + .setStartDelay(100 + i * DELAY) + .setInterpolator(interpolator) + .alpha(1) + .scaleX(1) + .scaleY(1); + } +} +``` + +### More circular reveal animations + +There are many different ways you can create a reveal animation. The important thing is to use the animation to help the user understand what is happening in the app. + +#### Circular Reveal from the middle of target view + +![reveal_green] + +```java +int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; +int cy = viewRoot.getTop(); +int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight()); + +Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius); +viewRoot.setBackgroundColor(color); +anim.start(); +``` + +#### Circular Reveal from top of target view + animations + +![reveal_blue] + +```java +int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; +int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; +int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight()); + +Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius); +viewRoot.setBackgroundColor(color); +anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + animateButtonsIn(); + } +}); +anim.start(); +``` + + +#### Circular Reveal from touch point + +![reveal_yellow] + +```java +@Override +public boolean onTouch(View view, MotionEvent motionEvent) { + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { + if (view.getId() == R.id.square_yellow) { + revealFromCoordinates(motionEvent.getRawX(), motionEvent.getRawY()); + } + } + return false; +} +``` + +```java +private Animator animateRevealColorFromCoordinates(int x, int y) { + float finalRadius = (float) Math.hypot(viewRoot.getWidth(), viewRoot.getHeight()); + + Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, x, y, 0, finalRadius); + viewRoot.setBackgroundColor(color); + anim.start(); +} +``` + +#### Animate and Reveal + +![reveal_red] + +```java +Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion); +transition.addListener(new Transition.TransitionListener() { + @Override + public void onTransitionEnd(Transition transition) { + animateRevealColor(bgViewGroup, R.color.red); + } + (...) + +}); +TransitionManager.beginDelayedTransition(bgViewGroup, transition); +RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); +layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT); +btnRed.setLayoutParams(layoutParams); +``` + + +# Sample source code + +**[https://github.com/lgvalle/Material-Animations](https://github.com/lgvalle/Material-Animations/)** + + +# More information + + * Alex Lockwood posts about Transition Framework. A great in deep into this topic: [http://www.androiddesignpatterns.com/2014/12/activity-fragment-transitions-in-android-lollipop-part1.html](http://www.androiddesignpatterns.com/2014/12/activity-fragment-transitions-in-android-lollipop-part1.html) + * Amazing repository with lot of Material Design samples by Saul Molinero: [https://github.com/saulmm/Android-Material-Examples](https://github.com/saulmm/Android-Material-Examples) + * Chet Hasse video explaining Transition framework: [https://www.youtube.com/watch?v=S3H7nJ4QaD8](https://www.youtube.com/watch?v=S3H7nJ4QaD8) + + + +[transition-framework]: https://developer.android.com/training/transitions/overview.html + +[explode_link]: https://developer.android.com/reference/android/transition/Explode.html +[fade_link]: https://developer.android.com/reference/android/transition/Fade.html +[slide_link]: https://developer.android.com/reference/android/transition/Slide.html + +[transition_explode]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/transition_explode.gif +[transition_slide]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/transition_slide.gif +[transition_fade]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/transition_fade.gif +[transition_fade2]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/transition_fade2.gif +[transition_a_to_b]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/transition_A_to_B.png +[transition_b_to_a]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/transition_B_to_A.png + +[shared_element]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/shared_element.png +[shared_element_anim]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/shared_element_anim.gif +[shared_element_no_overlap]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/shared_element_no_overlap.gif +[shared_element_overlap]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/shared_element_overlap.gif + +[scenes_anim]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/scenes_anim.gif +[view_layout_anim]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/view_layout_anim.gif + +[reveal_blue]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/reveal_blue.gif +[reveal_red]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/reveal_red.gif +[reveal_green]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/reveal_green.gif +[reveal_yellow]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/reveal_yellow.gif +[reveal_shared_anim]: https://raw.githubusercontent.com/lgvalle/Material-Animations/master/screenshots/shared_reveal_anim.gif diff --git a/Material-Animations/app/.gitignore b/Material-Animations/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/Material-Animations/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Material-Animations/app/build.gradle b/Material-Animations/app/build.gradle new file mode 100644 index 0000000..f3edc1f --- /dev/null +++ b/Material-Animations/app/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.2" + + defaultConfig { + applicationId "com.lgvalle.material_animations" + minSdkVersion 21 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + dataBinding { + enabled = true + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.android.support:recyclerview-v7:23.1.1' +} diff --git a/Material-Animations/app/proguard-rules.pro b/Material-Animations/app/proguard-rules.pro new file mode 100644 index 0000000..0a3081f --- /dev/null +++ b/Material-Animations/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/lgvalle/Developer/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/Material-Animations/app/src/androidTest/java/com/lgvalle/material_animations/ApplicationTest.java b/Material-Animations/app/src/androidTest/java/com/lgvalle/material_animations/ApplicationTest.java new file mode 100644 index 0000000..075e635 --- /dev/null +++ b/Material-Animations/app/src/androidTest/java/com/lgvalle/material_animations/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.lgvalle.material_animations; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/Material-Animations/app/src/main/AndroidManifest.xml b/Material-Animations/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..f31a555 --- /dev/null +++ b/Material-Animations/app/src/main/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/AnimationsActivity1.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/AnimationsActivity1.java new file mode 100644 index 0000000..140ef8c --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/AnimationsActivity1.java @@ -0,0 +1,98 @@ +package com.lgvalle.material_animations; + +import android.content.Intent; +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.transition.Fade; +import android.transition.TransitionManager; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.lgvalle.material_animations.databinding.ActivityAnimations1Binding; + +public class AnimationsActivity1 extends BaseDetailActivity { + private ImageView square; + private ViewGroup viewRoot; + private boolean sizeChanged; + private int savedWidth; + private boolean positionChanged; + private Sample sample; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + bindData(); + setupWindowAnimations(); + setupLayout(); + setupToolbar(); + } + + private void setupWindowAnimations() { + getWindow().setReenterTransition(new Fade()); + } + + private void bindData() { + ActivityAnimations1Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_animations1); + sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE); + binding.setAnimationsSample(sample); + } + + private void setupLayout() { + square = (ImageView) findViewById(R.id.square_green); + viewRoot = (ViewGroup) findViewById(R.id.sample3_root); + findViewById(R.id.sample3_button1).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + changeLayout(); + } + }); + findViewById(R.id.sample3_button2).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + changePosition(); + } + }); + + findViewById(R.id.sample3_button3).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(AnimationsActivity1.this, AnimationsActivity2.class); + i.putExtra(EXTRA_SAMPLE, sample); + transitionTo(i); + } + }); + } + + private void changeLayout() { + TransitionManager.beginDelayedTransition(viewRoot); + + ViewGroup.LayoutParams params = square.getLayoutParams(); + if (sizeChanged) { + params.width = savedWidth; + } else { + savedWidth = params.width; + params.width = 200; + } + sizeChanged = !sizeChanged; + square.setLayoutParams(params); + } + + private void changePosition() { + TransitionManager.beginDelayedTransition(viewRoot); + + LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) square.getLayoutParams(); + if (positionChanged) { + lp.gravity = Gravity.CENTER; + } else { + lp.gravity = Gravity.LEFT; + } + positionChanged = !positionChanged; + square.setLayoutParams(lp); + } + + + +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/AnimationsActivity2.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/AnimationsActivity2.java new file mode 100644 index 0000000..02bed94 --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/AnimationsActivity2.java @@ -0,0 +1,145 @@ +package com.lgvalle.material_animations; + +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.transition.ChangeBounds; +import android.transition.Scene; +import android.transition.Transition; +import android.transition.TransitionInflater; +import android.transition.TransitionManager; +import android.view.View; +import android.view.ViewGroup; + +import com.lgvalle.material_animations.databinding.ActivityAnimations2Binding; + +import java.util.ArrayList; +import java.util.List; + +public class AnimationsActivity2 extends BaseDetailActivity { + + private static final int DELAY = 100; + private Scene scene0; + private Scene scene1; + private Scene scene2; + private Scene scene3; + private Scene scene4; + private final List viewsToAnimate = new ArrayList<>(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + bindData(); + setupLayout(); + setupToolbar(); + setupWindowAnimations(); + } + + private void bindData() { + ActivityAnimations2Binding binding = DataBindingUtil.setContentView( + this, R.layout.activity_animations2); + Sample sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE); + binding.setAnimationsSample(sample); + } + + private void setupWindowAnimations() { + getWindow().setEnterTransition(TransitionInflater.from(this).inflateTransition( + R.transition.slide_from_bottom)); + getWindow().getEnterTransition().addListener(new Transition.TransitionListener() { + @Override + public void onTransitionStart(Transition transition) { + } + + @Override + public void onTransitionCancel(Transition transition) { + } + + @Override + public void onTransitionPause(Transition transition) { + } + + @Override + public void onTransitionResume(Transition transition) { + } + + @Override + public void onTransitionEnd(Transition transition) { + getWindow().getEnterTransition().removeListener(this); + TransitionManager.go(scene0); + } + }); + } + + private void setupLayout() { + final ViewGroup activityRoot = (ViewGroup) findViewById(R.id.buttons_group); + ViewGroup sceneRoot = (ViewGroup) findViewById(R.id.scene_root); + + scene0 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene0, this); + scene0.setEnterAction(new Runnable() { + @Override + public void run() { + for (int i = 0; i < viewsToAnimate.size(); i++) { + View child = viewsToAnimate.get(i); + child.animate() + .setStartDelay(i * DELAY) + .scaleX(1) + .scaleY(1); + + } + } + }); + scene0.setExitAction(new Runnable() { + @Override + public void run() { + TransitionManager.beginDelayedTransition(activityRoot); + View title = scene0.getSceneRoot().findViewById(R.id.scene0_title); + title.setScaleX(0); + title.setScaleY(0); + } + }); + + + scene1 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene1, this); + scene2 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene2, this); + scene3 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene3, this); + scene4 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene4, this); + + View button1 = findViewById(R.id.sample3_button1); + button1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + TransitionManager.go(scene1, new ChangeBounds()); + } + }); + View button2 = findViewById(R.id.sample3_button2); + button2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + TransitionManager.go(scene2, TransitionInflater.from(AnimationsActivity2.this). + inflateTransition(R.transition.slide_and_changebounds)); + } + }); + + View button3 = findViewById(R.id.sample3_button3); + button3.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + TransitionManager.go(scene3, TransitionInflater.from(AnimationsActivity2.this). + inflateTransition(R.transition.slide_and_changebounds_sequential)); + } + }); + + View button4 = findViewById(R.id.sample3_button4); + button4.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + TransitionManager.go(scene4, TransitionInflater.from(AnimationsActivity2.this). + inflateTransition(R.transition.slide_and_changebounds_sequential_with_interpolators)); + } + }); + + viewsToAnimate.add(button1); + viewsToAnimate.add(button2); + viewsToAnimate.add(button3); + viewsToAnimate.add(button4); + } +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/BaseDetailActivity.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/BaseDetailActivity.java new file mode 100644 index 0000000..41f5199 --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/BaseDetailActivity.java @@ -0,0 +1,37 @@ +package com.lgvalle.material_animations; + +import android.content.Intent; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.util.Pair; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.View; + +/** + * Created by lgvalle on 12/09/15. + */ +public class BaseDetailActivity extends AppCompatActivity { + static final String EXTRA_SAMPLE = "sample"; + static final String EXTRA_TYPE = "type"; + static final int TYPE_PROGRAMMATICALLY = 0; + static final int TYPE_XML = 1; + + void setupToolbar() { + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowTitleEnabled(false); + } + + @Override + public boolean onSupportNavigateUp() { + onBackPressed(); + return true; + } + + @SuppressWarnings("unchecked") void transitionTo(Intent i) { + final Pair[] pairs = TransitionHelper.createSafeTransitionParticipants(this, true); + ActivityOptionsCompat transitionActivityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(this, pairs); + startActivity(i, transitionActivityOptions.toBundle()); + } +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/MainActivity.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/MainActivity.java new file mode 100644 index 0000000..daa23dd --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/MainActivity.java @@ -0,0 +1,59 @@ +package com.lgvalle.material_animations; + +import android.os.Bundle; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.transition.Slide; +import android.view.Gravity; + +import java.util.Arrays; +import java.util.List; + +public class MainActivity extends AppCompatActivity { + private List samples; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + setupWindowAnimations(); + setupSamples(); + setupToolbar(); + setupLayout(); + } + + private void setupWindowAnimations() { + // Re-enter transition is executed when returning to this activity + Slide slideTransition = new Slide(); + slideTransition.setSlideEdge(Gravity.LEFT); + slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long)); + getWindow().setReenterTransition(slideTransition); + getWindow().setExitTransition(slideTransition); + } + + private void setupSamples() { + samples = Arrays.asList( + new Sample(ContextCompat.getColor(this, R.color.sample_red), "Transitions"), + new Sample(ContextCompat.getColor(this, R.color.sample_blue), "Shared Elements"), + new Sample(ContextCompat.getColor(this, R.color.sample_green), "View animations"), + new Sample(ContextCompat.getColor(this, R.color.sample_yellow), "Circular Reveal Animation") + ); + } + + private void setupToolbar() { + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayShowTitleEnabled(false); + } + + private void setupLayout() { + RecyclerView recyclerView = (RecyclerView) findViewById(R.id.sample_list); + recyclerView.setHasFixedSize(true); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + SamplesRecyclerAdapter samplesRecyclerAdapter = new SamplesRecyclerAdapter(this, samples); + recyclerView.setAdapter(samplesRecyclerAdapter); + } +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/RevealActivity.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/RevealActivity.java new file mode 100644 index 0000000..ff90439 --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/RevealActivity.java @@ -0,0 +1,291 @@ +package com.lgvalle.material_animations; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.support.annotation.ColorRes; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.Toolbar; +import android.transition.Fade; +import android.transition.Transition; +import android.transition.TransitionInflater; +import android.transition.TransitionManager; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewAnimationUtils; +import android.view.ViewGroup; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.lgvalle.material_animations.databinding.ActivityRevealBinding; + + +public class RevealActivity extends BaseDetailActivity implements View.OnTouchListener { + private static final int DELAY = 100; + private RelativeLayout bgViewGroup; + private Toolbar toolbar; + private Interpolator interpolator; + private TextView body; + private View btnRed; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + bindData(); + setupWindowAnimations(); + setupLayout(); + setupToolbar(); + } + + private void bindData() { + ActivityRevealBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_reveal); + Sample sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE); + binding.setReveal1Sample(sample); + } + + private void setupWindowAnimations() { + interpolator = AnimationUtils.loadInterpolator(this, android.R.interpolator.linear_out_slow_in); + setupEnterAnimations(); + setupExitAnimations(); + } + + private void setupEnterAnimations() { + Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion); + getWindow().setSharedElementEnterTransition(transition); + transition.addListener(new Transition.TransitionListener() { + @Override + public void onTransitionStart(Transition transition) { + } + + @Override + public void onTransitionEnd(Transition transition) { + // Removing listener here is very important because shared element transition is executed again backwards on exit. If we don't remove the listener this code will be triggered again. + transition.removeListener(this); + hideTarget(); + animateRevealShow(toolbar); + animateButtonsIn(); + } + + @Override + public void onTransitionCancel(Transition transition) { + } + + @Override + public void onTransitionPause(Transition transition) { + } + + @Override + public void onTransitionResume(Transition transition) { + } + }); + } + + private void setupExitAnimations() { + Fade returnTransition = new Fade(); + getWindow().setReturnTransition(returnTransition); + returnTransition.setDuration(getResources().getInteger(R.integer.anim_duration_medium)); + returnTransition.setStartDelay(getResources().getInteger(R.integer.anim_duration_medium)); + returnTransition.addListener(new Transition.TransitionListener() { + @Override + public void onTransitionStart(Transition transition) { + transition.removeListener(this); + animateButtonsOut(); + animateRevealHide(bgViewGroup); + } + + @Override + public void onTransitionEnd(Transition transition) { + } + + @Override + public void onTransitionCancel(Transition transition) { + } + + @Override + public void onTransitionPause(Transition transition) { + } + + @Override + public void onTransitionResume(Transition transition) { + } + }); + } + + private void setupLayout() { + bgViewGroup = (RelativeLayout) findViewById(R.id.reveal_root); + toolbar = (Toolbar) findViewById(R.id.toolbar); + body = ((TextView) findViewById(R.id.sample_body)); + View btnGreen = findViewById(R.id.square_green); + btnGreen.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + revealGreen(); + } + }); + btnRed = findViewById(R.id.square_red); + btnRed.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + revealRed(); + } + }); + View btnBlue = findViewById(R.id.square_blue); + btnBlue.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + revealBlue(); + } + }); + findViewById(R.id.square_yellow).setOnTouchListener(this); + } + + private void revealBlue() { + animateButtonsOut(); + Animator anim = animateRevealColorFromCoordinates(bgViewGroup, R.color.sample_blue, bgViewGroup.getWidth() / 2, 0); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + animateButtonsIn(); + } + }); + body.setText(R.string.reveal_body4); + body.setTextColor(ContextCompat.getColor(this, R.color.theme_blue_background)); + } + + private void revealRed() { + final ViewGroup.LayoutParams originalParams = btnRed.getLayoutParams(); + Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion); + transition.addListener(new Transition.TransitionListener() { + @Override + public void onTransitionStart(Transition transition) { + } + + @Override + public void onTransitionEnd(Transition transition) { + animateRevealColor(bgViewGroup, R.color.sample_red); + body.setText(R.string.reveal_body3); + body.setTextColor(ContextCompat.getColor(RevealActivity.this, R.color.theme_red_background)); + btnRed.setLayoutParams(originalParams); + } + + @Override + public void onTransitionCancel(Transition transition) { + } + + @Override + public void onTransitionPause(Transition transition) { + + } + + @Override + public void onTransitionResume(Transition transition) { + + } + }); + TransitionManager.beginDelayedTransition(bgViewGroup, transition); + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); + layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT); + btnRed.setLayoutParams(layoutParams); + } + + private void revealYellow(float x, float y) { + animateRevealColorFromCoordinates(bgViewGroup, R.color.sample_yellow, (int) x, (int) y); + body.setText(R.string.reveal_body1); + body.setTextColor(ContextCompat.getColor(this, R.color.theme_yellow_background)); + } + + private void revealGreen() { + animateRevealColor(bgViewGroup, R.color.sample_green); + body.setText(R.string.reveal_body2); + body.setTextColor(ContextCompat.getColor(this, R.color.theme_green_background)); + } + + private void hideTarget() { + findViewById(R.id.shared_target).setVisibility(View.GONE); + } + + private void animateButtonsIn() { + for (int i = 0; i < bgViewGroup.getChildCount(); i++) { + View child = bgViewGroup.getChildAt(i); + child.animate() + .setStartDelay(100 + i * DELAY) + .setInterpolator(interpolator) + .alpha(1) + .scaleX(1) + .scaleY(1); + } + } + + private void animateButtonsOut() { + for (int i = 0; i < bgViewGroup.getChildCount(); i++) { + View child = bgViewGroup.getChildAt(i); + child.animate() + .setStartDelay(i) + .setInterpolator(interpolator) + .alpha(0) + .scaleX(0f) + .scaleY(0f); + } + } + + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { + if (view.getId() == R.id.square_yellow) { + revealYellow(motionEvent.getRawX(), motionEvent.getRawY()); + } + } + return false; + } + + private void animateRevealShow(View viewRoot) { + int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; + int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; + int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight()); + + Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius); + viewRoot.setVisibility(View.VISIBLE); + anim.setDuration(getResources().getInteger(R.integer.anim_duration_long)); + anim.setInterpolator(new AccelerateInterpolator()); + anim.start(); + } + + private void animateRevealColor(ViewGroup viewRoot, @ColorRes int color) { + int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; + int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; + animateRevealColorFromCoordinates(viewRoot, color, cx, cy); + } + + private Animator animateRevealColorFromCoordinates(ViewGroup viewRoot, @ColorRes int color, int x, int y) { + float finalRadius = (float) Math.hypot(viewRoot.getWidth(), viewRoot.getHeight()); + + Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, x, y, 0, finalRadius); + viewRoot.setBackgroundColor(ContextCompat.getColor(this, color)); + anim.setDuration(getResources().getInteger(R.integer.anim_duration_long)); + anim.setInterpolator(new AccelerateDecelerateInterpolator()); + anim.start(); + return anim; + } + + private void animateRevealHide(final View viewRoot) { + int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; + int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; + int initialRadius = viewRoot.getWidth(); + + Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, initialRadius, 0); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + viewRoot.setVisibility(View.INVISIBLE); + } + }); + anim.setDuration(getResources().getInteger(R.integer.anim_duration_medium)); + anim.start(); + } +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/Sample.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/Sample.java new file mode 100644 index 0000000..2f9823e --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/Sample.java @@ -0,0 +1,38 @@ +package com.lgvalle.material_animations; + +import android.databinding.BindingAdapter; +import android.support.annotation.ColorRes; +import android.support.v4.graphics.drawable.DrawableCompat; +import android.widget.ImageView; + +import java.io.Serializable; + +/** + * Created by lgvalle on 04/09/15. + */ +public class Sample implements Serializable { + + final int color; + private final String name; + + public Sample(@ColorRes int color, String name) { + this.color = color; + this.name = name; + } + + @BindingAdapter("bind:colorTint") + public static void setColorTint(ImageView view, @ColorRes int color) { + DrawableCompat.setTint(view.getDrawable(), color); + //view.setColorFilter(color, PorterDuff.Mode.SRC_IN); + } + + public String getName() { + return name; + } + + public int getColor() { + return color; + } + + +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SamplesRecyclerAdapter.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SamplesRecyclerAdapter.java new file mode 100644 index 0000000..78049b6 --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SamplesRecyclerAdapter.java @@ -0,0 +1,98 @@ +package com.lgvalle.material_animations; + +import android.app.Activity; +import android.content.Intent; +import android.databinding.DataBindingUtil; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.util.Pair; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.lgvalle.material_animations.databinding.RowSampleBinding; + +import java.util.List; + +public class SamplesRecyclerAdapter extends RecyclerView.Adapter { + private final Activity activity; + private final List samples; + + public SamplesRecyclerAdapter(Activity activity, List samples) { + this.activity = activity; + this.samples = samples; + } + + @Override + public SamplesViewHolder onCreateViewHolder(ViewGroup parent, int position) { + RowSampleBinding binding = RowSampleBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new SamplesViewHolder(binding.getRoot()); + } + + @Override + public void onBindViewHolder(final SamplesViewHolder viewHolder, final int position) { + final Sample sample = samples.get(viewHolder.getAdapterPosition()); + viewHolder.binding.setSample(sample); + viewHolder.binding.sampleLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + switch (viewHolder.getAdapterPosition()) { + case 0: + transitionToActivity(TransitionActivity1.class, sample); + break; + case 1: + transitionToActivity(SharedElementActivity.class, viewHolder, sample); + break; + case 2: + transitionToActivity(AnimationsActivity1.class, sample); + break; + case 3: + transitionToActivity(RevealActivity.class, viewHolder, sample, R.string.transition_reveal1); + break; + } + } + }); + } + + private void transitionToActivity(Class target, Sample sample) { + final Pair[] pairs = TransitionHelper.createSafeTransitionParticipants(activity, true); + startActivity(target, pairs, sample); + } + + + private void transitionToActivity(Class target, SamplesViewHolder viewHolder, Sample sample, int transitionName) { + final Pair[] pairs = TransitionHelper.createSafeTransitionParticipants(activity, false, + new Pair<>(viewHolder.binding.sampleIcon, activity.getString(transitionName))); + startActivity(target, pairs, sample); + } + + private void transitionToActivity(Class target, SamplesViewHolder viewHolder, Sample sample) { + final Pair[] pairs = TransitionHelper.createSafeTransitionParticipants(activity, false, + new Pair<>(viewHolder.binding.sampleIcon, activity.getString(R.string.square_blue_name)), + new Pair<>(viewHolder.binding.sampleName, activity.getString(R.string.sample_blue_title))); + startActivity(target, pairs, sample); + } + + private void startActivity(Class target, Pair[] pairs, Sample sample) { + Intent i = new Intent(activity, target); + ActivityOptionsCompat transitionActivityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, pairs); + i.putExtra("sample", sample); + activity.startActivity(i, transitionActivityOptions.toBundle()); + } + + @Override + public int getItemCount() { + return samples.size(); + } + + + public class SamplesViewHolder extends RecyclerView.ViewHolder { + final RowSampleBinding binding; + + public SamplesViewHolder(View rootView) { + super(rootView); + binding = DataBindingUtil.bind(rootView); + + } + } +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementActivity.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementActivity.java new file mode 100644 index 0000000..fc902fc --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementActivity.java @@ -0,0 +1,48 @@ +package com.lgvalle.material_animations; + +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.transition.ChangeBounds; +import android.transition.Slide; +import android.view.Gravity; + +import com.lgvalle.material_animations.databinding.ActivitySharedelementBinding; + +public class SharedElementActivity extends BaseDetailActivity { + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Sample sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE); + bindData(sample); + setupWindowAnimations(); + setupLayout(sample); + setupToolbar(); + } + + private void bindData(Sample sample) { + ActivitySharedelementBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_sharedelement); + binding.setSharedSample(sample); + } + + private void setupWindowAnimations() { + // We are not interested in defining a new Enter Transition. Instead we change default transition duration + getWindow().getEnterTransition().setDuration(getResources().getInteger(R.integer.anim_duration_long)); + } + + private void setupLayout(Sample sample) { + // Transition for fragment1 + Slide slideTransition = new Slide(Gravity.LEFT); + slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long)); + // Create fragment and define some of it transitions + SharedElementFragment1 sharedElementFragment1 = SharedElementFragment1.newInstance(sample); + sharedElementFragment1.setReenterTransition(slideTransition); + sharedElementFragment1.setExitTransition(slideTransition); + sharedElementFragment1.setSharedElementEnterTransition(new ChangeBounds()); + + getSupportFragmentManager().beginTransaction() + .replace(R.id.sample2_content, sharedElementFragment1) + .commit(); + } +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementFragment1.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementFragment1.java new file mode 100644 index 0000000..58dff8a --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementFragment1.java @@ -0,0 +1,77 @@ +package com.lgvalle.material_animations; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.graphics.drawable.DrawableCompat; +import android.transition.ChangeBounds; +import android.transition.Slide; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +/** + * Created by lgvalle on 05/09/15. + */ +public class SharedElementFragment1 extends Fragment { + + private static final String EXTRA_SAMPLE = "sample"; + + public static SharedElementFragment1 newInstance(Sample sample) { + + Bundle args = new Bundle(); + + args.putSerializable(EXTRA_SAMPLE, sample); + SharedElementFragment1 fragment = new SharedElementFragment1(); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.activity_sharedelement_fragment1, container, false); + final Sample sample = (Sample) getArguments().getSerializable(EXTRA_SAMPLE); + + final ImageView squareBlue = (ImageView) view.findViewById(R.id.square_blue); + DrawableCompat.setTint(squareBlue.getDrawable(), sample.color); + + view.findViewById(R.id.sample2_button1).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + addNextFragment(sample, squareBlue, false); + } + }); + + view.findViewById(R.id.sample2_button2).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + addNextFragment(sample, squareBlue, true); + } + }); + + return view; + } + + private void addNextFragment(Sample sample, ImageView squareBlue, boolean overlap) { + SharedElementFragment2 sharedElementFragment2 = SharedElementFragment2.newInstance(sample); + + Slide slideTransition = new Slide(Gravity.RIGHT); + slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_medium)); + + ChangeBounds changeBoundsTransition = new ChangeBounds(); + changeBoundsTransition.setDuration(getResources().getInteger(R.integer.anim_duration_medium)); + + sharedElementFragment2.setEnterTransition(slideTransition); + sharedElementFragment2.setAllowEnterTransitionOverlap(overlap); + sharedElementFragment2.setAllowReturnTransitionOverlap(overlap); + sharedElementFragment2.setSharedElementEnterTransition(changeBoundsTransition); + + getFragmentManager().beginTransaction() + .replace(R.id.sample2_content, sharedElementFragment2) + .addToBackStack(null) + .addSharedElement(squareBlue, getString(R.string.square_blue_name)) + .commit(); + } + +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementFragment2.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementFragment2.java new file mode 100644 index 0000000..bf0c630 --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/SharedElementFragment2.java @@ -0,0 +1,33 @@ +package com.lgvalle.material_animations; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.graphics.drawable.DrawableCompat; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +public class SharedElementFragment2 extends Fragment { + private static final String EXTRA_SAMPLE = "sample"; + + public static SharedElementFragment2 newInstance(Sample sample) { + Bundle args = new Bundle(); + args.putSerializable(EXTRA_SAMPLE, sample); + SharedElementFragment2 fragment = new SharedElementFragment2(); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.activity_sharedelement_fragment2, container, false); + Sample sample = (Sample) getArguments().getSerializable(EXTRA_SAMPLE); + + ImageView squareBlue = (ImageView) view.findViewById(R.id.square_blue); + DrawableCompat.setTint(squareBlue.getDrawable(), sample.color); + + return view; + } + +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity1.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity1.java new file mode 100644 index 0000000..d994990 --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity1.java @@ -0,0 +1,112 @@ +package com.lgvalle.material_animations; + +import android.content.Intent; +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.transition.Fade; +import android.transition.Slide; +import android.transition.Visibility; +import android.view.View; + +import com.lgvalle.material_animations.databinding.ActivityTransition1Binding; + +public class TransitionActivity1 extends BaseDetailActivity { + private Sample sample; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + bindData(); + setupWindowAnimations(); + setupLayout(); + setupToolbar(); + } + + private void bindData() { + ActivityTransition1Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_transition1); + sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE); + binding.setTransition1Sample(sample); + } + + private void setupWindowAnimations() { + Visibility enterTransition = buildEnterTransition(); + getWindow().setEnterTransition(enterTransition); + } + + + private void setupLayout() { + findViewById(R.id.sample1_button1).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(TransitionActivity1.this, TransitionActivity2.class); + i.putExtra(EXTRA_SAMPLE, sample); + i.putExtra(EXTRA_TYPE, TYPE_PROGRAMMATICALLY); + transitionTo(i); + } + }); + + findViewById(R.id.sample1_button2).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(TransitionActivity1.this, TransitionActivity2.class); + i.putExtra(EXTRA_SAMPLE, sample); + i.putExtra(EXTRA_TYPE, TYPE_XML); + transitionTo(i); + } + }); + + findViewById(R.id.sample1_button3).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(TransitionActivity1.this, TransitionActivity3.class); + i.putExtra(EXTRA_SAMPLE, sample); + i.putExtra(EXTRA_TYPE, TYPE_PROGRAMMATICALLY); + transitionTo(i); + } + }); + + findViewById(R.id.sample1_button4).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(TransitionActivity1.this, TransitionActivity3.class); + i.putExtra(EXTRA_SAMPLE, sample); + i.putExtra(EXTRA_TYPE, TYPE_XML); + transitionTo(i); + } + }); + + findViewById(R.id.sample1_button5).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Visibility returnTransition = buildReturnTransition(); + getWindow().setReturnTransition(returnTransition); + + finishAfterTransition(); + } + }); + findViewById(R.id.sample1_button6).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + /** + * If no return transition is defined Android will use reversed enter transition + * In this case, return transition will be a reversed Slide (defined in buildEnterTransition) + */ + finishAfterTransition(); + } + }); + } + + private Visibility buildEnterTransition() { + Fade enterTransition = new Fade(); + enterTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long)); + // This view will not be affected by enter transition animation + enterTransition.excludeTarget(R.id.square_red, true); + return enterTransition; + } + + private Visibility buildReturnTransition() { + Visibility enterTransition = new Slide(); + enterTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long)); + return enterTransition; + } +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity2.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity2.java new file mode 100644 index 0000000..76f2628 --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity2.java @@ -0,0 +1,58 @@ +package com.lgvalle.material_animations; + +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.transition.Explode; +import android.transition.Transition; +import android.transition.TransitionInflater; +import android.view.View; + +import com.lgvalle.material_animations.databinding.ActivityTransition2Binding; + +public class TransitionActivity2 extends BaseDetailActivity { + + private int type; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + bindData(); + setupWindowAnimations(); + setupLayout(); + setupToolbar(); + } + + private void bindData() { + ActivityTransition2Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_transition2); + Sample sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE); + type = getIntent().getExtras().getInt(EXTRA_TYPE); + binding.setTransition2Sample(sample); + } + + private void setupWindowAnimations() { + Transition transition; + + if (type == TYPE_PROGRAMMATICALLY) { + transition = buildEnterTransition(); + } else { + transition = TransitionInflater.from(this).inflateTransition(R.transition.explode); + } + getWindow().setEnterTransition(transition); + } + + private void setupLayout() { + findViewById(R.id.exit_button).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finishAfterTransition(); + } + }); + } + + private Transition buildEnterTransition() { + Explode enterTransition = new Explode(); + enterTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long)); + return enterTransition; + } + +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity3.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity3.java new file mode 100644 index 0000000..5f56ace --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionActivity3.java @@ -0,0 +1,61 @@ +package com.lgvalle.material_animations; + +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.transition.Slide; +import android.transition.Transition; +import android.transition.TransitionInflater; +import android.transition.Visibility; +import android.view.Gravity; +import android.view.View; + +import com.lgvalle.material_animations.databinding.ActivityTransition3Binding; + +public class TransitionActivity3 extends BaseDetailActivity { + + private int type; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + bindData(); + setupWindowAnimations(); + setupLayout(); + setupToolbar(); + } + + private void bindData() { + ActivityTransition3Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_transition3); + Sample sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE); + type = getIntent().getExtras().getInt(EXTRA_TYPE); + binding.setTransition3Sample(sample); + } + + private void setupWindowAnimations() { + Transition transition; + + if (type == TYPE_PROGRAMMATICALLY) { + transition = buildEnterTransition(); + } else { + transition = TransitionInflater.from(this).inflateTransition(R.transition.slide_from_bottom); + } + getWindow().setEnterTransition(transition); + } + + private void setupLayout() { + findViewById(R.id.exit_button).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finishAfterTransition(); + } + }); + } + + private Visibility buildEnterTransition() { + Slide enterTransition = new Slide(); + enterTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long)); + enterTransition.setSlideEdge(Gravity.RIGHT); + return enterTransition; + } + +} diff --git a/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionHelper.java b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionHelper.java new file mode 100644 index 0000000..679c182 --- /dev/null +++ b/Material-Animations/app/src/main/java/com/lgvalle/material_animations/TransitionHelper.java @@ -0,0 +1,73 @@ +/* + * Copyright 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.lgvalle.material_animations; + +import android.app.Activity; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.util.Pair; +import android.view.View; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Helper class for creating content transitions used with {@link android.app.ActivityOptions}. + */ +class TransitionHelper { + + /** + * Create the transition participants required during a activity transition while + * avoiding glitches with the system UI. + * + * @param activity The activity used as start for the transition. + * @param includeStatusBar If false, the status bar will not be added as the transition + * participant. + * @return All transition participants. + */ + public static Pair[] createSafeTransitionParticipants(@NonNull Activity activity, + boolean includeStatusBar, @Nullable Pair... otherParticipants) { + // Avoid system UI glitches as described here: + // https://plus.google.com/+AlexLockwood/posts/RPtwZ5nNebb + View decor = activity.getWindow().getDecorView(); + View statusBar = null; + if (includeStatusBar) { + statusBar = decor.findViewById(android.R.id.statusBarBackground); + } + View navBar = decor.findViewById(android.R.id.navigationBarBackground); + + // Create pair of transition participants. + List participants = new ArrayList<>(3); + addNonNullViewToTransitionParticipants(statusBar, participants); + addNonNullViewToTransitionParticipants(navBar, participants); + // only add transition participants if there's at least one none-null element + if (otherParticipants != null && !(otherParticipants.length == 1 + && otherParticipants[0] == null)) { + participants.addAll(Arrays.asList(otherParticipants)); + } + return participants.toArray(new Pair[participants.size()]); + } + + private static void addNonNullViewToTransitionParticipants(View view, List participants) { + if (view == null) { + return; + } + participants.add(new Pair<>(view, view.getTransitionName())); + } + +} diff --git a/Material-Animations/app/src/main/res/drawable/circle_24dp.xml b/Material-Animations/app/src/main/res/drawable/circle_24dp.xml new file mode 100644 index 0000000..d92150a --- /dev/null +++ b/Material-Animations/app/src/main/res/drawable/circle_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/Material-Animations/app/src/main/res/drawable/square.xml b/Material-Animations/app/src/main/res/drawable/square.xml new file mode 100644 index 0000000..ec66c24 --- /dev/null +++ b/Material-Animations/app/src/main/res/drawable/square.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/Material-Animations/app/src/main/res/layout/activity_animations1.xml b/Material-Animations/app/src/main/res/layout/activity_animations1.xml new file mode 100644 index 0000000..3325fdc --- /dev/null +++ b/Material-Animations/app/src/main/res/layout/activity_animations1.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +