├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── gradle-build.yml ├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── encodings.xml ├── runConfigurations.xml └── vcs.xml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── animators ├── build.gradle └── src │ ├── androidTest │ └── java │ │ └── jp │ │ └── wasabeef │ │ └── recyclerview │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ └── java │ └── jp │ └── wasabeef │ └── recyclerview │ ├── adapters │ ├── AlphaInAnimationAdapter.kt │ ├── AnimationAdapter.kt │ ├── ScaleInAnimationAdapter.kt │ ├── SlideInBottomAnimationAdapter.kt │ ├── SlideInLeftAnimationAdapter.kt │ └── SlideInRightAnimationAdapter.kt │ ├── animators │ ├── BaseItemAnimator.kt │ ├── FadeInAnimator.kt │ ├── FadeInDownAnimator.kt │ ├── FadeInLeftAnimator.kt │ ├── FadeInRightAnimator.kt │ ├── FadeInUpAnimator.kt │ ├── FlipInBottomXAnimator.kt │ ├── FlipInLeftYAnimator.kt │ ├── FlipInRightYAnimator.kt │ ├── FlipInTopXAnimator.kt │ ├── LandingAnimator.kt │ ├── OvershootInLeftAnimator.kt │ ├── OvershootInRightAnimator.kt │ ├── ScaleInAnimator.kt │ ├── ScaleInBottomAnimator.kt │ ├── ScaleInLeftAnimator.kt │ ├── ScaleInRightAnimator.kt │ ├── ScaleInTopAnimator.kt │ ├── SlideInDownAnimator.kt │ ├── SlideInLeftAnimator.kt │ ├── SlideInRightAnimator.kt │ ├── SlideInUpAnimator.kt │ └── holder │ │ └── AnimateViewHolder.kt │ └── internal │ └── ViewHelper.kt ├── art ├── demo.gif ├── demo2.gif ├── demo3.gif ├── demo4.gif ├── demo5.gif └── logo.jpg ├── build.gradle ├── example ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── jp │ │ └── wasabeef │ │ └── example │ │ └── recyclerview │ │ ├── AdapterSampleActivity.kt │ │ ├── AnimatorSampleActivity.kt │ │ ├── MainActivity.kt │ │ ├── MainAdapter.kt │ │ ├── MyAnimationAdapter.kt │ │ ├── MyAnimator.kt │ │ └── SampleData.kt │ └── res │ ├── drawable-hdpi │ └── ic_launcher.png │ ├── drawable-mdpi │ └── ic_launcher.png │ ├── drawable-xhdpi │ ├── chip.jpg │ └── ic_launcher.png │ ├── drawable-xxhdpi │ ├── ic_github.png │ └── ic_launcher.png │ ├── layout │ ├── activity_adapter_sample.xml │ ├── activity_animator_sample.xml │ ├── activity_main.xml │ └── layout_list_item.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── signingConfigs ├── debug.gradle └── debug.keystore /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{kt,kts,java}] 2 | indent_size=2 3 | max_line_length=off 4 | insert_final_newline=true 5 | 6 | [*.{kt,kts}] 7 | kotlin_imports_layout=ascii 8 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: wasabeef # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Future Task 2 | 3 | ## What is the motivation? 4 | 5 | ## What kind of solution can be considered? 6 | 7 | ## What do you want to discuss? 8 | 9 | *Please add relevant labels* 10 | 11 | ----- 12 | 13 | # Bug Reporting 14 | 15 | ## Steps to Reproduce 16 | 17 | ## Actual Results (include screenshots) 18 | 19 | ## Expected Results (include screenshots) 20 | 21 | ## URL 22 | 23 | ## OS details 24 | 25 | - Device: 26 | - OS: 27 | 28 | *Please add relevant labels* 29 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## What does this change? 2 | 3 | ## What is the value of this and can you measure success? 4 | 5 | ## Screenshots 6 | 7 | -------------------------------------------------------------------------------- /.github/workflows/gradle-build.yml: -------------------------------------------------------------------------------- 1 | name: "Gradle build" 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | gradle: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | - uses: actions/setup-java@v1 10 | with: 11 | java-version: 1.8 12 | - name: Build with Gradle 13 | run: ./gradlew build -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS 2 | .DS_store 3 | 4 | # Built application files 5 | *.apk 6 | *.ap_ 7 | 8 | # Files for the ART/Dalvik VM 9 | *.dex 10 | 11 | # Java class files 12 | *.class 13 | 14 | # Generated files 15 | bin/ 16 | gen/ 17 | out/ 18 | 19 | # Gradle files 20 | .gradle/ 21 | build/ 22 | 23 | # Local configuration file (sdk path, etc) 24 | local.properties 25 | 26 | # Proguard folder generated by Eclipse 27 | proguard/ 28 | 29 | # Log Files 30 | *.log 31 | 32 | # Android Studio Navigation editor temp files 33 | .navigation/ 34 | 35 | # Android Studio captures folder 36 | captures/ 37 | 38 | # IntelliJ 39 | *.iml 40 | .idea/workspace.xml 41 | .idea/tasks.xml 42 | .idea/gradle.xml 43 | .idea/assetWizardSettings.xml 44 | .idea/dictionaries 45 | .idea/libraries 46 | .idea/caches 47 | .idea/misc.xml 48 | .idea/modules.xml 49 | .idea/navEditor.xml 50 | .idea/markdown* 51 | .idea/compiler.xml 52 | .idea/inspectionProfiles/Project_Default.xml 53 | .idea/jarRepositories.xml 54 | projectFilesBackup/ 55 | 56 | # Keystore files 57 | # Uncomment the following line if you do not want to check your keystore files in. 58 | #*.jks 59 | 60 | # External native build folder generated in Android Studio 2.2 and later 61 | .externalNativeBuild 62 | 63 | # Google Services (e.g. APIs or Firebase) 64 | google-services.json 65 | 66 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 405 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | ========== 3 | 4 | Version 4.0.0 *(2020-08-27)* 5 | ---------------------------- 6 | 7 | Update: 8 | - Convert from all Java codes to Kotlin 1.3.72 9 | - The minSdkVersion from 14 to 21 10 | - The targetSdkVersion from 28 to 30 11 | - The compileSdkVersion from 28 to 30 12 | - Update project settings 13 | - Disable Jetifier 14 | - Add CodeStyle settings 15 | 16 | Version 3.0.0 *(2018-11-15)* 17 | ---------------------------- 18 | 19 | Update: 20 | - Migrate to AndroidX 21 | - Remove novoda-bintray-plugin 22 | - Fix a buf [#161](https://github.com/wasabeef/recyclerview-animators/pull/161) 23 | 24 | Version 2.3.0 *(2018-02-07)* 25 | ---------------------------- 26 | 27 | Update: 28 | - Compile & Target SDK Version 25 -> 27 29 | - Build Tools 26.0.1 -> 27.0.3 30 | - Support Library 25.3.1 -> 27.0.2 31 | 32 | Version 2.2.7 *(2017-06-29)* 33 | ---------------------------- 34 | 35 | Update: 36 | - Support Library 25.3.0 -> 25.4.0 37 | 38 | Version 2.2.6 *(2017-03-17)* 39 | ---------------------------- 40 | 41 | Feature: 42 | - [Changed Interpolator to DecelerateInterpolator #125](https://github.com/wasabeef/recyclerview-animators/pull/125) 43 | 44 | Update: 45 | - Build Tools 25 -> 25.0.2 46 | - Support Library 24.2.0 -> 25.3.0 47 | 48 | Bugfix: 49 | - [Fix animations not fully canceled on endAnimations() #86](https://github.com/wasabeef/recyclerview-animators/pull/86) 50 | 51 | 52 | Version 2.2.5 *(2016-12-02)* 53 | ---------------------------- 54 | 55 | Update: 56 | - Build Tools 24.0.2 -> 25 57 | - Support Library 23.4.0 -> 24.2.0 58 | 59 | 60 | Version 2.2.4 *(2016-08-03)* 61 | ---------------------------- 62 | 63 | Update: 64 | - Build Tools 23.0.1 -> 24.0.2 65 | - Support Library 23.0.1 -> 23.4.0 66 | 67 | 68 | Version 2.2.3 *(2016-04-19)* 69 | ---------------------------- 70 | 71 | Bug fix: 72 | [Dispatch onViewRecycled event to wrapped adapter #80](https://github.com/wasabeef/recyclerview-animators/pull/80) 73 | [Fix setStartDelay() is not reset by clear() #82](https://github.com/wasabeef/recyclerview-animators/pull/82) 74 | 75 | Update: 76 | Support library 23.2.1 77 | 78 | Version 2.2.2 *(2016-04-05)* 79 | ---------------------------- 80 | 81 | Bug fix 82 | 83 | Version 2.2.1 *(2016-02-28)* 84 | ---------------------------- 85 | 86 | Bug fix: firstOnly 87 | 88 | Version 2.2.0 *(2016-01-29)* 89 | ---------------------------- 90 | 91 | Bug fix: [issue #64](https://github.com/wasabeef/recyclerview-animators/issues/64) by [@emartynov](https://github.com/wasabeef/recyclerview-animators/issues/64) 92 | Feature: [Motion Delay](https://github.com/wasabeef/recyclerview-animators/pull/66) by [@aphexcx](https://github.com/aphexcx) 93 | 94 | Version 2.1.0 *(2015-11-25)* 95 | ---------------------------- 96 | 97 | Move the adapters of the package. 98 | Added BaseItemAnimator#setInterpolator. 99 | 100 | Version 2.0.2 *(2015-11-24)* 101 | ---------------------------- 102 | 103 | Added AnimationAdapter#getIemId 104 | Fixed the getItemId() to return the nested adapter item id 105 | 106 | Version 2.0.1 *(2015-11-10)* 107 | ---------------------------- 108 | 109 | Bug fix registerAdapterDataObserver, unregisterAdapterDataObserver 110 | 111 | Version 2.0.0 *(2015-10-16)* 112 | ---------------------------- 113 | 114 | Support RecyclerView 23.1.0+ 115 | 116 | **Use 1.3.0 If you are using a 23.0.1 or below.** 117 | 118 | Version 1.3.0 *(2015-09-11)* 119 | ---------------------------- 120 | 121 | Added in ability to pass in interpolators to the four ItemAnimators. 122 | Thanks to [@craya1982](https://github.com/craya1982) 123 | 124 | Version 1.2.3 *(2015-09-07)* 125 | ---------------------------- 126 | 127 | Update support library. 128 | 129 | Version 1.2.2 *(2015-08-19)* 130 | ---------------------------- 131 | 132 | Add tension in OvershootAnimators. 133 | 134 | Version 1.2.1 *(2015-07-07)* 135 | ---------------------------- 136 | 137 | Update AnimationAdapter to allow grabbing the wrappedAdapter. 138 | 139 | Version 1.2.0 *(2015-04-15)* 140 | ---------------------------- 141 | 142 | Support Multiple animators for ViewHolders. 143 | 144 | Version 1.1.3 *(2015-04-08)* 145 | ---------------------------- 146 | 147 | Support Interpolator in AnimationAdapter. 148 | 149 | Version 1.1.2 *(2015-03-23)* 150 | ---------------------------- 151 | 152 | Supports multiple viewTypes. 153 | 154 | Version 1.1.1 *(2015-03-17)* 155 | ---------------------------- 156 | 157 | Improved reliability and speed. 158 | 159 | Version 1.1.0 *(2015-01-21)* 160 | ---------------------------- 161 | 162 | add RecyclerView.Adapter support. 163 | 164 | 165 | Version 1.0.3 *(2015-01-21)* 166 | ---------------------------- 167 | 168 | fix setting of pom.xml 169 | 170 | Version 1.0.2 *(2015-01-20)* 171 | ---------------------------- 172 | 173 | fix setting of pom.xml 174 | 175 | Version 1.0.1 *(2015-01-10)* 176 | ---------------------------- 177 | 178 | Attach a jar for non-Gradle Android users. 179 | 180 | Version 1.0.0 *(2015-01-05)* 181 | ---------------------------- 182 | 183 | Initial release. 184 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at dadadada.chop@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RecyclerView Animators 2 | ====================== 3 |

