Skip to content

Commit

Permalink
add view visibility animation state, upped version, updated readme
Browse files Browse the repository at this point in the history
  • Loading branch information
David Ganster committed Jun 20, 2019
1 parent a5f9370 commit 21591d1
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 230 deletions.
72 changes: 69 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The amount code required to produce this animation is trivial:

```java
public boolean onTouch(View v, MotionEvent event) {
AdditiveAnimator.animate(animatedView).x(event.getX()).y(event.getY()).setDuration(1000).start();
AdditiveAnimator.animate(animatedView, 1000).x(event.getX()).y(event.getY()).start();
return true;
}
```
Expand Down Expand Up @@ -63,6 +63,69 @@ The timeline of this animation looks like this:

Check out `MultipleViewsAnimationDemoFragment` in the demo app for an example of this!


# Visibility animations
**New in 1.7.2**

View visibility can now be properly animated without adding an animation end block and checking if the visibility should be updated based on some other state variable:

```java
AdditiveAnimator.animate(view)
.fadeVisibility(View.GONE) // fades out the view, then sets visibility to GONE
.start();
```

Since fading the visibiliy is probably the most common usecase, there's a default builder method for it. A few more default animations are provided as well:

```java
AdditiveAnimator.animate(view)
// the first param decides whether the view should be GONE or INVISIBLE,
// the second one decides how much to move the view as it fades out
.visibility(ViewVisibilityAnimation.fadeOutAndTranslateX(true, 100f)) // only move x
.visibility(ViewVisibilityAnimation.fadeOutAndTranslateY(true, 100f)) // only move y
.visibility(ViewVisibilityAnimation.fadeOutAndTranslate(true, 100f, 100f)) // move x and y
.start();
```

The new `ViewVisibilityAnimation` class provides a convenient constructor to make your own view state animations - an example can be found in the new demo (`StateDemoFragment`).

# Animation States

`AdditiveAnimator` now supports the concepts of _animation states_.
A __State__ encapsulates a set of animations to perform and an ID to uniquely identify it.

What's special about this is that `AdditiveAnimator` can now automatically decide whether or not to run animation start/end blocks - if the view is no longer in the appropriate state for the block, it won't run.

This is how the view visibility feature is implemented, and can easily be extended to work with all kinds of custom states via the new `state()` builder method.

For example, we might want to switch the states of some views between __highlighted__ and __normal__ in a `then()`-chained block like this:

```java
new AdditiveAnimator()
.targets(normalViews)
.scale(1f) // normal
.then()
.target(highlightedView)
.scale(1.2f) // highlighted
.start();
```

There's a race condition in this piece of code: The `then()`-chaining block is executed whether or not the `highlightedView` is actually still highlighted.

Animation states fix this problem entirely:

```java
new AdditiveAnimator()
.targets(normalViews)
.state(MyViewState.NORMAL)
.then()
.target(highlightedView)
.state(MyViewState.HIGHLIGHTED)
.start();
```

With this code, the animations associated with the `NORMAL` and `HIGHLIGHTED` states are only allowed to run if the state of the enqueued animation still matches the current view state!

