diff --git a/README.md b/README.md index afcd41c..3665582 100644 --- a/README.md +++ b/README.md @@ -1 +1,279 @@ -# jerry \ No newline at end of file +# jerry +[![](https://jitpack.io/v/alexandregpereira/jerry.svg)](https://jitpack.io/#alexandregpereira/jerry) + +Android library animation APIs that uses the [SpringAnimation](https://developer.android.com/guide/topics/graphics/spring-animation) behind. Jerry APIs helps to build complex physics based animations. This library also provides some animations ready to use that change the view visibility. + +## Why jerry? +Using a physics based animation makes the changes in target value more smooth and natural. When we use the default animation system provided by Android, these kind of changes in the traget value abrupted stops the continuation of the animation. The examples below ilustrate this behavior. + +**Figure 1.** Animation built with jerry physics-based APIs | **Figure 2.** Animation built with ViewProperty animation +-|- + | + +**Figure 1 code** +``` +moveView.translationXSpring(targetValue = pointX) + .translationYSpring(targetValue = pointY) + .force(stiffness = 60f, dampingRatio = 0.8f) + .start() +``` +**Figure 2 code** +``` +moveView.animate() + .translationX(pointX) + .translationY(pointY) + .setInterpolator(AccelerateDecelerateInterpolator()) + .setDuration(500) + .start() +``` + +## Setup +**Step 1.** Add the JitPack repository in your root build.gradle at the end of repositories: +``` + allprojects { + repositories { + ... + maven { url 'https://jitpack.io' } + } + } +``` +**Step 2.** Add the dependency +``` + dependencies { + implementation 'com.github.alexandregpereira:jerry:version' + } +``` + +## Animating view properties examples +Like the view property animation system provided by the `android.animation` package, you can use a set of APIs to change the view properties using jerry physic-based animation APIs. + +Example 1 | Example 2 | Example 3 +-|-|- + | | + + +Example 4 | Example 5 | Example 6 +-|-|- + | | + +### Example 1 + +
+ +
+ +``` +view.scaleXSpring(targetValue = 0.3f) + .scaleYSpring(targetValue = 0.3f) + .start() +``` + +### Example 2 + ++ +
+ +``` +view.apply { + scaleXSpring(targetValue = 0.6f) + .scaleYSpring(targetValue = 0.6f) + .after( + scaleXSpring(targetValue = 1f) + .scaleYSpring( + targetValue = 1f, + ) + .force(dampingRatio = 0.15f) + ) + .start() +} +``` + +### Example 3 + ++ +
+ +``` +view.rotationSpring(targetValue = 180f) + .start() +``` + +### Example 4 + ++ +
+ +``` +view.apply { + scaleXSpring(targetValue = 0.3f) + .scaleYSpring(targetValue = 0.3f) + .force(stiffness = 200f, dampingRatio = 0.7f) + .translationXSpring(targetValue = screenSize - width.toFloat() * 0.7f) + .lastForce(stiffness = 30f) + .start() +} +``` + +### Example 5 + ++ +
+ +``` +view.apply { + translationXSpring(targetValue = screenSize - width.toFloat()) + .force(stiffness = 200f) + .after( + translationXSpring(targetValue = 0f) + .force(dampingRatio = 0.5f) + ) + .start() +} +``` + +### Example 6 + ++ +
+ +``` +view.apply { + pivotX = width.toFloat() + translationXSpring(targetValue = screenSize - width.toFloat()) + .force(stiffness = 1000f) + .scaleXSpring(targetValue = 0.6f) + .lastForce(stiffness = 50f) + .after( + scaleXSpring(targetValue = 1f) + .after( + translationXSpring(targetValue = screenSize * 0.2f) + .force(dampingRatio = 0.3f) + ) + ) + .start() +} +``` + +## Changing view visibility using animation examples +This library also provides some animations ready to use that change the view visibility. + +### Expandable animation ++ +
+ +``` +// Expandable height +view.goneCollapseHeight() +// or +view.visibleOrGoneExpandableHeight(visible = false) + +view.visibleExpandHeight() +// or +view.visibleOrGoneExpandableHeight(visible = true) + +// Expandable width +view.goneCollapseWidth() +// or +view.visibleOrGoneExpandableWidth(visible = false) + +view.visibleExpandWidth() +// or +view.visibleOrGoneExpandableWidth(visible = true) +``` + +### Fade animation ++ +
+ +``` +// Fade text change +textView.setTextFadeSpring(text = "some text") + +// Fade out +view.goneFadeOut() +// or +view.visibleOrGoneFade(visible = false) + +// Fade in +view.visibleFadeIn() +// or +view.visibleOrGoneFade(visible = true) +``` + +### Expandable Fading ++ +
+ +``` +// Expandable height +view.goneCollapseHeightFadeOut() +// or +view.visibleOrGoneExpandableHeightFade(visible = false) + +view.visibleExpandHeightFadeIn() +// or +view.visibleOrGoneExpandableHeightFade(visible = true) + +// Expandable width +view.goneCollapseWidthFadeOut() +// or +view.visibleOrGoneExpandableWidthFade(visible = false) + +view.visibleExpandWidthFadeIn() +// or +view.visibleOrGoneExpandableWidthFade(visible = true) +``` + +## RecyclerView ItemAnimator +The class `BaseItemAnimator` provides the base of a custom `ItemAnimator` implementation. Overrides the methods `preAnimateAdd`, `startRemoveAnimation`, `startAddAnimation`, `startOldHolderChangeAnimation`, `startNewHolderChangeAnimation` or `startMoveAnimation` when you want to change any default animation. You can follow the `ElevationSpringItemAnimator` class in this repository as example. + +### ElevationSpringItemAnimator +The `ElevationSpringItemAnimator` resolves an animation problem post `LOLLIPOP` when we use a view with elevation in a RecyclerView with the default animations (`DefaultItemAnimator`). With default animations, the shadown behind the view appears when fade animation starts. The `ElevationSpringItemAnimator` overrides the default animations, adding the spring animations, and animating the elevation too. The examples below ilustrate this. + +ElevationSpringItemAnimator | DefaultItemAnimator +-|- + | + +Grid - ElevationSpringItemAnimator | Grid - DefaultItemAnimator +-|- + | + +``` +if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + recyclerView.itemAnimator = ElevationSpringItemAnimator() +} +``` + +## Sample App +Check more examples on the sample app in this repository. + +## Licence + MIT License + + Copyright (c) 2020 Alexandre Gomes Pereira + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/jerry/src/main/java/br/alexandregpereira/jerry/JerryAnimation.kt b/jerry/src/main/java/br/alexandregpereira/jerry/JerryAnimation.kt index 0429ce3..85ec3f9 100644 --- a/jerry/src/main/java/br/alexandregpereira/jerry/JerryAnimation.kt +++ b/jerry/src/main/java/br/alexandregpereira/jerry/JerryAnimation.kt @@ -2,12 +2,14 @@ package br.alexandregpereira.jerry import android.view.View import androidx.dynamicanimation.animation.SpringAnimation +import androidx.dynamicanimation.animation.SpringForce data class JerryAnimation( val key: Int, val view: View, val springAnimation: SpringAnimation, - internal val targetValue: Float + internal val targetValue: Float, + internal val springForce: SpringForce? = null ) { val isRunning: Boolean get() = springAnimation.isRunning diff --git a/jerry/src/main/java/br/alexandregpereira/jerry/SpringAnimation.kt b/jerry/src/main/java/br/alexandregpereira/jerry/SpringAnimation.kt index 4d1ab9a..c4f817b 100644 --- a/jerry/src/main/java/br/alexandregpereira/jerry/SpringAnimation.kt +++ b/jerry/src/main/java/br/alexandregpereira/jerry/SpringAnimation.kt @@ -48,10 +48,6 @@ fun View.spring( addSpringAnimationKeyIfNotContains(key) setTag(key, SpringAnimationHolder(springAnimation)) } - springAnimation.spring.apply { - this.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY - this.stiffness = ANIMATION_STIFFNESS - } return JerryAnimation(key = key, view = this, springAnimation, targetValue) } @@ -86,30 +82,32 @@ fun JerryAnimation.force( stiffness: Float = ANIMATION_STIFFNESS, dampingRatio: Float = SpringForce.DAMPING_RATIO_NO_BOUNCY ): JerryAnimation { - return this.apply { - springAnimation.spring.apply { - this.dampingRatio = dampingRatio - this.stiffness = stiffness - } + val springForce = SpringForce().apply { + this.dampingRatio = dampingRatio + this.stiffness = stiffness } + return this.copy( + springForce = springForce + ) } fun JerryAnimationSet.force( stiffness: Float = ANIMATION_STIFFNESS, dampingRatio: Float = SpringForce.DAMPING_RATIO_NO_BOUNCY ): JerryAnimationSet { - return this.apply { - jerryAnimations.forEach { it.force(stiffness, dampingRatio) } - } + return this.copy( + jerryAnimations = jerryAnimations.map { it.force(stiffness, dampingRatio) } + ) } fun JerryAnimationSet.lastForce( stiffness: Float = ANIMATION_STIFFNESS, dampingRatio: Float = SpringForce.DAMPING_RATIO_NO_BOUNCY ): JerryAnimationSet { - return this.apply { - jerryAnimations.last().force(stiffness, dampingRatio) - } + return this.copy( + jerryAnimations = jerryAnimations.subList(0, jerryAnimations.size - 1) + + jerryAnimations.last().force(stiffness, dampingRatio) + ) } private fun JerryAnimation.animationSet(): JerryAnimationSet { @@ -174,6 +172,10 @@ fun JerryAnimation.start( onAnimationEnd = onAnimationEnd ) + springAnimation.spring.apply { + this.dampingRatio = springForce?.dampingRatio ?: SpringForce.DAMPING_RATIO_NO_BOUNCY + this.stiffness = springForce?.stiffness ?: ANIMATION_STIFFNESS + } springAnimation.animateToFinalPosition(targetValue) } diff --git a/media/expandable-animation.gif b/media/expandable-animation.gif new file mode 100644 index 0000000..fd9a43c Binary files /dev/null and b/media/expandable-animation.gif differ diff --git a/media/expandable-fading-animation.gif b/media/expandable-fading-animation.gif new file mode 100644 index 0000000..77da1fa Binary files /dev/null and b/media/expandable-fading-animation.gif differ diff --git a/media/fade-animation.gif b/media/fade-animation.gif new file mode 100644 index 0000000..620ebad Binary files /dev/null and b/media/fade-animation.gif differ diff --git a/media/new-grid-animator.gif b/media/new-grid-animator.gif new file mode 100644 index 0000000..67e31cf Binary files /dev/null and b/media/new-grid-animator.gif differ diff --git a/media/new-list-animator.gif b/media/new-list-animator.gif new file mode 100644 index 0000000..df310b2 Binary files /dev/null and b/media/new-list-animator.gif differ diff --git a/media/normal-animation-example.gif b/media/normal-animation-example.gif new file mode 100644 index 0000000..e8af3d3 Binary files /dev/null and b/media/normal-animation-example.gif differ diff --git a/media/old-grid-animator.gif b/media/old-grid-animator.gif new file mode 100644 index 0000000..96cd5ba Binary files /dev/null and b/media/old-grid-animator.gif differ diff --git a/media/old-list-animator.gif b/media/old-list-animator.gif new file mode 100644 index 0000000..8c7631b Binary files /dev/null and b/media/old-list-animator.gif differ diff --git a/media/ping-pong-animation.gif b/media/ping-pong-animation.gif new file mode 100644 index 0000000..6b41586 Binary files /dev/null and b/media/ping-pong-animation.gif differ diff --git a/media/ping-pong-spring-animation.gif b/media/ping-pong-spring-animation.gif new file mode 100644 index 0000000..88bc9ed Binary files /dev/null and b/media/ping-pong-spring-animation.gif differ diff --git a/media/rotate-animation.gif b/media/rotate-animation.gif new file mode 100644 index 0000000..bd4d46d Binary files /dev/null and b/media/rotate-animation.gif differ diff --git a/media/scale-animation.gif b/media/scale-animation.gif new file mode 100644 index 0000000..b474f3a Binary files /dev/null and b/media/scale-animation.gif differ diff --git a/media/spring-animation-example.gif b/media/spring-animation-example.gif new file mode 100644 index 0000000..b70d7d4 Binary files /dev/null and b/media/spring-animation-example.gif differ diff --git a/media/spring-animation.gif b/media/spring-animation.gif new file mode 100644 index 0000000..d40311e Binary files /dev/null and b/media/spring-animation.gif differ diff --git a/media/translate-scale-animation.gif b/media/translate-scale-animation.gif new file mode 100644 index 0000000..5efe305 Binary files /dev/null and b/media/translate-scale-animation.gif differ