4 | 5 |

6 | 7 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-recyclerview--animators-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1327) 8 | [![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) 9 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/jp.wasabeef/recyclerview-animators/badge.svg)](https://search.maven.org/artifact/jp.wasabeef/recyclerview-animators) 10 | 11 | RecyclerView Animators is an Android library that allows developers to easily create RecyclerView with animations. 12 | 13 | Please feel free to use this. 14 | 15 | # Features 16 | 17 | * Animate addition and removal of [`ItemAnimator`](#itemanimator-1) 18 | * Appearance animations for items in [`RecyclerView.Adapter`](#recyclerviewadapter) 19 | 20 | # Demo 21 | 22 | ### ItemAnimator 23 | 24 | 25 | ### Adapters 26 | 27 | 28 | # How do I use it? 29 | 30 | ## Setup 31 | 32 | #### Gradle 33 | 34 | On your module's `build.gradle` file add this implementation statement to the `dependencies` section: 35 | 36 | ```groovy 37 | dependencies { 38 | // Kotlin 39 | implementation 'jp.wasabeef:recyclerview-animators:4.0.2' 40 | } 41 | ``` 42 | 43 | Also make sure that the `repositories` section includes not only `"mavenCentral()"` but also a `maven` section with the `"google()"` endpoint. 44 | 45 | ``` 46 | repositories { 47 | google() 48 | mavenCentral() 49 | jcenter() 50 | } 51 | ``` 52 | 53 | ## ItemAnimator 54 | ### Step 1 55 | 56 | Set RecyclerView ItemAnimator. 57 | 58 | ```kotlin 59 | val recyclerView = findViewById(R.id.list) 60 | recyclerView.itemAnimator = SlideInLeftAnimator() 61 | ``` 62 | 63 | ```kotlin 64 | val recyclerView = findViewById(R.id.list) 65 | recyclerView.itemAnimator = SlideInUpAnimator(OvershootInterpolator(1f)) 66 | ``` 67 | 68 | ## Step 2 69 | Please use the following 70 | `notifyItemChanged(int)` 71 | `notifyItemInserted(int)` 72 | `notifyItemRemoved(int)` 73 | `notifyItemRangeChanged(int, int)` 74 | `notifyItemRangeInserted(int, int)` 75 | `notifyItemRangeRemoved(int, int)` 76 | 77 | > If you want your animations to work, do not rely on calling `notifyDataSetChanged()`; 78 | > as it is the RecyclerView's default behavior, animations are not triggered to start inside this method. 79 | 80 | ```kotlin 81 | fun remove(position: Int) { 82 | dataSet.removeAt(position) 83 | notifyItemRemoved(position) 84 | } 85 | 86 | fun add(text: String, position: Int) { 87 | dataSet.add(position, text) 88 | notifyItemInserted(position) 89 | } 90 | ``` 91 | 92 | ### Advanced Step 3 93 | 94 | You can change the durations. 95 | 96 | ```kotlin 97 | recyclerView.itemAnimator?.apply { 98 | addDuration = 1000 99 | removeDuration = 100 100 | moveDuration = 1000 101 | changeDuration = 100 102 | } 103 | ``` 104 | 105 | ### Advanced Step 4 106 | 107 | Change the interpolator. 108 | 109 | ```kotlin 110 | recyclerView.itemAnimator = SlideInLeftAnimator().apply { 111 | setInterpolator(OvershootInterpolator()) 112 | } 113 | ``` 114 | 115 | ### Advanced Step 5 116 | 117 | By implementing AnimateViewHolder, you can override preset animation. 118 | So, custom animation can be set depending on view holder. 119 | 120 | ```kotlin 121 | class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), AnimateViewHolder { 122 | 123 | override fun preAnimateRemoveImpl(holder: RecyclerView.ViewHolder) { 124 | // do something 125 | } 126 | 127 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder, listener: ViewPropertyAnimatorListener) { 128 | itemView.animate().apply { 129 | translationY(-itemView.height * 0.3f) 130 | alpha(0f) 131 | duration = 300 132 | setListener(listener) 133 | }.start() 134 | } 135 | 136 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 137 | itemView.setTranslationY(-itemView.height * 0.3f) 138 | itemView.setAlpha(0f) 139 | } 140 | 141 | override fun animateAddImpl(holder: RecyclerView.ViewHolder, listener: ViewPropertyAnimatorListener) { 142 | itemView.animate().apply { 143 | translationY(0f) 144 | alpha(1f) 145 | duration = 300 146 | setListener(listener) 147 | }.start() 148 | } 149 | } 150 | ``` 151 | 152 | ### Animators 153 | 154 | #### Cool 155 | `LandingAnimator` 156 | 157 | ##### Scale 158 | `ScaleInAnimator`, `ScaleInTopAnimator`, `ScaleInBottomAnimator` 159 | `ScaleInLeftAnimator`, `ScaleInRightAnimator` 160 | 161 | 162 | ##### Fade 163 | `FadeInAnimator`, `FadeInDownAnimator`, `FadeInUpAnimator` 164 | `FadeInLeftAnimator`, `FadeInRightAnimator` 165 | 166 | ##### Flip 167 | `FlipInTopXAnimator`, `FlipInBottomXAnimator` 168 | `FlipInLeftYAnimator`, `FlipInRightYAnimator` 169 | 170 | ##### Slide 171 | `SlideInLeftAnimator`, `SlideInRightAnimator`, `OvershootInLeftAnimator`, `OvershootInRightAnimator` 172 | `SlideInUpAnimator`, `SlideInDownAnimator` 173 | 174 | ## RecyclerView.Adapter 175 | ### Step 1 176 | 177 | Set RecyclerView ItemAnimator. 178 | 179 | ```kotlin 180 | val recyclerView = findViewById(R.id.list) 181 | recyclerView.adapter = AlphaInAnimationAdapter(MyAdapter()) 182 | ``` 183 | 184 | #### Java 185 | ```java 186 | RecyclerView recyclerView = findViewById(R.id.list); 187 | recyclerView.setAdapter(new AlphaInAnimationAdapter(MyAdapter()); 188 | ``` 189 | 190 | ### Advanced Step 2 191 | 192 | ```kotlin 193 | recyclerView.adapter = AlphaInAnimationAdapter(MyAdapter()).apply { 194 | // Change the durations. 195 | setDuration(1000) 196 | // Change the interpolator. 197 | setInterpolator(vershootInterpolator()) 198 | // Disable the first scroll mode. 199 | setFirstOnly(false) 200 | } 201 | ``` 202 | 203 | #### Java 204 | ```java 205 | AlphaInAnimationAdapter alphaInAnimationAdapter = new AlphaInAnimationAdapter(new MyAdapter()); 206 | alphaInAnimationAdapter.setDuration(1000); 207 | alphaInAnimationAdapter.setInterpolator(new OvershootInterpolator()); 208 | alphaInAnimationAdapter.setFirstOnly(false); 209 | ``` 210 | 211 | ### Advanced Step 3 212 | 213 | Multiple Animations 214 | 215 | ```kotlin 216 | val alphaAdapter = AlphaInAnimationAdapter(MyAdapter()) 217 | recyclerView.adapter = ScaleInAnimationAdapter(alphaAdapter) 218 | ``` 219 | 220 | #### Java 221 | ```java 222 | recyclerView.setAdapter(new ScaleInAnimationAdapter(alphaInAnimationAdapter)); 223 | ``` 224 | 225 | ### Adapters 226 | 227 | #### Alpha 228 | `AlphaInAnimationAdapter` 229 | 230 | #### Scale 231 | `ScaleInAnimationAdapter` 232 | 233 | #### Slide 234 | `SlideInBottomAnimationAdapter` 235 | `SlideInRightAnimationAdapter`, `SlideInLeftAnimationAdapter` 236 | 237 | Applications using RecyclerView Animators 238 | --- 239 | 240 | Please [ping](mailto:dadadada.chop@gmail.com) me or send a pull request if you would like to be added here. 241 | 242 | Icon | Application 243 | ------------ | ------------- 244 | | [Ameba Ownd](https://play.google.com/store/apps/details?id=jp.co.cyberagent.madrid) 245 | | [QuitNow!](https://play.google.com/store/apps/details?id=com.EAGINsoftware.dejaloYa) 246 | | [AbemaTV](https://play.google.com/store/apps/details?id=tv.abema) 247 | | [CL](https://play.google.com/store/apps/details?id=com.cllive) 248 | 249 | Developed By 250 | ------- 251 | Daichi Furiya (Wasabeef) - 252 | 253 | 254 | Follow me on Twitter 256 | 257 | 258 | Contributions 259 | ------- 260 | 261 | Any contributions are welcome! 262 | 263 | Contributers 264 | ------- 265 | 266 | * [craya1982](https://github.com/craya1982) 267 | 268 | Thanks 269 | ------- 270 | 271 | * Inspired by `AndroidViewAnimations` in [daimajia](https://github.com/daimajia). 272 | 273 | License 274 | ------- 275 | 276 | Copyright 2020 Daichi Furiya / Wasabeef 277 | 278 | Licensed under the Apache License, Version 2.0 (the "License"); 279 | you may not use this file except in compliance with the License. 280 | You may obtain a copy of the License at 281 | 282 | http://www.apache.org/licenses/LICENSE-2.0 283 | 284 | Unless required by applicable law or agreed to in writing, software 285 | distributed under the License is distributed on an "AS IS" BASIS, 286 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 287 | See the License for the specific language governing permissions and 288 | limitations under the License. 289 | -------------------------------------------------------------------------------- /animators/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | compileSdkVersion COMPILE_SDK_VERSION as int 6 | 7 | defaultConfig { 8 | minSdkVersion MIN_SDK_VERSION as int 9 | targetSdkVersion TARGET_SDK_VERSION as int 10 | } 11 | } 12 | 13 | dependencies { 14 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 15 | implementation "androidx.recyclerview:recyclerview:1.1.0" 16 | } 17 | 18 | ext { 19 | bintrayRepo = 'maven' 20 | bintrayName = 'recyclerview-animators' 21 | bintrayUserOrg = 'wasabeef' 22 | publishedGroupId = 'jp.wasabeef' 23 | libraryName = 'recyclerview-animators' 24 | artifact = 'recyclerview-animators' 25 | libraryDescription = 'Which provides simple Item animations to RecyclerView items' 26 | siteUrl = 'https://github.com/wasabeef/recyclerview-animators' 27 | gitUrl = 'https://github.com/wasabeef/recyclerview-animators.git' 28 | issueUrl = 'https://github.com/wasabeef/recyclerview-animators/issues' 29 | libraryVersion = VERSION_NAME 30 | developerId = 'wasabeef' 31 | developerName = 'Wasabeef' 32 | developerEmail = 'dadadada.chop@gmail.com' 33 | licenseName = 'The Apache Software License, Version 2.0' 34 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 35 | allLicenses = ["Apache-2.0"] 36 | } 37 | 38 | // TODO: Close JCenter on May 1st https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/ 39 | // apply from: 'https://gist.githubusercontent.com/wasabeef/cf14805bee509baf7461974582f17d26/raw/bintray-v1.gradle' 40 | // apply from: 'https://gist.githubusercontent.com/wasabeef/cf14805bee509baf7461974582f17d26/raw/install-v1.gradle' 41 | 42 | apply from: 'https://gist.githubusercontent.com/wasabeef/2f2ae8d97b429e7d967128125dc47854/raw/maven-central-v1.gradle' -------------------------------------------------------------------------------- /animators/src/androidTest/java/jp/wasabeef/recyclerview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | 11 | public ApplicationTest() { 12 | super(Application.class); 13 | } 14 | } -------------------------------------------------------------------------------- /animators/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/adapters/AlphaInAnimationAdapter.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.adapters 2 | 3 | import android.animation.Animator 4 | import android.animation.ObjectAnimator 5 | import android.view.View 6 | import androidx.recyclerview.widget.RecyclerView 7 | 8 | /** 9 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | */ 23 | open class AlphaInAnimationAdapter @JvmOverloads constructor( 24 | adapter: RecyclerView.Adapter, 25 | private val from: Float = DEFAULT_ALPHA_FROM 26 | ) : AnimationAdapter(adapter) { 27 | 28 | override fun getAnimators(view: View): Array = 29 | arrayOf(ObjectAnimator.ofFloat(view, "alpha", from, 1f)) 30 | 31 | companion object { 32 | private const val DEFAULT_ALPHA_FROM = 0f 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/adapters/AnimationAdapter.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.adapters 2 | 3 | import android.animation.Animator 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import android.view.animation.Interpolator 7 | import android.view.animation.LinearInterpolator 8 | import androidx.recyclerview.widget.RecyclerView 9 | import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver 10 | import jp.wasabeef.recyclerview.internal.ViewHelper.clear 11 | 12 | /** 13 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 14 | * 15 | * Licensed under the Apache License, Version 2.0 (the "License"); 16 | * you may not use this file except in compliance with the License. 17 | * You may obtain a copy of the License at 18 | * 19 | * http://www.apache.org/licenses/LICENSE-2.0 20 | * 21 | * Unless required by applicable law or agreed to in writing, software 22 | * distributed under the License is distributed on an "AS IS" BASIS, 23 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | * See the License for the specific language governing permissions and 25 | * limitations under the License. 26 | */ 27 | abstract class AnimationAdapter(wrapped: RecyclerView.Adapter) : 28 | RecyclerView.Adapter() { 29 | 30 | private var duration = 300 31 | private var interpolator: Interpolator = LinearInterpolator() 32 | private var lastPosition = -1 33 | private var isFirstOnly = true 34 | 35 | protected var adapter: RecyclerView.Adapter 36 | 37 | init { 38 | @Suppress("UNCHECKED_CAST") 39 | this.adapter = wrapped as RecyclerView.Adapter 40 | super.setHasStableIds(this.adapter.hasStableIds()) 41 | } 42 | 43 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { 44 | return adapter.onCreateViewHolder(parent, viewType) 45 | } 46 | 47 | override fun registerAdapterDataObserver(observer: AdapterDataObserver) { 48 | super.registerAdapterDataObserver(observer) 49 | adapter.registerAdapterDataObserver(observer) 50 | } 51 | 52 | override fun unregisterAdapterDataObserver(observer: AdapterDataObserver) { 53 | super.unregisterAdapterDataObserver(observer) 54 | adapter.unregisterAdapterDataObserver(observer) 55 | } 56 | 57 | override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { 58 | super.onAttachedToRecyclerView(recyclerView) 59 | adapter.onAttachedToRecyclerView(recyclerView) 60 | } 61 | 62 | override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { 63 | super.onDetachedFromRecyclerView(recyclerView) 64 | adapter.onDetachedFromRecyclerView(recyclerView) 65 | } 66 | 67 | override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) { 68 | super.onViewAttachedToWindow(holder) 69 | adapter.onViewAttachedToWindow(holder) 70 | } 71 | 72 | override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) { 73 | super.onViewDetachedFromWindow(holder) 74 | adapter.onViewDetachedFromWindow(holder) 75 | } 76 | 77 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { 78 | adapter.onBindViewHolder(holder, position) 79 | val adapterPosition = holder.adapterPosition 80 | if (!isFirstOnly || adapterPosition > lastPosition) { 81 | for (anim in getAnimators(holder.itemView)) { 82 | anim.setDuration(duration.toLong()).start() 83 | anim.interpolator = interpolator 84 | } 85 | lastPosition = adapterPosition 86 | } else { 87 | clear(holder.itemView) 88 | } 89 | } 90 | 91 | override fun onViewRecycled(holder: RecyclerView.ViewHolder) { 92 | adapter.onViewRecycled(holder) 93 | super.onViewRecycled(holder) 94 | } 95 | 96 | override fun getItemCount(): Int { 97 | return adapter.itemCount 98 | } 99 | 100 | fun setDuration(duration: Int) { 101 | this.duration = duration 102 | } 103 | 104 | fun setInterpolator(interpolator: Interpolator) { 105 | this.interpolator = interpolator 106 | } 107 | 108 | fun setStartPosition(start: Int) { 109 | lastPosition = start 110 | } 111 | 112 | protected abstract fun getAnimators(view: View): Array 113 | fun setFirstOnly(firstOnly: Boolean) { 114 | isFirstOnly = firstOnly 115 | } 116 | 117 | override fun getItemViewType(position: Int): Int { 118 | return adapter.getItemViewType(position) 119 | } 120 | 121 | val wrappedAdapter: RecyclerView.Adapter 122 | get() = adapter 123 | 124 | override fun setHasStableIds(hasStableIds: Boolean) { 125 | super.setHasStableIds(hasStableIds) 126 | adapter.setHasStableIds(hasStableIds) 127 | } 128 | 129 | override fun getItemId(position: Int): Long { 130 | return adapter.getItemId(position) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/adapters/ScaleInAnimationAdapter.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.adapters 2 | 3 | import android.animation.Animator 4 | import android.animation.ObjectAnimator 5 | import android.view.View 6 | import androidx.recyclerview.widget.RecyclerView 7 | 8 | /** 9 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | */ 23 | open class ScaleInAnimationAdapter @JvmOverloads constructor( 24 | adapter: RecyclerView.Adapter, 25 | private val from: Float = DEFAULT_SCALE_FROM 26 | ) : AnimationAdapter(adapter) { 27 | 28 | override fun getAnimators(view: View): Array { 29 | val scaleX = ObjectAnimator.ofFloat(view, "scaleX", from, 1f) 30 | val scaleY = ObjectAnimator.ofFloat(view, "scaleY", from, 1f) 31 | return arrayOf(scaleX, scaleY) 32 | } 33 | 34 | companion object { 35 | private const val DEFAULT_SCALE_FROM = .5f 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/adapters/SlideInBottomAnimationAdapter.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.adapters 2 | 3 | import android.animation.Animator 4 | import android.animation.ObjectAnimator 5 | import android.view.View 6 | import androidx.recyclerview.widget.RecyclerView 7 | 8 | /** 9 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | */ 23 | open class SlideInBottomAnimationAdapter( 24 | adapter: RecyclerView.Adapter 25 | ) : AnimationAdapter(adapter) { 26 | 27 | override fun getAnimators(view: View): Array = arrayOf( 28 | ObjectAnimator.ofFloat(view, "translationY", view.measuredHeight.toFloat(), 0f) 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/adapters/SlideInLeftAnimationAdapter.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.adapters 2 | 3 | import android.animation.Animator 4 | import android.animation.ObjectAnimator 5 | import android.view.View 6 | import androidx.recyclerview.widget.RecyclerView 7 | 8 | /** 9 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | */ 23 | open class SlideInLeftAnimationAdapter( 24 | adapter: RecyclerView.Adapter 25 | ) : AnimationAdapter(adapter) { 26 | 27 | override fun getAnimators(view: View): Array = arrayOf( 28 | ObjectAnimator.ofFloat(view, "translationX", -view.rootView.width.toFloat(), 0f) 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/adapters/SlideInRightAnimationAdapter.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.adapters 2 | 3 | import android.animation.Animator 4 | import android.animation.ObjectAnimator 5 | import android.view.View 6 | import androidx.recyclerview.widget.RecyclerView 7 | 8 | /** 9 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | */ 23 | open class SlideInRightAnimationAdapter( 24 | adapter: RecyclerView.Adapter 25 | ) : AnimationAdapter(adapter) { 26 | 27 | override fun getAnimators(view: View): Array = arrayOf( 28 | ObjectAnimator.ofFloat(view, "translationX", view.rootView.width.toFloat(), 0f) 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/BaseItemAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.animation.Animator 4 | import android.view.animation.DecelerateInterpolator 5 | import android.view.animation.Interpolator 6 | import androidx.recyclerview.widget.RecyclerView 7 | import androidx.recyclerview.widget.SimpleItemAnimator 8 | import jp.wasabeef.recyclerview.animators.holder.AnimateViewHolder 9 | import jp.wasabeef.recyclerview.internal.ViewHelper.clear 10 | import java.util.ArrayList 11 | import kotlin.math.abs 12 | 13 | /* 14 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 15 | * 16 | * Licensed under the Apache License, Version 2.0 (the "License"); 17 | * you may not use this file except in compliance with the License. 18 | * You may obtain a copy of the License at 19 | * 20 | * http://www.apache.org/licenses/LICENSE-2.0 21 | * 22 | * Unless required by applicable law or agreed to in writing, software 23 | * distributed under the License is distributed on an "AS IS" BASIS, 24 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | * See the License for the specific language governing permissions and 26 | * limitations under the License. 27 | * 28 | */ 29 | abstract class BaseItemAnimator : SimpleItemAnimator() { 30 | 31 | private val pendingRemovals = ArrayList() 32 | private val pendingAdditions = ArrayList() 33 | private val pendingMoves = ArrayList() 34 | private val pendingChanges = ArrayList() 35 | private val additionsList = ArrayList>() 36 | private val movesList = ArrayList>() 37 | private val changesList = ArrayList>() 38 | protected var addAnimations = ArrayList() 39 | private val moveAnimations = ArrayList() 40 | protected var removeAnimations = ArrayList() 41 | private val changeAnimations = ArrayList() 42 | protected var interpolator: Interpolator = DecelerateInterpolator() 43 | 44 | companion object { 45 | private const val DEBUG = false 46 | } 47 | 48 | init { 49 | supportsChangeAnimations = false 50 | } 51 | 52 | private class MoveInfo( 53 | var holder: RecyclerView.ViewHolder, 54 | var fromX: Int, 55 | var fromY: Int, 56 | var toX: Int, 57 | var toY: Int 58 | ) 59 | 60 | private class ChangeInfo private constructor( 61 | oldHolder: RecyclerView.ViewHolder, 62 | newHolder: RecyclerView.ViewHolder 63 | ) { 64 | var oldHolder: RecyclerView.ViewHolder? = oldHolder 65 | var newHolder: RecyclerView.ViewHolder? = newHolder 66 | var fromX = 0 67 | var fromY = 0 68 | var toX = 0 69 | var toY = 0 70 | 71 | constructor( 72 | oldHolder: RecyclerView.ViewHolder, 73 | newHolder: RecyclerView.ViewHolder, 74 | fromX: Int, 75 | fromY: Int, 76 | toX: Int, 77 | toY: Int 78 | ) : this(oldHolder, newHolder) { 79 | this.fromX = fromX 80 | this.fromY = fromY 81 | this.toX = toX 82 | this.toY = toY 83 | } 84 | 85 | override fun toString(): String { 86 | return ("ChangeInfo{" + "oldHolder=" + oldHolder + ", newHolder=" + newHolder + ", fromX=" 87 | + fromX + ", fromY=" + fromY + ", toX=" + toX + ", toY=" + toY + '}') 88 | } 89 | } 90 | 91 | override fun runPendingAnimations() { 92 | val removalsPending = pendingRemovals.isNotEmpty() 93 | val movesPending = pendingMoves.isNotEmpty() 94 | val changesPending = pendingChanges.isNotEmpty() 95 | val additionsPending = pendingAdditions.isNotEmpty() 96 | if (!removalsPending && !movesPending && !additionsPending && !changesPending) { 97 | // nothing to animate 98 | return 99 | } 100 | // First, remove stuff 101 | for (holder in pendingRemovals) { 102 | doAnimateRemove(holder) 103 | } 104 | pendingRemovals.clear() 105 | // Next, move stuff 106 | if (movesPending) { 107 | val moves = ArrayList(pendingMoves) 108 | movesList.add(moves) 109 | pendingMoves.clear() 110 | val mover = Runnable { 111 | val removed = movesList.remove(moves) 112 | if (!removed) { 113 | // already canceled 114 | return@Runnable 115 | } 116 | for (moveInfo in moves) { 117 | animateMoveImpl( 118 | moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, 119 | moveInfo.toY 120 | ) 121 | } 122 | moves.clear() 123 | } 124 | if (removalsPending) { 125 | val view = moves[0].holder.itemView 126 | view.postOnAnimationDelayed(mover, removeDuration) 127 | } else { 128 | mover.run() 129 | } 130 | } 131 | // Next, change stuff, to run in parallel with move animations 132 | if (changesPending) { 133 | val changes = ArrayList(pendingChanges) 134 | changesList.add(changes) 135 | pendingChanges.clear() 136 | val changer = Runnable { 137 | val removed = changesList.remove(changes) 138 | if (!removed) { 139 | // already canceled 140 | return@Runnable 141 | } 142 | for (change in changes) { 143 | animateChangeImpl(change) 144 | } 145 | changes.clear() 146 | } 147 | if (removalsPending) { 148 | val holder = changes[0].oldHolder 149 | holder!!.itemView.postOnAnimationDelayed(changer, removeDuration) 150 | } else { 151 | changer.run() 152 | } 153 | } 154 | // Next, add stuff 155 | if (additionsPending) { 156 | val additions = ArrayList(pendingAdditions) 157 | additionsList.add(additions) 158 | pendingAdditions.clear() 159 | val adder = Runnable { 160 | val removed = additionsList.remove(additions) 161 | if (!removed) { 162 | // already canceled 163 | return@Runnable 164 | } 165 | for (holder in additions) { 166 | doAnimateAdd(holder) 167 | } 168 | additions.clear() 169 | } 170 | if (removalsPending || movesPending || changesPending) { 171 | val removeDuration = if (removalsPending) removeDuration else 0 172 | val moveDuration = if (movesPending) moveDuration else 0 173 | val changeDuration = if (changesPending) changeDuration else 0 174 | val totalDelay = removeDuration + moveDuration.coerceAtLeast(changeDuration) 175 | val view = additions[0].itemView 176 | view.postOnAnimationDelayed(adder, totalDelay) 177 | } else { 178 | adder.run() 179 | } 180 | } 181 | } 182 | 183 | protected open fun preAnimateRemoveImpl(holder: RecyclerView.ViewHolder) {} 184 | 185 | protected open fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) {} 186 | 187 | protected abstract fun animateRemoveImpl(holder: RecyclerView.ViewHolder) 188 | 189 | protected abstract fun animateAddImpl(holder: RecyclerView.ViewHolder) 190 | 191 | private fun preAnimateRemove(holder: RecyclerView.ViewHolder) { 192 | clear(holder.itemView) 193 | if (holder is AnimateViewHolder) { 194 | holder.preAnimateRemoveImpl(holder) 195 | } else { 196 | preAnimateRemoveImpl(holder) 197 | } 198 | } 199 | 200 | private fun preAnimateAdd(holder: RecyclerView.ViewHolder) { 201 | clear(holder.itemView) 202 | if (holder is AnimateViewHolder) { 203 | holder.preAnimateAddImpl(holder) 204 | } else { 205 | preAnimateAddImpl(holder) 206 | } 207 | } 208 | 209 | private fun doAnimateRemove(holder: RecyclerView.ViewHolder) { 210 | if (holder is AnimateViewHolder) { 211 | holder.animateRemoveImpl(holder, DefaultRemoveAnimatorListener(holder)) 212 | } else { 213 | animateRemoveImpl(holder) 214 | } 215 | removeAnimations.add(holder) 216 | } 217 | 218 | private fun doAnimateAdd(holder: RecyclerView.ViewHolder) { 219 | if (holder is AnimateViewHolder) { 220 | holder.animateAddImpl(holder, DefaultAddAnimatorListener(holder)) 221 | } else { 222 | animateAddImpl(holder) 223 | } 224 | addAnimations.add(holder) 225 | } 226 | 227 | override fun animateRemove(holder: RecyclerView.ViewHolder): Boolean { 228 | endAnimation(holder) 229 | preAnimateRemove(holder) 230 | pendingRemovals.add(holder) 231 | return true 232 | } 233 | 234 | protected fun getRemoveDelay(holder: RecyclerView.ViewHolder): Long { 235 | return abs(holder.oldPosition * removeDuration / 4) 236 | } 237 | 238 | override fun animateAdd(holder: RecyclerView.ViewHolder): Boolean { 239 | endAnimation(holder) 240 | preAnimateAdd(holder) 241 | pendingAdditions.add(holder) 242 | return true 243 | } 244 | 245 | protected fun getAddDelay(holder: RecyclerView.ViewHolder): Long { 246 | return abs(holder.adapterPosition * addDuration / 4) 247 | } 248 | 249 | override fun animateMove( 250 | holder: RecyclerView.ViewHolder, 251 | fromX: Int, 252 | fromY: Int, 253 | toX: Int, 254 | toY: Int 255 | ): Boolean { 256 | var fX = fromX 257 | var fY = fromY 258 | val view = holder.itemView 259 | fX += holder.itemView.translationX.toInt() 260 | fY += holder.itemView.translationY.toInt() 261 | endAnimation(holder) 262 | val deltaX = toX - fX 263 | val deltaY = toY - fY 264 | if (deltaX == 0 && deltaY == 0) { 265 | dispatchMoveFinished(holder) 266 | return false 267 | } 268 | if (deltaX != 0) { 269 | view.translationX = -deltaX.toFloat() 270 | } 271 | if (deltaY != 0) { 272 | view.translationY = -deltaY.toFloat() 273 | } 274 | pendingMoves.add(MoveInfo(holder, fX, fY, toX, toY)) 275 | return true 276 | } 277 | 278 | private fun animateMoveImpl( 279 | holder: RecyclerView.ViewHolder, 280 | fromX: Int, 281 | fromY: Int, 282 | toX: Int, 283 | toY: Int 284 | ) { 285 | val view = holder.itemView 286 | val deltaX = toX - fromX 287 | val deltaY = toY - fromY 288 | if (deltaX != 0) { 289 | view.animate().translationX(0f) 290 | } 291 | if (deltaY != 0) { 292 | view.animate().translationY(0f) 293 | } 294 | // TODO: make EndActions end listeners instead, since end actions aren't called when 295 | // vpas are canceled (and can't end them. why?) 296 | // need listener functionality in VPACompat for this. Ick. 297 | moveAnimations.add(holder) 298 | val animation = view.animate() 299 | animation.setDuration(moveDuration).setListener(object : AnimatorListenerAdapter() { 300 | override fun onAnimationStart(animator: Animator) { 301 | dispatchMoveStarting(holder) 302 | } 303 | 304 | override fun onAnimationCancel(animator: Animator) { 305 | if (deltaX != 0) { 306 | view.translationX = 0f 307 | } 308 | if (deltaY != 0) { 309 | view.translationY = 0f 310 | } 311 | } 312 | 313 | override fun onAnimationEnd(animator: Animator) { 314 | animation.setListener(null) 315 | dispatchMoveFinished(holder) 316 | moveAnimations.remove(holder) 317 | dispatchFinishedWhenDone() 318 | } 319 | }).start() 320 | } 321 | 322 | override fun animateChange( 323 | oldHolder: RecyclerView.ViewHolder, newHolder: RecyclerView.ViewHolder, fromX: Int, fromY: Int, 324 | toX: Int, toY: Int 325 | ): Boolean { 326 | if (oldHolder === newHolder) { 327 | // Don't know how to run change animations when the same view holder is re-used. 328 | // run a move animation to handle position changes. 329 | return animateMove(oldHolder, fromX, fromY, toX, toY) 330 | } 331 | val prevTranslationX = oldHolder.itemView.translationX 332 | val prevTranslationY = oldHolder.itemView.translationY 333 | val prevAlpha = oldHolder.itemView.alpha 334 | endAnimation(oldHolder) 335 | val deltaX = (toX - fromX - prevTranslationX).toInt() 336 | val deltaY = (toY - fromY - prevTranslationY).toInt() 337 | // recover prev translation state after ending animation 338 | oldHolder.itemView.translationX = prevTranslationX 339 | oldHolder.itemView.translationY = prevTranslationY 340 | oldHolder.itemView.alpha = prevAlpha 341 | // carry over translation values 342 | endAnimation(newHolder) 343 | newHolder.itemView.translationX = -deltaX.toFloat() 344 | newHolder.itemView.translationY = -deltaY.toFloat() 345 | newHolder.itemView.alpha = 0f 346 | pendingChanges.add(ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY)) 347 | return true 348 | } 349 | 350 | private fun animateChangeImpl(changeInfo: ChangeInfo) { 351 | val holder = changeInfo.oldHolder 352 | val view = holder?.itemView 353 | val newHolder = changeInfo.newHolder 354 | val newView = newHolder?.itemView 355 | if (view != null) { 356 | if (changeInfo.oldHolder != null) changeAnimations.add(changeInfo.oldHolder!!) 357 | val oldViewAnim = view.animate().setDuration( 358 | changeDuration 359 | ) 360 | oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX.toFloat()) 361 | oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY.toFloat()) 362 | oldViewAnim.alpha(0f).setListener(object : AnimatorListenerAdapter() { 363 | override fun onAnimationStart(animator: Animator) { 364 | dispatchChangeStarting(changeInfo.oldHolder, true) 365 | } 366 | 367 | override fun onAnimationEnd(animator: Animator) { 368 | oldViewAnim.setListener(null) 369 | view.alpha = 1f 370 | view.translationX = 0f 371 | view.translationY = 0f 372 | dispatchChangeFinished(changeInfo.oldHolder, true) 373 | if (changeInfo.oldHolder != null) changeAnimations.remove(changeInfo.oldHolder!!) 374 | dispatchFinishedWhenDone() 375 | } 376 | }).start() 377 | } 378 | if (newView != null) { 379 | if (changeInfo.newHolder != null) changeAnimations.add(changeInfo.newHolder!!) 380 | val newViewAnimation = newView.animate() 381 | newViewAnimation.translationX(0f).translationY(0f).setDuration(changeDuration).alpha(1f) 382 | .setListener(object : AnimatorListenerAdapter() { 383 | override fun onAnimationStart(animator: Animator) { 384 | dispatchChangeStarting(changeInfo.newHolder, false) 385 | } 386 | 387 | override fun onAnimationEnd(animator: Animator) { 388 | newViewAnimation.setListener(null) 389 | newView.alpha = 1f 390 | newView.translationX = 0f 391 | newView.translationY = 0f 392 | dispatchChangeFinished(changeInfo.newHolder, false) 393 | if (changeInfo.newHolder != null) changeAnimations.remove(changeInfo.newHolder!!) 394 | dispatchFinishedWhenDone() 395 | } 396 | }).start() 397 | } 398 | } 399 | 400 | private fun endChangeAnimation(infoList: MutableList, item: RecyclerView.ViewHolder) { 401 | for (i in infoList.indices.reversed()) { 402 | val changeInfo = infoList[i] 403 | if (endChangeAnimationIfNecessary(changeInfo, item)) { 404 | if (changeInfo.oldHolder == null && changeInfo.newHolder == null) { 405 | infoList.remove(changeInfo) 406 | } 407 | } 408 | } 409 | } 410 | 411 | private fun endChangeAnimationIfNecessary(changeInfo: ChangeInfo) { 412 | if (changeInfo.oldHolder != null) { 413 | endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder) 414 | } 415 | if (changeInfo.newHolder != null) { 416 | endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder) 417 | } 418 | } 419 | 420 | private fun endChangeAnimationIfNecessary( 421 | changeInfo: ChangeInfo, 422 | item: RecyclerView.ViewHolder? 423 | ): Boolean { 424 | var oldItem = false 425 | when { 426 | changeInfo.newHolder === item -> { 427 | changeInfo.newHolder = null 428 | } 429 | changeInfo.oldHolder === item -> { 430 | changeInfo.oldHolder = null 431 | oldItem = true 432 | } 433 | else -> { 434 | return false 435 | } 436 | } 437 | item!!.itemView.alpha = 1f 438 | item.itemView.translationX = 0f 439 | item.itemView.translationY = 0f 440 | dispatchChangeFinished(item, oldItem) 441 | return true 442 | } 443 | 444 | override fun endAnimation(item: RecyclerView.ViewHolder) { 445 | val view = item.itemView 446 | // this will trigger end callback which should set properties to their target values. 447 | view.animate().cancel() 448 | // TODO if some other animations are chained to end, how do we cancel them as well? 449 | for (i in pendingMoves.indices.reversed()) { 450 | val moveInfo = pendingMoves[i] 451 | if (moveInfo.holder === item) { 452 | view.translationY = 0f 453 | view.translationX = 0f 454 | dispatchMoveFinished(item) 455 | pendingMoves.removeAt(i) 456 | } 457 | } 458 | endChangeAnimation(pendingChanges, item) 459 | if (pendingRemovals.remove(item)) { 460 | clear(item.itemView) 461 | dispatchRemoveFinished(item) 462 | } 463 | if (pendingAdditions.remove(item)) { 464 | clear(item.itemView) 465 | dispatchAddFinished(item) 466 | } 467 | for (i in changesList.indices.reversed()) { 468 | val changes = changesList[i] 469 | endChangeAnimation(changes, item) 470 | if (changes.isEmpty()) { 471 | changesList.removeAt(i) 472 | } 473 | } 474 | for (i in movesList.indices.reversed()) { 475 | val moves = movesList[i] 476 | for (j in moves.indices.reversed()) { 477 | val moveInfo = moves[j] 478 | if (moveInfo.holder === item) { 479 | view.translationY = 0f 480 | view.translationX = 0f 481 | dispatchMoveFinished(item) 482 | moves.removeAt(j) 483 | if (moves.isEmpty()) { 484 | movesList.removeAt(i) 485 | } 486 | break 487 | } 488 | } 489 | } 490 | for (i in additionsList.indices.reversed()) { 491 | val additions = additionsList[i] 492 | if (additions.remove(item)) { 493 | clear(item.itemView) 494 | dispatchAddFinished(item) 495 | if (additions.isEmpty()) { 496 | additionsList.removeAt(i) 497 | } 498 | } 499 | } 500 | 501 | // animations should be ended by the cancel above. 502 | check(!(removeAnimations.remove(item) && DEBUG)) { "after animation is cancelled, item should not be in " + "mRemoveAnimations list" } 503 | check(!(addAnimations.remove(item) && DEBUG)) { "after animation is cancelled, item should not be in " + "mAddAnimations list" } 504 | check(!(changeAnimations.remove(item) && DEBUG)) { "after animation is cancelled, item should not be in " + "mChangeAnimations list" } 505 | check(!(moveAnimations.remove(item) && DEBUG)) { "after animation is cancelled, item should not be in " + "mMoveAnimations list" } 506 | dispatchFinishedWhenDone() 507 | } 508 | 509 | override fun isRunning(): Boolean { 510 | return (pendingAdditions.isNotEmpty() || pendingChanges.isNotEmpty() || pendingMoves.isNotEmpty() 511 | || pendingRemovals.isNotEmpty() || moveAnimations.isNotEmpty() || removeAnimations.isNotEmpty() 512 | || addAnimations.isNotEmpty() || changeAnimations.isNotEmpty() || movesList.isNotEmpty() 513 | || additionsList.isNotEmpty() || changesList.isNotEmpty()) 514 | } 515 | 516 | /** 517 | * Check the state of currently pending and running animations. If there are none 518 | * pending/running, call #dispatchAnimationsFinished() to notify any 519 | * listeners. 520 | */ 521 | private fun dispatchFinishedWhenDone() { 522 | if (!isRunning) { 523 | dispatchAnimationsFinished() 524 | } 525 | } 526 | 527 | override fun endAnimations() { 528 | var count = pendingMoves.size 529 | for (i in count - 1 downTo 0) { 530 | val item = pendingMoves[i] 531 | val view = item.holder.itemView 532 | view.translationY = 0f 533 | view.translationX = 0f 534 | dispatchMoveFinished(item.holder) 535 | pendingMoves.removeAt(i) 536 | } 537 | count = pendingRemovals.size 538 | for (i in count - 1 downTo 0) { 539 | val item = pendingRemovals[i] 540 | dispatchRemoveFinished(item) 541 | pendingRemovals.removeAt(i) 542 | } 543 | count = pendingAdditions.size 544 | for (i in count - 1 downTo 0) { 545 | val item = pendingAdditions[i] 546 | clear(item.itemView) 547 | dispatchAddFinished(item) 548 | pendingAdditions.removeAt(i) 549 | } 550 | count = pendingChanges.size 551 | for (i in count - 1 downTo 0) { 552 | endChangeAnimationIfNecessary(pendingChanges[i]) 553 | } 554 | pendingChanges.clear() 555 | if (!isRunning) { 556 | return 557 | } 558 | var listCount = movesList.size 559 | for (i in listCount - 1 downTo 0) { 560 | val moves = movesList[i] 561 | count = moves.size 562 | for (j in count - 1 downTo 0) { 563 | val moveInfo = moves[j] 564 | val item = moveInfo.holder 565 | val view = item.itemView 566 | view.translationY = 0f 567 | view.translationX = 0f 568 | dispatchMoveFinished(moveInfo.holder) 569 | moves.removeAt(j) 570 | if (moves.isEmpty()) { 571 | movesList.remove(moves) 572 | } 573 | } 574 | } 575 | listCount = additionsList.size 576 | for (i in listCount - 1 downTo 0) { 577 | val additions = additionsList[i] 578 | count = additions.size 579 | for (j in count - 1 downTo 0) { 580 | val item = additions[j] 581 | val view = item.itemView 582 | view.alpha = 1f 583 | dispatchAddFinished(item) 584 | //this check prevent exception when removal already happened during finishing animation 585 | if (j < additions.size) { 586 | additions.removeAt(j) 587 | } 588 | if (additions.isEmpty()) { 589 | additionsList.remove(additions) 590 | } 591 | } 592 | } 593 | listCount = changesList.size 594 | for (i in listCount - 1 downTo 0) { 595 | val changes = changesList[i] 596 | count = changes.size 597 | for (j in count - 1 downTo 0) { 598 | endChangeAnimationIfNecessary(changes[j]) 599 | if (changes.isEmpty()) { 600 | changesList.remove(changes) 601 | } 602 | } 603 | } 604 | cancelAll(removeAnimations) 605 | cancelAll(moveAnimations) 606 | cancelAll(addAnimations) 607 | cancelAll(changeAnimations) 608 | dispatchAnimationsFinished() 609 | } 610 | 611 | private fun cancelAll(viewHolders: List) { 612 | for (i in viewHolders.indices.reversed()) { 613 | viewHolders[i].itemView.animate().cancel() 614 | } 615 | } 616 | 617 | open class AnimatorListenerAdapter : Animator.AnimatorListener { 618 | override fun onAnimationStart(animator: Animator) {} 619 | override fun onAnimationEnd(animator: Animator) {} 620 | override fun onAnimationCancel(animator: Animator) {} 621 | override fun onAnimationRepeat(animator: Animator) {} 622 | } 623 | 624 | inner class DefaultAddAnimatorListener(var viewHolder: RecyclerView.ViewHolder) : 625 | AnimatorListenerAdapter() { 626 | override fun onAnimationStart(animator: Animator) { 627 | dispatchAddStarting(viewHolder) 628 | } 629 | 630 | override fun onAnimationCancel(animator: Animator) { 631 | clear(viewHolder.itemView) 632 | } 633 | 634 | override fun onAnimationEnd(animator: Animator) { 635 | clear(viewHolder.itemView) 636 | dispatchAddFinished(viewHolder) 637 | addAnimations.remove(viewHolder) 638 | dispatchFinishedWhenDone() 639 | } 640 | } 641 | 642 | protected inner class DefaultRemoveAnimatorListener(var viewHolder: RecyclerView.ViewHolder) : 643 | AnimatorListenerAdapter() { 644 | override fun onAnimationStart(animator: Animator) { 645 | dispatchRemoveStarting(viewHolder) 646 | } 647 | 648 | override fun onAnimationCancel(animator: Animator) { 649 | clear(viewHolder.itemView) 650 | } 651 | 652 | override fun onAnimationEnd(animator: Animator) { 653 | clear(viewHolder.itemView) 654 | dispatchRemoveFinished(viewHolder) 655 | removeAnimations.remove(viewHolder) 656 | dispatchFinishedWhenDone() 657 | } 658 | } 659 | } 660 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/FadeInAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class FadeInAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | alpha(0f) 30 | duration = removeDuration 31 | interpolator = interpolator 32 | setListener(DefaultRemoveAnimatorListener(holder)) 33 | startDelay = getRemoveDelay(holder) 34 | }.start() 35 | } 36 | 37 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 38 | holder.itemView.alpha = 0f 39 | } 40 | 41 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 42 | holder.itemView.animate().apply { 43 | alpha(1f) 44 | duration = addDuration 45 | interpolator = interpolator 46 | setListener(DefaultAddAnimatorListener(holder)) 47 | startDelay = getAddDelay(holder) 48 | }.start() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/FadeInDownAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class FadeInDownAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | translationY(-holder.itemView.height * .25f) 30 | alpha(0f) 31 | duration = removeDuration 32 | interpolator = interpolator 33 | setListener(DefaultRemoveAnimatorListener(holder)) 34 | startDelay = getRemoveDelay(holder) 35 | }.start() 36 | } 37 | 38 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 39 | holder.itemView.translationY = -holder.itemView.height * .25f 40 | holder.itemView.alpha = 0f 41 | } 42 | 43 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 44 | holder.itemView.animate().apply { 45 | translationY(0f) 46 | alpha(1f) 47 | duration = addDuration 48 | interpolator = interpolator 49 | setListener(DefaultAddAnimatorListener(holder)) 50 | startDelay = getAddDelay(holder) 51 | }.start() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/FadeInLeftAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class FadeInLeftAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | translationX(-holder.itemView.rootView.width * .25f) 30 | alpha(0f) 31 | duration = removeDuration 32 | interpolator = interpolator 33 | setListener(DefaultRemoveAnimatorListener(holder)) 34 | startDelay = getRemoveDelay(holder) 35 | }.start() 36 | } 37 | 38 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 39 | holder.itemView.translationX = -holder.itemView.rootView.width * .25f 40 | holder.itemView.alpha = 0f 41 | } 42 | 43 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 44 | holder.itemView.animate().apply { 45 | translationX(0f) 46 | alpha(1f) 47 | duration = addDuration 48 | interpolator = interpolator 49 | setListener(DefaultAddAnimatorListener(holder)) 50 | startDelay = getAddDelay(holder) 51 | }.start() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/FadeInRightAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class FadeInRightAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | translationX(holder.itemView.rootView.width * .25f) 30 | alpha(0f) 31 | duration = removeDuration 32 | interpolator = interpolator 33 | setListener(DefaultRemoveAnimatorListener(holder)) 34 | startDelay = getRemoveDelay(holder) 35 | }.start() 36 | } 37 | 38 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 39 | holder.itemView.translationX = holder.itemView.rootView.width * .25f 40 | holder.itemView.alpha = 0f 41 | } 42 | 43 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 44 | holder.itemView.animate().apply { 45 | translationX(0f) 46 | alpha(1f) 47 | duration = addDuration 48 | interpolator = interpolator 49 | setListener(DefaultAddAnimatorListener(holder)) 50 | startDelay = getAddDelay(holder) 51 | }.start() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/FadeInUpAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class FadeInUpAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | translationY(holder.itemView.height * .25f) 30 | alpha(0f) 31 | duration = removeDuration 32 | interpolator = interpolator 33 | setListener(DefaultRemoveAnimatorListener(holder)) 34 | startDelay = getRemoveDelay(holder) 35 | }.start() 36 | } 37 | 38 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 39 | holder.itemView.translationY = holder.itemView.height * .25f 40 | holder.itemView.alpha = 0f 41 | } 42 | 43 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 44 | holder.itemView.animate().apply { 45 | translationY(0f) 46 | alpha(1f) 47 | duration = addDuration 48 | interpolator = interpolator 49 | setListener(DefaultAddAnimatorListener(holder)) 50 | startDelay = getAddDelay(holder) 51 | }.start() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/FlipInBottomXAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class FlipInBottomXAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | rotationX(-90f) 30 | duration = removeDuration 31 | interpolator = interpolator 32 | setListener(DefaultRemoveAnimatorListener(holder)) 33 | startDelay = getRemoveDelay(holder) 34 | }.start() 35 | } 36 | 37 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 38 | holder.itemView.rotationX = -90f 39 | } 40 | 41 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 42 | holder.itemView.animate().apply { 43 | rotationX(0f) 44 | duration = addDuration 45 | interpolator = interpolator 46 | setListener(DefaultAddAnimatorListener(holder)) 47 | startDelay = getAddDelay(holder) 48 | }.start() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/FlipInLeftYAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class FlipInLeftYAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | rotationY(90f) 30 | duration = removeDuration 31 | interpolator = interpolator 32 | setListener(DefaultRemoveAnimatorListener(holder)) 33 | startDelay = getRemoveDelay(holder) 34 | }.start() 35 | } 36 | 37 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 38 | holder.itemView.rotationY = 90f 39 | } 40 | 41 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 42 | holder.itemView.animate().apply { 43 | rotationY(0f) 44 | duration = addDuration 45 | interpolator = interpolator 46 | setListener(DefaultAddAnimatorListener(holder)) 47 | startDelay = getAddDelay(holder) 48 | }.start() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/FlipInRightYAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class FlipInRightYAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | rotationY(-90f) 30 | duration = removeDuration 31 | interpolator = interpolator 32 | setListener(DefaultRemoveAnimatorListener(holder)) 33 | startDelay = getRemoveDelay(holder) 34 | }.start() 35 | } 36 | 37 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 38 | holder.itemView.rotationY = -90f 39 | } 40 | 41 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 42 | holder.itemView.animate().apply { 43 | rotationY(0f) 44 | duration = addDuration 45 | interpolator = interpolator 46 | setListener(DefaultAddAnimatorListener(holder)) 47 | startDelay = getAddDelay(holder) 48 | }.start() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/FlipInTopXAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class FlipInTopXAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | rotationX(90f) 30 | duration = removeDuration 31 | interpolator = interpolator 32 | setListener(DefaultRemoveAnimatorListener(holder)) 33 | startDelay = getRemoveDelay(holder) 34 | }.start() 35 | } 36 | 37 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 38 | holder.itemView.rotationX = 90f 39 | } 40 | 41 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 42 | holder.itemView.animate().apply { 43 | rotationX(0f) 44 | duration = addDuration 45 | interpolator = interpolator 46 | setListener(DefaultAddAnimatorListener(holder)) 47 | startDelay = getAddDelay(holder) 48 | }.start() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/LandingAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class LandingAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | alpha(0f) 30 | .scaleX(1.5f) 31 | .scaleY(1.5f) 32 | duration = removeDuration 33 | interpolator = interpolator 34 | setListener(DefaultRemoveAnimatorListener(holder)) 35 | startDelay = getRemoveDelay(holder) 36 | }.start() 37 | } 38 | 39 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 40 | holder.itemView.alpha = 0f 41 | holder.itemView.scaleX = 1.5f 42 | holder.itemView.scaleY = 1.5f 43 | } 44 | 45 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 46 | holder.itemView.animate().apply { 47 | alpha(1f) 48 | scaleX(1f) 49 | scaleY(1f) 50 | duration = addDuration 51 | interpolator = interpolator 52 | setListener(DefaultAddAnimatorListener(holder)) 53 | startDelay = getAddDelay(holder) 54 | }.start() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/OvershootInLeftAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.OvershootInterpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class OvershootInLeftAnimator : BaseItemAnimator { 22 | private val tension: Float 23 | 24 | constructor() { 25 | tension = 2.0f 26 | } 27 | 28 | constructor(tension: Float) { 29 | this.tension = tension 30 | } 31 | 32 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 33 | holder.itemView.animate().apply { 34 | translationX(-holder.itemView.rootView.width.toFloat()) 35 | duration = removeDuration 36 | setListener(DefaultRemoveAnimatorListener(holder)) 37 | startDelay = getRemoveDelay(holder) 38 | }.start() 39 | } 40 | 41 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 42 | holder.itemView.translationX = -holder.itemView.rootView.width.toFloat() 43 | } 44 | 45 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 46 | holder.itemView.animate().apply { 47 | translationX(0f) 48 | duration = addDuration 49 | setListener(DefaultAddAnimatorListener(holder)) 50 | interpolator = OvershootInterpolator(tension) 51 | startDelay = getAddDelay(holder) 52 | }.start() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/OvershootInRightAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.OvershootInterpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class OvershootInRightAnimator : BaseItemAnimator { 22 | private val tension: Float 23 | 24 | constructor() { 25 | tension = 2.0f 26 | } 27 | 28 | constructor(tension: Float) { 29 | this.tension = tension 30 | } 31 | 32 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 33 | holder.itemView.animate().apply { 34 | translationX(holder.itemView.rootView.width.toFloat()) 35 | duration = removeDuration 36 | setListener(DefaultRemoveAnimatorListener(holder)) 37 | startDelay = getRemoveDelay(holder) 38 | }.start() 39 | } 40 | 41 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 42 | holder.itemView.translationX = holder.itemView.rootView.width.toFloat() 43 | } 44 | 45 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 46 | holder.itemView.animate().apply { 47 | translationX(0f) 48 | duration = addDuration 49 | interpolator = OvershootInterpolator(tension) 50 | setListener(DefaultAddAnimatorListener(holder)) 51 | startDelay = getAddDelay(holder) 52 | }.start() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/ScaleInAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class ScaleInAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | scaleX(0f) 30 | scaleY(0f) 31 | duration = removeDuration 32 | interpolator = interpolator 33 | setListener(DefaultRemoveAnimatorListener(holder)) 34 | startDelay = getRemoveDelay(holder) 35 | }.start() 36 | } 37 | 38 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 39 | holder.itemView.scaleX = 0f 40 | holder.itemView.scaleY = 0f 41 | } 42 | 43 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 44 | holder.itemView.animate().apply { 45 | scaleX(1f) 46 | scaleY(1f) 47 | duration = addDuration 48 | interpolator = interpolator 49 | setListener(DefaultAddAnimatorListener(holder)) 50 | startDelay = getAddDelay(holder) 51 | }.start() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/ScaleInBottomAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class ScaleInBottomAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun preAnimateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.pivotY = holder.itemView.height.toFloat() 29 | } 30 | 31 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 32 | holder.itemView.animate().apply { 33 | scaleX(0f) 34 | scaleY(0f) 35 | duration = removeDuration 36 | interpolator = interpolator 37 | setListener(DefaultRemoveAnimatorListener(holder)) 38 | startDelay = getRemoveDelay(holder) 39 | }.start() 40 | } 41 | 42 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 43 | holder.itemView.pivotY = holder.itemView.height.toFloat() 44 | holder.itemView.scaleX = 0f 45 | holder.itemView.scaleY = 0f 46 | } 47 | 48 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 49 | holder.itemView.animate().apply { 50 | scaleX(1f) 51 | scaleY(1f) 52 | duration = addDuration 53 | interpolator = interpolator 54 | setListener(DefaultAddAnimatorListener(holder)) 55 | startDelay = getAddDelay(holder) 56 | }.start() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/ScaleInLeftAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class ScaleInLeftAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun preAnimateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.pivotX = 0f 29 | } 30 | 31 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 32 | holder.itemView.animate().apply { 33 | scaleX(0f) 34 | scaleY(0f) 35 | duration = removeDuration 36 | interpolator = interpolator 37 | setListener(DefaultRemoveAnimatorListener(holder)) 38 | startDelay = getRemoveDelay(holder) 39 | }.start() 40 | } 41 | 42 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 43 | holder.itemView.pivotX = 0f 44 | holder.itemView.scaleX = 0f 45 | holder.itemView.scaleY = 0f 46 | } 47 | 48 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 49 | holder.itemView.animate().apply { 50 | scaleX(1f) 51 | scaleY(1f) 52 | duration = addDuration 53 | interpolator = interpolator 54 | setListener(DefaultAddAnimatorListener(holder)) 55 | startDelay = getAddDelay(holder) 56 | }.start() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/ScaleInRightAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class ScaleInRightAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun preAnimateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.pivotX = holder.itemView.width.toFloat() 29 | } 30 | 31 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 32 | holder.itemView.animate().apply { 33 | scaleX(0f) 34 | scaleY(0f) 35 | duration = removeDuration 36 | interpolator = interpolator 37 | setListener(DefaultRemoveAnimatorListener(holder)) 38 | startDelay = getRemoveDelay(holder) 39 | }.start() 40 | } 41 | 42 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 43 | holder.itemView.pivotX = holder.itemView.width.toFloat() 44 | holder.itemView.scaleX = 0f 45 | holder.itemView.scaleY = 0f 46 | } 47 | 48 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 49 | holder.itemView.animate().apply { 50 | scaleX(1f) 51 | scaleY(1f) 52 | duration = addDuration 53 | interpolator = interpolator 54 | setListener(DefaultAddAnimatorListener(holder)) 55 | startDelay = getAddDelay(holder) 56 | }.start() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/ScaleInTopAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class ScaleInTopAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun preAnimateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.pivotY = 0f 29 | } 30 | 31 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 32 | holder.itemView.animate().apply { 33 | scaleX(0f) 34 | scaleY(0f) 35 | duration = removeDuration 36 | interpolator = interpolator 37 | setListener(DefaultRemoveAnimatorListener(holder)) 38 | startDelay = getRemoveDelay(holder) 39 | }.start() 40 | } 41 | 42 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 43 | holder.itemView.pivotY = 0f 44 | holder.itemView.scaleX = 0f 45 | holder.itemView.scaleY = 0f 46 | } 47 | 48 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 49 | holder.itemView.animate().apply { 50 | scaleX(1f) 51 | scaleY(1f) 52 | duration = addDuration 53 | interpolator = interpolator 54 | setListener(DefaultAddAnimatorListener(holder)) 55 | startDelay = getAddDelay(holder) 56 | }.start() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/SlideInDownAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class SlideInDownAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | translationY(-holder.itemView.height.toFloat()) 30 | alpha(0f) 31 | duration = removeDuration 32 | interpolator = interpolator 33 | setListener(DefaultRemoveAnimatorListener(holder)) 34 | startDelay = getRemoveDelay(holder) 35 | }.start() 36 | } 37 | 38 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 39 | holder.itemView.translationY = -holder.itemView.height.toFloat() 40 | holder.itemView.alpha = 0f 41 | } 42 | 43 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 44 | holder.itemView.animate().apply { 45 | translationY(0f) 46 | alpha(1f) 47 | duration = addDuration 48 | interpolator = interpolator 49 | setListener(DefaultAddAnimatorListener(holder)) 50 | startDelay = getAddDelay(holder) 51 | }.start() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/SlideInLeftAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class SlideInLeftAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | translationX(-holder.itemView.rootView.width.toFloat()) 30 | duration = removeDuration 31 | interpolator = interpolator 32 | setListener(DefaultRemoveAnimatorListener(holder)) 33 | startDelay = getRemoveDelay(holder) 34 | }.start() 35 | } 36 | 37 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 38 | holder.itemView.translationX = -holder.itemView.rootView.width.toFloat() 39 | } 40 | 41 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 42 | holder.itemView.animate().apply { 43 | translationX(0f) 44 | duration = addDuration 45 | interpolator = interpolator 46 | setListener(DefaultAddAnimatorListener(holder)) 47 | startDelay = getAddDelay(holder) 48 | }.start() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/SlideInRightAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class SlideInRightAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | translationX(holder.itemView.rootView.width.toFloat()) 30 | duration = removeDuration 31 | interpolator = interpolator 32 | setListener(DefaultRemoveAnimatorListener(holder)) 33 | startDelay = getRemoveDelay(holder) 34 | }.start() 35 | } 36 | 37 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 38 | holder.itemView.translationX = holder.itemView.rootView.width.toFloat() 39 | } 40 | 41 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 42 | holder.itemView.animate().apply { 43 | translationX(0f) 44 | duration = addDuration 45 | interpolator = interpolator 46 | setListener(DefaultAddAnimatorListener(holder)) 47 | startDelay = getAddDelay(holder) 48 | }.start() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/SlideInUpAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | /** 7 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | open class SlideInUpAnimator : BaseItemAnimator { 22 | constructor() 23 | constructor(interpolator: Interpolator) { 24 | this.interpolator = interpolator 25 | } 26 | 27 | override fun animateRemoveImpl(holder: RecyclerView.ViewHolder) { 28 | holder.itemView.animate().apply { 29 | translationY(holder.itemView.height.toFloat()) 30 | alpha(0f) 31 | duration = removeDuration 32 | interpolator = interpolator 33 | setListener(DefaultRemoveAnimatorListener(holder)) 34 | startDelay = getRemoveDelay(holder) 35 | }.start() 36 | } 37 | 38 | override fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) { 39 | holder.itemView.translationY = holder.itemView.height.toFloat() 40 | holder.itemView.alpha = 0f 41 | } 42 | 43 | override fun animateAddImpl(holder: RecyclerView.ViewHolder) { 44 | holder.itemView.animate().apply { 45 | translationY(0f) 46 | alpha(1f) 47 | duration = addDuration 48 | interpolator = interpolator 49 | setListener(DefaultAddAnimatorListener(holder)) 50 | startDelay = getAddDelay(holder) 51 | }.start() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/animators/holder/AnimateViewHolder.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.animators.holder 2 | 3 | import android.animation.Animator 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | interface AnimateViewHolder { 7 | fun preAnimateAddImpl(holder: RecyclerView.ViewHolder) 8 | fun preAnimateRemoveImpl(holder: RecyclerView.ViewHolder) 9 | fun animateAddImpl(holder: RecyclerView.ViewHolder, listener: Animator.AnimatorListener) 10 | fun animateRemoveImpl( 11 | holder: RecyclerView.ViewHolder, 12 | listener: Animator.AnimatorListener 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /animators/src/main/java/jp/wasabeef/recyclerview/internal/ViewHelper.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.recyclerview.internal 2 | 3 | import android.view.View 4 | 5 | /** 6 | * Copyright (C) 2021 Daichi Furiya / Wasabeef 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | object ViewHelper { 21 | @JvmStatic 22 | fun clear(v: View) { 23 | v.apply { 24 | alpha = 1f 25 | scaleY = 1f 26 | scaleX = 1f 27 | translationY = 0f 28 | translationX = 0f 29 | rotation = 0f 30 | rotationY = 0f 31 | rotationX = 0f 32 | pivotY = v.measuredHeight / 2f 33 | pivotX = v.measuredWidth / 2f 34 | animate().setInterpolator(null).startDelay = 0 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /art/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/art/demo.gif -------------------------------------------------------------------------------- /art/demo2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/art/demo2.gif -------------------------------------------------------------------------------- /art/demo3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/art/demo3.gif -------------------------------------------------------------------------------- /art/demo4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/art/demo4.gif -------------------------------------------------------------------------------- /art/demo5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/art/demo5.gif -------------------------------------------------------------------------------- /art/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/art/logo.jpg -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.72' 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5' 11 | classpath 'com.android.tools.build:gradle:4.2.0-beta04' 12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | google() 20 | mavenCentral() 21 | jcenter() 22 | } 23 | tasks.withType(Javadoc) { 24 | enabled = false 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | compileSdkVersion COMPILE_SDK_VERSION as int 6 | 7 | defaultConfig { 8 | minSdkVersion MIN_SDK_VERSION as int 9 | targetSdkVersion TARGET_SDK_VERSION as int 10 | versionCode VERSION_CODE as int 11 | versionName VERSION_NAME 12 | } 13 | 14 | // SigningConfigs 15 | apply from: '../signingConfigs/debug.gradle', to: android 16 | 17 | buildTypes { 18 | debug { 19 | debuggable true 20 | signingConfig signingConfigs.debug 21 | } 22 | release { 23 | debuggable false 24 | zipAlignEnabled true 25 | } 26 | } 27 | } 28 | 29 | repositories { 30 | // maven { url = "https://oss.sonatype.org/content/repositories/snapshots"} 31 | } 32 | 33 | dependencies { 34 | implementation project(':animators') 35 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 36 | implementation "androidx.appcompat:appcompat:1.2.0" 37 | implementation "androidx.recyclerview:recyclerview:1.1.0" 38 | implementation 'com.squareup.picasso:picasso:2.8' 39 | } 40 | -------------------------------------------------------------------------------- /example/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /example/src/main/java/jp/wasabeef/example/recyclerview/AdapterSampleActivity.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.example.recyclerview 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.view.View 6 | import android.view.animation.OvershootInterpolator 7 | import android.widget.AdapterView 8 | import android.widget.ArrayAdapter 9 | import android.widget.Spinner 10 | import androidx.appcompat.app.AppCompatActivity 11 | import androidx.recyclerview.widget.GridLayoutManager 12 | import androidx.recyclerview.widget.LinearLayoutManager 13 | import androidx.recyclerview.widget.RecyclerView 14 | import jp.wasabeef.recyclerview.adapters.AlphaInAnimationAdapter 15 | import jp.wasabeef.recyclerview.adapters.AnimationAdapter 16 | import jp.wasabeef.recyclerview.adapters.ScaleInAnimationAdapter 17 | import jp.wasabeef.recyclerview.adapters.SlideInBottomAnimationAdapter 18 | import jp.wasabeef.recyclerview.adapters.SlideInLeftAnimationAdapter 19 | import jp.wasabeef.recyclerview.adapters.SlideInRightAnimationAdapter 20 | import jp.wasabeef.recyclerview.animators.FadeInAnimator 21 | 22 | /** 23 | * Created by Daichi Furiya / Wasabeef on 2020/08/26. 24 | */ 25 | class AdapterSampleActivity : AppCompatActivity() { 26 | 27 | internal enum class Type { 28 | AlphaIn { 29 | override operator fun get(context: Context): AnimationAdapter { 30 | return AlphaInAnimationAdapter(MainAdapter(context, SampleData.LIST.toMutableList())) 31 | } 32 | }, 33 | ScaleIn { 34 | override operator fun get(context: Context): AnimationAdapter { 35 | return ScaleInAnimationAdapter(MainAdapter(context, SampleData.LIST.toMutableList())) 36 | } 37 | }, 38 | SlideInBottom { 39 | override operator fun get(context: Context): AnimationAdapter { 40 | return SlideInBottomAnimationAdapter(MainAdapter(context, SampleData.LIST.toMutableList())) 41 | } 42 | }, 43 | SlideInLeft { 44 | override operator fun get(context: Context): AnimationAdapter { 45 | return SlideInLeftAnimationAdapter(MainAdapter(context, SampleData.LIST.toMutableList())) 46 | } 47 | }, 48 | SlideInRight { 49 | override operator fun get(context: Context): AnimationAdapter { 50 | return SlideInRightAnimationAdapter(MainAdapter(context, SampleData.LIST.toMutableList())) 51 | } 52 | }; 53 | 54 | abstract operator fun get(context: Context): AnimationAdapter 55 | } 56 | 57 | override fun onCreate(savedInstanceState: Bundle?) { 58 | super.onCreate(savedInstanceState) 59 | setContentView(R.layout.activity_adapter_sample) 60 | 61 | setSupportActionBar(findViewById(R.id.tool_bar)) 62 | supportActionBar?.setDisplayShowTitleEnabled(false) 63 | 64 | val recyclerView = findViewById(R.id.list) 65 | recyclerView.layoutManager = if (intent.getBooleanExtra(MainActivity.KEY_GRID, true)) { 66 | GridLayoutManager(this, 2) 67 | } else { 68 | LinearLayoutManager(this) 69 | } 70 | 71 | val spinner = findViewById(R.id.spinner) 72 | spinner.adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1).apply { 73 | for (type in Type.values()) add(type.name) 74 | } 75 | spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { 76 | override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { 77 | recyclerView.adapter = Type.values()[position][view.context].apply { 78 | setFirstOnly(true) 79 | setDuration(500) 80 | setInterpolator(OvershootInterpolator(.5f)) 81 | } 82 | } 83 | 84 | override fun onNothingSelected(parent: AdapterView<*>) { 85 | // no-op 86 | } 87 | } 88 | 89 | recyclerView.itemAnimator = FadeInAnimator() 90 | val adapter = MainAdapter(this, SampleData.LIST.toMutableList()) 91 | recyclerView.adapter = AlphaInAnimationAdapter(adapter).apply { 92 | setFirstOnly(true) 93 | setDuration(500) 94 | setInterpolator(OvershootInterpolator(.5f)) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /example/src/main/java/jp/wasabeef/example/recyclerview/AnimatorSampleActivity.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.example.recyclerview 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import android.widget.AdapterView 6 | import android.widget.ArrayAdapter 7 | import android.widget.Spinner 8 | import androidx.appcompat.app.AppCompatActivity 9 | import androidx.recyclerview.widget.GridLayoutManager 10 | import androidx.recyclerview.widget.LinearLayoutManager 11 | import androidx.recyclerview.widget.RecyclerView 12 | import jp.wasabeef.recyclerview.animators.BaseItemAnimator 13 | import jp.wasabeef.recyclerview.animators.FadeInAnimator 14 | import jp.wasabeef.recyclerview.animators.FadeInDownAnimator 15 | import jp.wasabeef.recyclerview.animators.FadeInLeftAnimator 16 | import jp.wasabeef.recyclerview.animators.FadeInRightAnimator 17 | import jp.wasabeef.recyclerview.animators.FadeInUpAnimator 18 | import jp.wasabeef.recyclerview.animators.FlipInBottomXAnimator 19 | import jp.wasabeef.recyclerview.animators.FlipInLeftYAnimator 20 | import jp.wasabeef.recyclerview.animators.FlipInRightYAnimator 21 | import jp.wasabeef.recyclerview.animators.FlipInTopXAnimator 22 | import jp.wasabeef.recyclerview.animators.LandingAnimator 23 | import jp.wasabeef.recyclerview.animators.OvershootInLeftAnimator 24 | import jp.wasabeef.recyclerview.animators.OvershootInRightAnimator 25 | import jp.wasabeef.recyclerview.animators.ScaleInAnimator 26 | import jp.wasabeef.recyclerview.animators.ScaleInBottomAnimator 27 | import jp.wasabeef.recyclerview.animators.ScaleInLeftAnimator 28 | import jp.wasabeef.recyclerview.animators.ScaleInRightAnimator 29 | import jp.wasabeef.recyclerview.animators.ScaleInTopAnimator 30 | import jp.wasabeef.recyclerview.animators.SlideInDownAnimator 31 | import jp.wasabeef.recyclerview.animators.SlideInLeftAnimator 32 | import jp.wasabeef.recyclerview.animators.SlideInRightAnimator 33 | import jp.wasabeef.recyclerview.animators.SlideInUpAnimator 34 | 35 | /** 36 | * Created by Daichi Furiya / Wasabeef on 2020/08/26. 37 | */ 38 | class AnimatorSampleActivity : AppCompatActivity() { 39 | 40 | internal enum class Type(val animator: BaseItemAnimator) { 41 | FadeIn(FadeInAnimator()), 42 | FadeInDown(FadeInDownAnimator()), 43 | FadeInUp(FadeInUpAnimator()), 44 | FadeInLeft(FadeInLeftAnimator()), 45 | FadeInRight(FadeInRightAnimator()), 46 | Landing(LandingAnimator()), 47 | ScaleIn(ScaleInAnimator()), 48 | ScaleInTop(ScaleInTopAnimator()), 49 | ScaleInBottom(ScaleInBottomAnimator()), 50 | ScaleInLeft(ScaleInLeftAnimator()), 51 | ScaleInRight(ScaleInRightAnimator()), 52 | FlipInTopX(FlipInTopXAnimator()), 53 | FlipInBottomX(FlipInBottomXAnimator()), 54 | FlipInLeftY(FlipInLeftYAnimator()), 55 | FlipInRightY(FlipInRightYAnimator()), 56 | SlideInLeft(SlideInLeftAnimator()), 57 | SlideInRight(SlideInRightAnimator()), 58 | SlideInDown(SlideInDownAnimator()), 59 | SlideInUp(SlideInUpAnimator()), 60 | OvershootInRight(OvershootInRightAnimator(1.0f)), 61 | OvershootInLeft(OvershootInLeftAnimator(1.0f)) 62 | } 63 | 64 | private val adapter = MainAdapter(this, SampleData.LIST.toMutableList()) 65 | 66 | override fun onCreate(savedInstanceState: Bundle?) { 67 | super.onCreate(savedInstanceState) 68 | setContentView(R.layout.activity_animator_sample) 69 | 70 | setSupportActionBar(findViewById(R.id.tool_bar)) 71 | supportActionBar?.setDisplayShowTitleEnabled(false) 72 | 73 | val recyclerView = findViewById(R.id.list) 74 | recyclerView.apply { 75 | itemAnimator = SlideInLeftAnimator() 76 | adapter = this@AnimatorSampleActivity.adapter 77 | 78 | layoutManager = if (intent.getBooleanExtra(MainActivity.KEY_GRID, true)) { 79 | GridLayoutManager(context, 2) 80 | } else { 81 | LinearLayoutManager(context) 82 | } 83 | } 84 | 85 | 86 | val spinner = findViewById(R.id.spinner) 87 | val spinnerAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1) 88 | for (type in Type.values()) { 89 | spinnerAdapter.add(type.name) 90 | } 91 | spinner.adapter = spinnerAdapter 92 | spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { 93 | override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { 94 | recyclerView.itemAnimator = Type.values()[position].animator 95 | recyclerView.itemAnimator?.addDuration = 500 96 | recyclerView.itemAnimator?.removeDuration = 500 97 | } 98 | 99 | override fun onNothingSelected(parent: AdapterView<*>) { 100 | // no-op 101 | } 102 | } 103 | 104 | findViewById(R.id.add).setOnClickListener { adapter.add("newly added item", 1) } 105 | 106 | findViewById(R.id.del).setOnClickListener { adapter.remove(1) } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /example/src/main/java/jp/wasabeef/example/recyclerview/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.example.recyclerview 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.view.View 6 | import androidx.appcompat.app.AppCompatActivity 7 | import androidx.appcompat.widget.SwitchCompat 8 | 9 | /** 10 | * Created by Daichi Furiya / Wasabeef on 2020/08/26. 11 | */ 12 | class MainActivity : AppCompatActivity() { 13 | 14 | companion object { 15 | const val KEY_GRID = "GRID" 16 | } 17 | 18 | private var enabledGrid = false 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | setContentView(R.layout.activity_main) 23 | 24 | findViewById(R.id.btn_animator_sample).setOnClickListener { 25 | startActivity(Intent(this, AnimatorSampleActivity::class.java).apply { 26 | putExtra(KEY_GRID, enabledGrid) 27 | }) 28 | } 29 | 30 | findViewById(R.id.btn_adapter_sample).setOnClickListener { 31 | startActivity(Intent(this, AdapterSampleActivity::class.java).apply { 32 | putExtra(KEY_GRID, enabledGrid) 33 | }) 34 | } 35 | 36 | findViewById(R.id.grid).setOnCheckedChangeListener { _, isChecked -> 37 | enabledGrid = isChecked 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /example/src/main/java/jp/wasabeef/example/recyclerview/MainAdapter.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.example.recyclerview 2 | 3 | import android.content.Context 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.ImageView 8 | import android.widget.TextView 9 | import androidx.recyclerview.widget.RecyclerView 10 | import com.squareup.picasso.Picasso 11 | 12 | /** 13 | * Created by Daichi Furiya / Wasabeef on 2020/08/26. 14 | */ 15 | class MainAdapter(private val context: Context, private val dataSet: MutableList) : 16 | RecyclerView.Adapter() { 17 | 18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 19 | val v = LayoutInflater.from(context).inflate(R.layout.layout_list_item, parent, false) 20 | return ViewHolder(v) 21 | } 22 | 23 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 24 | Picasso.get().load(R.drawable.chip).into(holder.image) 25 | holder.text.text = dataSet[position] 26 | } 27 | 28 | override fun getItemCount(): Int { 29 | return dataSet.size 30 | } 31 | 32 | fun remove(position: Int) { 33 | dataSet.removeAt(position) 34 | notifyItemRemoved(position) 35 | } 36 | 37 | fun add(text: String, position: Int) { 38 | dataSet.add(position, text) 39 | notifyItemInserted(position) 40 | } 41 | 42 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 43 | 44 | var image: ImageView = itemView.findViewById(R.id.image) as ImageView 45 | var text: TextView = itemView.findViewById(R.id.text) as TextView 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/src/main/java/jp/wasabeef/example/recyclerview/MyAnimationAdapter.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.example.recyclerview 2 | 3 | import androidx.recyclerview.widget.RecyclerView 4 | import jp.wasabeef.recyclerview.adapters.AlphaInAnimationAdapter 5 | 6 | class MyAnimatorAdapter constructor( 7 | adapter: RecyclerView.Adapter, 8 | from: Float = 0.5f 9 | ) : AlphaInAnimationAdapter(adapter, from) { 10 | } 11 | -------------------------------------------------------------------------------- /example/src/main/java/jp/wasabeef/example/recyclerview/MyAnimator.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.example.recyclerview 2 | 3 | import android.view.animation.Interpolator 4 | import androidx.interpolator.view.animation.LinearOutSlowInInterpolator 5 | import jp.wasabeef.recyclerview.animators.ScaleInRightAnimator 6 | 7 | class MyAnimator( 8 | interpolator: Interpolator = LinearOutSlowInInterpolator() 9 | ) : ScaleInRightAnimator(interpolator) { 10 | } 11 | -------------------------------------------------------------------------------- /example/src/main/java/jp/wasabeef/example/recyclerview/SampleData.kt: -------------------------------------------------------------------------------- 1 | package jp.wasabeef.example.recyclerview 2 | 3 | /** 4 | * Created by Daichi Furiya / Wasabeef on 2020/08/26. 5 | */ 6 | interface SampleData { 7 | companion object { 8 | val LIST = arrayOf( 9 | "Apple", "Ball", "Camera", "Day", "Egg", "Foo", "Google", "Hello", 10 | "Iron", "Japan", "Coke", "Dog", "Cat", "Yahoo", "Sony", "Canon", "Fujitsu", "USA", "Nexus", 11 | "LINE", "Haskell", "C++", "Java", "Go", "Swift", "Objective-c", "Ruby", "PHP", "Bash", "ksh", 12 | "C", "Groovy", "Kotlin", "Chip", "Japan", "U.S.A", "San Francisco", "Paris", "Tokyo", 13 | "Silicon Valley", "London", "Spain", "China", "Taiwan", "Asia", "New York", "France", "Kyoto", 14 | "Android", "Google", "iPhone", "iPad", "iPod", "Wasabeef" 15 | ) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/example/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/example/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-xhdpi/chip.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/example/src/main/res/drawable-xhdpi/chip.jpg -------------------------------------------------------------------------------- /example/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/example/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-xxhdpi/ic_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/example/src/main/res/drawable-xxhdpi/ic_github.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasabeef/recyclerview-animators/6c5c7748e86f43d3d03f7b3122f473e1fd807681/example/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/src/main/res/layout/activity_adapter_sample.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /example/src/main/res/layout/activity_animator_sample.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 19 | 20 | 25 | 26 | 36 | 37 | 47 | 48 | 49 | 50 | 51 | 52 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /example/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 |