# Animating all kinds of objects and properties
In addition to the builder methods for views, there are multiple options for animating custom properties of any object.
The first option is subclassing `BaseAdditiveAnimator` and providing your own builder methods (which are usually one-liners) such as this:
Expand Down Expand Up @@ -114,15 +177,18 @@ AdditiveObjectAnimator.animate(myPaint)
.setAnimationApplier(new ViewAnimationApplier(myView)) // tells the generic AdditiveObjectAnimator how to apply the changed values
.start();
```

A more complete example of both of these approaches can be found in the sample app in `CustomDrawingFragment.java`.


Of course you can combine both approaches - custom builder methods which animate properties. This is the recommended approach and is how everything provided by `AdditiveAnimator` was built.

Both versions don't require a lot of code, and the few lines you have to write are almost always trivial.

# Integration
To use `AdditiveAnimator` in your project, add the following lines to your `build.gradle`:
```
dependencies {
compile 'at.wirecube:additive_animations:1.6.2'
compile 'at.wirecube:additive_animations:1.7.2'
}
...
repositories {
Expand Down
10 changes: 5 additions & 5 deletions additive_animations/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ext {
siteUrl = 'https://github.com/davidganster/android_additive_animations'
gitUrl = 'https://github.com/davidganster/android_additive_animations.git'

libraryVersion = '1.7.1'
libraryVersion = '1.7.2'

developerId = 'davidganster'
developerName = 'David Ganster'
Expand All @@ -48,8 +48,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 27
versionCode 19
versionName "1.7.1"
versionCode 20
versionName "1.7.2"
}
buildTypes {
release {
Expand All @@ -58,8 +58,8 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.Map;
import java.util.Set;

import at.wirecube.additiveanimations.additive_animator.view_visibility.ViewVisibilityAnimation;
import at.wirecube.additiveanimations.helper.AnimationUtils;
import at.wirecube.additiveanimations.helper.evaluators.ColorEvaluator;
import at.wirecube.additiveanimations.helper.propertywrappers.ColorProperties;
Expand Down Expand Up @@ -150,6 +151,22 @@ public void run() {
return self();
}

public T fadeVisibility(int visibility) {
switch(visibility) {
case View.VISIBLE:
return state(ViewVisibilityAnimation.fadeIn());
case View.INVISIBLE:
return state(ViewVisibilityAnimation.fadeOut(false));
case View.GONE:
return state(ViewVisibilityAnimation.fadeOut(true));
}
return self();
}

public T visibility(ViewVisibilityAnimation animation) {
return state(animation);
}

public T backgroundColor(int color) {
return animate(ColorProperties.BACKGROUND_COLOR, color, new ColorEvaluator());
}
Expand Down Expand Up @@ -558,159 +575,4 @@ public T elevationBy(int elevationBy) {
}
return self();
}


// public T widthPercent(float widthPercent) {
// if (initPercentListener()){
// mPercentListener.widthPercent(widthPercent);
// }
// return self();
// }
//
// public T widthPercentBy(float widthPercentBy) {
// if (initPercentListener()){
// mPercentListener.widthPercentBy(widthPercentBy);
// }
// return self();
// }
//
// public T heightPercent(float heightPercent) {
// if (initPercentListener()){
// mPercentListener.heightPercent(heightPercent);
// }
// return self();
// }
//
// public T heightPercentBy(float heightPercentBy) {
// if (initPercentListener()){
// mPercentListener.heightPercentBy(heightPercentBy);
// }
// return self();
// }
//
// public T sizePercent(float sizePercent) {
// if (initPercentListener()){
// mPercentListener.sizePercent(sizePercent);
// }
// return self();
// }
//
// public T sizePercentBy(float sizePercentBy) {
// if (initPercentListener()){
// mPercentListener.sizePercentBy(sizePercentBy);
// }
// return self();
// }
//
// public T leftMarginPercent(float marginPercent) {
// if (initPercentListener()){
// mPercentListener.leftMarginPercent(marginPercent);
// }
// return self();
// }
//
// public T leftMarginPercentBy(float marginPercentBy) {
// if (initPercentListener()){
// mPercentListener.leftMarginPercentBy(marginPercentBy);
// }
// return self();
// }
//
// public T topMarginPercent(float marginPercent) {
// if (initPercentListener()){
// mPercentListener.topMarginPercent(marginPercent);
// }
// return self();
// }
//
// public T topMarginPercentBy(float marginPercentBy) {
// if (initPercentListener()){
// mPercentListener.topMarginPercentBy(marginPercentBy);
// }
// return self();
// }
//
// public T bottomMarginPercent(float marginPercent) {
// if (initPercentListener()){
// mPercentListener.bottomMarginPercent(marginPercent);
// }
// return self();
// }
//
// public T bottomMarginPercentBy(float marginPercentBy) {
// if (initPercentListener()){
// mPercentListener.bottomMarginPercentBy(marginPercentBy);
// }
// return self();
// }
//
// public T rightMarginPercent(float marginPercent) {
// if (initPercentListener()){
// mPercentListener.rightMarginPercent(marginPercent);
// }
// return self();
// }
//
// public T rightMarginPercentBy(float marginPercentBy) {
// if (initPercentListener()){
// mPercentListener.rightMarginPercentBy(marginPercentBy);
// }
// return self();
// }
//
// public T horizontalMarginPercent(float marginPercent) {
// if (initPercentListener()){
// mPercentListener.horizontalMarginPercent(marginPercent);
// }
// return self();
// }
//
// public T horizontalMarginPercentBy(float marginPercentBy) {
// if (initPercentListener()){
// mPercentListener.horizontalMarginPercentBy(marginPercentBy);
// }
// return self();
// }
//
// public T verticalMarginPercent(float marginPercent) {
// if (initPercentListener()){
// mPercentListener.verticalMarginPercent(marginPercent);
// }
// return self();
// }
//
// public T verticalMarginPercentBy(float marginPercentBy) {
// if (initPercentListener()){
// mPercentListener.verticalMarginPercentBy(marginPercentBy);
// }
// return self();
// }
//
// public T marginPercent(float marginPercent) {
// if (initPercentListener()){
// mPercentListener.marginPercent(marginPercent);
// }
// return self();
// }
//
// public T marginPercentBy(float marginPercentBy) {
// if (initPercentListener()){
// mPercentListener.marginPercentBy(marginPercentBy);
// }
// return self();
// }
//
// public T aspectRatio(float aspectRatio) {
// if (initPercentListener()){
// mPercentListener.aspectRatio(aspectRatio);
// }
// return self();
// }
//
// public T aspectRatioBy(float aspectRatioBy) {
// if (initPercentListener()){
// mPercentListener.aspectRatioBy(aspectRatioBy);
// }
// return self();
// }
}
Loading

0 comments on commit 21591d1

Please sign in to comment.