{"id":27938551,"url":"https://github.com/willowtreeapps/spruce-android","last_synced_at":"2025-05-15T08:08:41.414Z","repository":{"id":45143223,"uuid":"82968973","full_name":"willowtreeapps/spruce-android","owner":"willowtreeapps","description":"Spruce Animation Library","archived":false,"fork":false,"pushed_at":"2021-02-09T01:00:46.000Z","size":8169,"stargazers_count":3715,"open_issues_count":1,"forks_count":367,"subscribers_count":88,"default_branch":"master","last_synced_at":"2024-04-21T09:50:24.579Z","etag":null,"topics":["android","animation","animation-library","design","spruce"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/willowtreeapps.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"Contributing.md","funding":null,"license":"LICENSE","code_of_conduct":"code-of-conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-23T20:34:18.000Z","updated_at":"2024-04-16T15:38:28.000Z","dependencies_parsed_at":"2022-07-13T16:45:04.215Z","dependency_job_id":null,"html_url":"https://github.com/willowtreeapps/spruce-android","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willowtreeapps%2Fspruce-android","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willowtreeapps%2Fspruce-android/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willowtreeapps%2Fspruce-android/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willowtreeapps%2Fspruce-android/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/willowtreeapps","download_url":"https://codeload.github.com/willowtreeapps/spruce-android/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252847250,"owners_count":21813438,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","animation","animation-library","design","spruce"],"created_at":"2025-05-07T08:49:12.711Z","updated_at":"2025-05-07T08:49:13.285Z","avatar_url":"https://github.com/willowtreeapps.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Spruce Logo](https://github.com/willowtreeapps/spruce-android/blob/master/imgs/header_image.png)\n\n# Spruce Android Animation Library (and [iOS](https://github.com/willowtreeapps/spruce-ios))\n[![CircleCI Build Status](https://circleci.com/gh/willowtreeapps/spruce-android.svg?style=shield)](https://circleci.com/gh/willowtreeapps/spruce-android)\n[![License MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat)]()\n[![Public Yes](https://img.shields.io/badge/Public-yes-green.svg?style=flat)]()\n\n## What is it?\nSpruce is a lightweight animation library that helps choreograph the animations on the screen. With so many different animation libraries out there, developers need to make sure that each view is animating at the appropriate time. Spruce can help designers request complex multi-view animations and not have the developers cringe at the prototype.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/willowtreeapps/spruce-android/blob/master/imgs/recycler-example.gif\" width=25% height=25%/\u003e\n\u003c/p\u003e\n\n### Gradle\nAdd the following to your project's root build.gradle file\n```gradle\nrepositories {\n\tmaven {\n\t\turl  \"https://dl.bintray.com/bfears/maven\"\n\t}\n}\n```\nAdd the following to your project's build.gradle file\n\n```gradle\ndependencies {\n    implementation 'com.willowtreeapps.spruce:spruce-android:1.1.0'\n}\n```\n\n## Documentation\nFor javadocs checkout [the documentation](https://willowtreeapps.github.io/spruce-android/) for more information.\n\n## Basic Usage\n```java\nAnimator spruceAnimator = new Spruce\n        .SpruceBuilder(parentViewGroup)\n        .sortWith(new Default(/*interObjectDelay=*/50L))\n        .animateWith(new Animator[] {DefaultAnimations.shrinkAnimator(parentViewGroup, /*duration=*/800)})\n        .start();\n```\n\nCheckout [the builder documentation](https://willowtreeapps.github.io/spruce-android/com/willowtreeapps/spruce/Spruce.SpruceBuilder.html) for more information.\n\n### Preparing for Animation\nSpruce comes packed with `Animator` options within the `DefaultAnimations` class meant to make your life easier when calling an animation. Let's say we want to have your views fade in. For example, we would create an `animators = new Animator[] {}` and add `DefaultAnimations.fadeInAnimator(parentViewGroup, /*duration=*/800)` as an array item.\nIf you want a view to fade in, then you need to make sure that it is already faded out. To do that, we need to set the alpha to `0` on the views or you could first use a fade out animator.\n\n### Running the Animation \n\nUse the following command to run a basic animation on your view.\n\n```java\nAnimator spruceAnimator = new Spruce\n        .SpruceBuilder(parentViewGroup)\n        .sortWith(new DefaultSort(/*interObjectDelay=*/50L))\n        .animateWith(animators)\n        .start();\n```\n\nCheckout [default animation documentation](https://willowtreeapps.github.io/spruce-android/com/willowtreeapps/spruce/animation/DefaultAnimations.html) for more information.\n\n## Using a SortFunction\nLuckily, Spruce comes with 8 `SortFunction` implementations with a wide open possibility to make more! Use the `SortFunction` to change the order in which views animate. Consider the following example:\n\n```java\nLinearSort sort = new LinearSort(/*interObjectDelay=*/100L, /*reversed=*/false, LinearSort.Direction.TOP_TO_BOTTOM);\n```\nIn this example we have created a `LinearSort` which will have views animate in from the top to bottom. We can change the look and feel of the animation by using a `RadialSort` instead which will have the views animate in a circular fashion. If we wanted to use this `sort` in an actual Spruce `start()` call then that would look something like:\n\n```java\nAnimator spruceAnimator = new Spruce\n        .SpruceBuilder(parentViewGroup)\n        .sortWith(new LinearSort(/*interObjectDelay=*/100L, /*reversed=*/false, LinearSort.Direction.TOP_TO_BOTTOM))\n        .animateWith(DefaultAnimations.shrinkAnimator(parentViewGroup, /*duration=*/800))\n        .start();\n```\nDefinitely play around with the stock `SortFunction` implementations until you find the one that is perfect for you! Check out the example app if you want to get previews of what each `SortFunction` will look like.\n\n### The Animators\nThe animations used in Spruce are produced by leveraging the `Animator` class. You may provide your own custom animations by creating your own `Animator` and provide it to the as part of an `Animator[]` to `SpruceBuilder.animateWith(Animator... animators)`. For more information on using the `Animator` class please check out https://developer.android.com/reference/android/animation/Animator.html\n\n### Standard Animation\nThe `DefaultAnimation` class provides simple `Animator` methods to apply the change `Animator` to the views. Use this class if you want to have a stock linear movement of the changes.\n\n## Sort Functions\nWith all different types of animations, especially those dealing with subviews, we have to consider a way in which we want to animate them. Some views can have 0 subviews while others may have hundreds. To handle this, we have the notion of a `SortFunction`. What this will do is take each of the subviews in the `ViewGroup`, and apply a mapping from the specific subview to the exact delay that it should wait before animating. Some of these will sort in a radial formation while others may actually sort randomly. One of the cool features of Spruce, is that you can actually define your own `SortFunction` and then the animation will look completely different. Luckily, Spruce also comes jam packed with a ton of default `SortFunction` classes to make everything easier on you as the developer. Take a look at some of the default `SortFunction` classes we have and see if you can use them or branch off of them for your cool and custom animations!\n\n### The SortFunction Interface\nA very simple interface that requires classes to extend the following class\n\n```java\npublic abstract class SortFunction {\n    public abstract List\u003cSpruceTimedView\u003e getViewListWithTimeOffsets(ViewGroup parent, List\u003cView\u003e children);\n}\n```\n\nWhat the above class needs to do is take in a `ViewGroup` parent and a `List` of `View` children or subviews to generate a list of subviews and their animation offsets. Once the list of subviews has been generated, you can define your own sort metric to determine in which order the `View`'s should animate. To do so, you need to create a `List` of `SpruceTimedView`'s. This special class has two properties: (1) `View view` and (2) `long timeOffset`. Your `SortFunction` can define the `timeOffset` however it likes, but the animators will use this to determine how long it should delay the start of that specific view from animating. The best way to learn, is to play around. So why not have some fun and make your own `SortFunction`!\n\n### About Sort Functions\nTo make sure that developers can use Spruce out of the box, we included about 8 stock `SortFunction` implementations. These are some of the main functions we use at WillowTree and are so excited to see what others come up with!\n\n- `DefaultSort`\n- `LinearSort`\n- `CorneredSort`\n- `RadialSort`\n- `RandomSort`\n- `InlineSort`\n- `ContinousSort`\n- `ContinuousWeightedSort`\n\nCheck out the docs [here](https://willowtreeapps.github.io/spruce-android/com/willowtreeapps/spruce/sort/SortFunction.html) for more information\n\n### View Exclusion Feature\n\nSpruce Animate all the views inside the view group. One of the key tips for pulling the best performance out of an Android app is to maintain a flat hierarchy. Spruce is now Introducing a new Exclusion feature.  \nThis work in 2 modes:\n- NORMAL_MODE: This mode should be used when you have view groups like Constraint/Frame/Relative/Linear Layouts. We feed a list of ids to be excluded to the SpruceBuilder.\n- R_L_MODE: This mode is used when we have ListView/RecyclerView. The only difference with the first mode is that we pass in the positions to be excluded instead of Ids.\n\n```java\nAnimator spruceAnimator = new Spruce\n        .SpruceBuilder(parentViewGroup)\n        .sortWith(new LinearSort(/*interObjectDelay=*/100L, /*reversed=*/false, LinearSort.Direction.TOP_TO_BOTTOM))\n        .excludeViews(getExcludedViewIds(), NORMAL_MODE)\n        //or \n       .excludeViews(getExcludedViewPosition(), R_L_MODE)\n        .start();\n```\n\n### Sort Function Interpolators\n\nSpruce now allows the user to control the overall flow of sort function using Interpolators. \n\n```java\nAnimator spruceAnimator = new Spruce\n        .SpruceBuilder(parentViewGroup)\n        .sortWith(new LinearSort(/*interObjectDelay=*/100L, /*reversed=*/false, LinearSort.Direction.TOP_TO_BOTTOM))\n        .addInterpolator(new LinearInterpolator())\n        .start();\n```\n\nSpruce gives you a wide variety of stock interpolators to choose from.\n\n- `SpruceInterpolators.EASE`\n- `SpruceInterpolators.EASE_IN`\n- `SpruceInterpolators.EASE_OUT`\n- `SpruceInterpolators.EASE_IN_OUT`\n- `SpruceInterpolators.EASE_IN_QUAD`\n- `SpruceInterpolators.EASE_IN_CUBIC`\n- `SpruceInterpolators.EASE_IN_QUART`\n- `SpruceInterpolators.EASE_IN_QUINT`\n- `SpruceInterpolators.EASE_IN_SINE`\n- `SpruceInterpolators.EASE_IN_EXPO`\n- ` SpruceInterpolators.EASE_IN_CIRC`\n- ` SpruceInterpolators.EASE_IN_BACK`\n- ` SpruceInterpolators.EASE_OUT_QUAD`\n- ` SpruceInterpolators.EASE_OUT_CUBIC`\n- ` SpruceInterpolators.EASE_OUT_QUART`\n- ` SpruceInterpolators.EASE_OUT_QUINT`\n- ` SpruceInterpolators.EASE_OUT_SINE`\n- ` SpruceInterpolators.EASE_OUT_EXPO`\n- ` SpruceInterpolators.EASE_OUT_CIRC`\n- ` SpruceInterpolators.EASE_OUT_BACK`\n- ` SpruceInterpolators.EASE_IN_OUT_QUAD`\n- ` SpruceInterpolators.EASE_IN_OUT_CUBIC`\n- ` SpruceInterpolators.EASE_IN_OUT_QUART`\n- ` SpruceInterpolators.EASE_IN_OUT_QUINT`\n- ` SpruceInterpolators.EASE_IN_OUT_SINE`\n- ` SpruceInterpolators.EASE_IN_OUT_EXPO`\n- ` SpruceInterpolators.EASE_IN_OUT_CIRC`\n- ` SpruceInterpolators.EASE_IN_OUT_BACK` \n\nCheckout [interpolator documentation](https://developer.android.com/reference/android/view/animation/Interpolator) for more information.\n\n## Spruce Dynamics\n\nSpruce now supports Dynamic Animations. Spruce Dynamics is an extension of the [androidx dynamic animations](https://developer.android.com/jetpack/androidx/releases/dynamicanimation).\n\nThese are the option that SpruceDynamics exposes to the developers:\n- Allows start delay for dynamic animations\n- Animation Property is now exposed (developers can set progress of the animations dynamically) \n\n\nYou can create your own Spring/Fling animations from SpruceDynamics and add them to the '.animateWith' function for\nplaying the animations in the respective ViewGroup\n\n```java\nAnimator spruceAnimator = new Spruce\n        .SpruceBuilder(parentViewGroup)\n        .sortWith(new LinearSort(/*interObjectDelay=*/100L, /*reversed=*/false, LinearSort.Direction.TOP_TO_BOTTOM))\n        .animateWith(DefaultAnimations.dynamicTranslationUpwards(parent))\n        .start();\n```\n\nAbove all these, With spruce, you can implement a combination of both Android Animations and Spruce Dynamics at the same time.\n\n ```java\n\n animators = new Object[]{\n         DefaultAnimations.dynamicTranslationUpwards(parent),\n         DefaultAnimations.dynamicFadeIn(parent),\n         DefaultAnimations.shrinkAnimator(parent,800)\n };\n\n\n Animator spruceAnimator = new Spruce\n         .SpruceBuilder(parentViewGroup)\n         .sortWith(new LinearSort(/*interObjectDelay=*/100L, /*reversed=*/false, LinearSort.Direction.TOP_TO_BOTTOM))\n         .animateWith(animators)\n         .start();\n ```\n\n## Stock Animators\nTo make everybody's lives easier, the stock animators perform basic `View` animations that a lot of apps use today. Mix and match these animators to get the core motion you are looking for.\n\n- `DefaultAnimations.growAnimator(View view, long duration)`\n- `DefaultAnimations.shrinkAnimator(View view, long duration)`\n- `DefaultAnimations.fadeAwayAnimator(View view, long duration)`\n- `DefaultAnimations.fadeInAnimator(View view, long duration)`\n- `DefaultAnimations.spinAnimator(View view, long duration)`\n- `DefaultAnimations.dynamicTranslationUpwards(View view)`\n- `DefaultAnimations.dynamicFadeIn(View view, long duration)`\n\nExperiment which ones work for you! If you think of anymore feel free to add them to the library yourself!\n\n# Example App\nUse the [example app](https://github.com/willowtreeapps/spruce-android/tree/master/app) to find the right `SortFunction`. In the app you will be able to see the affects of each `SortFunction`.\n\n## Contributing to Spruce\nContributions are more than welcome! Please see the [Contributing Guidelines](https://github.com/willowtreeapps/spruce-android/blob/master/Contributing.md) and be mindful of our [Code of Conduct](https://github.com/willowtreeapps/spruce-android/blob/master/code-of-conduct.md).\n\n# Issues or Future Ideas\nIf part of Spruce is not working correctly be sure to file a Github issue. In the issue provide as many details as possible. This could include example code or the exact steps that you did so that everyone can reproduce the issue. Sample projects are always the best way :). This makes it easy for our developers or someone from the open-source community to start working!\n\nIf you have a feature idea submit an issue with a feature request or submit a pull request and we will work with you to merge it in!\n\n## Third Party Bindings\n\n### React Native\nYou may now use this library with [React Native](https://github.com/facebook/react-native) via the module [here](https://github.com/prscX/react-native-spruce)\n\n\n# About WillowTree!\n![WillowTree Logo](https://github.com/willowtreeapps/spruce-android/blob/master/imgs/willowtree_logo.png)\n\nWe build apps, responsive sites, bots—any digital product that lives on a screen—for the world’s leading companies. Our elite teams challenge themselves to build extraordinary experiences by bridging the latest strategy and design thinking with enterprise-grade software development.\n\nInterested in working on more unique projects like Spruce? Check out our [careers page](http://willowtreeapps.com/careers?utm_campaign=spruce-gh).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwillowtreeapps%2Fspruce-android","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwillowtreeapps%2Fspruce-android","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwillowtreeapps%2Fspruce-android/lists"}