-
Notifications
You must be signed in to change notification settings - Fork 185
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Generalizes animation framework and adds support for icon animation
- Loading branch information
Showing
7 changed files
with
262 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
145 changes: 15 additions & 130 deletions
145
flashbar/src/main/java/com/andrognito/flashbar/FlashAnim.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,148 +1,33 @@ | ||
package com.andrognito.flashbar | ||
|
||
import android.content.Context | ||
import android.support.annotation.AnimRes | ||
import android.support.annotation.InterpolatorRes | ||
import android.view.animation.Animation | ||
import android.view.animation.AnimationSet | ||
import android.view.animation.AnimationUtils | ||
import android.view.animation.Interpolator | ||
import com.andrognito.flashbar.FlashAnim.Position.BOTTOM | ||
import com.andrognito.flashbar.FlashAnim.Position.TOP | ||
|
||
class FlashAnim { | ||
|
||
private lateinit var animationSet: AnimationSet | ||
|
||
fun getAnimation() = animationSet | ||
internal lateinit var animation: AnimationSet | ||
|
||
companion object { | ||
fun with(context: Context): FlashAnimBuilder = FlashAnimBuilder(context) | ||
fun with(context: Context) = FlashAnimBuilderRetriever(context) | ||
} | ||
|
||
class FlashAnimBuilder(private val context: Context) { | ||
private val DEFAULT_ANIM_DURATION = context.resources | ||
.getInteger(R.integer.default_animation_duration).toLong() | ||
|
||
private val ANIM_ENTER_TOP = AnimationUtils.loadAnimation(context, R.anim.anim_enter_top) | ||
private val ANIM_ENTER_BOTTOM = AnimationUtils.loadAnimation(context, R.anim.anim_enter_bottom) | ||
private val ANIM_EXIT_TOP = AnimationUtils.loadAnimation(context, R.anim.anim_exit_top) | ||
private val ANIM_EXIT_BOTTOM = AnimationUtils.loadAnimation(context, R.anim.anim_exit_bottom) | ||
private val ANIM_ALPHA_ENTER = AnimationUtils.loadAnimation(context, R.anim.anim_alpha_enter) | ||
private val ANIM_ALPHA_EXIT = AnimationUtils.loadAnimation(context, R.anim.anim_alpha_exit) | ||
|
||
private val INTERPOLATOR_ACCELERATE = AnimationUtils.loadInterpolator(context, android.R.anim.accelerate_interpolator) | ||
private val INTERPOLATOR_DECELERATE = AnimationUtils.loadInterpolator(context, android.R.anim.decelerate_interpolator) | ||
private val INTERPOLATOR_ACCELERATE_DECELERATE = AnimationUtils.loadInterpolator(context, android.R.anim.accelerate_decelerate_interpolator) | ||
private val INTERPOLATOR_BOUNCE = AnimationUtils.loadInterpolator(context, android.R.anim.bounce_interpolator) | ||
private val INTERPOLATOR_OVERSHOOT = AnimationUtils.loadInterpolator(context, android.R.anim.overshoot_interpolator) | ||
|
||
private lateinit var positionAnim: Animation | ||
private lateinit var alphaAnim: Animation | ||
private var enterPosition: Position? = null | ||
private var exitPosition: Position? = null | ||
private var duration: Long? = null | ||
private var alpha: Boolean = false | ||
|
||
internal var interpolator: Interpolator? = null | ||
|
||
fun enterFrom(position: Position) = apply { | ||
this.enterPosition = position | ||
} | ||
|
||
fun exitFrom(position: Position) = apply { | ||
this.exitPosition = position | ||
} | ||
|
||
fun customAnimation(animation: Animation) = apply { | ||
this.positionAnim = animation | ||
} | ||
|
||
fun customAnimation(@AnimRes id: Int) = apply { | ||
this.positionAnim = AnimationUtils.loadAnimation(context, id) | ||
} | ||
|
||
fun alpha(alpha: Boolean) = apply { this.alpha = alpha } | ||
|
||
fun accelerate() = apply { | ||
this.interpolator = INTERPOLATOR_ACCELERATE | ||
} | ||
|
||
fun decelerate() = apply { | ||
this.interpolator = INTERPOLATOR_DECELERATE | ||
} | ||
|
||
fun accelerateDecelerate() = apply { | ||
this.interpolator = INTERPOLATOR_ACCELERATE_DECELERATE | ||
} | ||
|
||
fun bounce() = apply { | ||
this.interpolator = INTERPOLATOR_BOUNCE | ||
} | ||
|
||
fun overshoot() = apply { | ||
this.interpolator = INTERPOLATOR_OVERSHOOT | ||
} | ||
|
||
fun interpolator(interpolator: Interpolator) = apply { | ||
this.interpolator = interpolator | ||
} | ||
|
||
fun interpolator(@InterpolatorRes id: Int) = apply { | ||
this.interpolator = AnimationUtils.loadInterpolator(context, id) | ||
} | ||
|
||
fun duration(duration: Long) = apply { | ||
this.duration = duration | ||
} | ||
|
||
fun build(): FlashAnim { | ||
require((enterPosition != null).xor(exitPosition != null), | ||
{ "You must specify at least one of the animations but not both" }) | ||
|
||
val flashAnim = FlashAnim() | ||
val animationSet = AnimationSet(false) | ||
animationSet.fillAfter = true | ||
|
||
if (!::positionAnim.isInitialized) { | ||
if (enterPosition != null) { | ||
when (enterPosition) { | ||
TOP -> positionAnim = ANIM_ENTER_TOP | ||
BOTTOM -> positionAnim = ANIM_ENTER_BOTTOM | ||
} | ||
|
||
if (alpha) alphaAnim = ANIM_ALPHA_ENTER | ||
} | ||
|
||
if (exitPosition != null) { | ||
when (exitPosition) { | ||
TOP -> positionAnim = ANIM_EXIT_TOP | ||
BOTTOM -> positionAnim = ANIM_EXIT_BOTTOM | ||
} | ||
|
||
if (alpha) alphaAnim = ANIM_ALPHA_EXIT | ||
|
||
} | ||
} | ||
|
||
animationSet.addAnimation(positionAnim) | ||
if (::alphaAnim.isInitialized) { | ||
animationSet.addAnimation(alphaAnim) | ||
} | ||
|
||
animationSet.duration = if (duration != null) duration!! else DEFAULT_ANIM_DURATION | ||
|
||
if (interpolator != null) { | ||
positionAnim.interpolator = interpolator | ||
} | ||
|
||
flashAnim.animationSet = animationSet | ||
return flashAnim | ||
} | ||
enum class Type { | ||
ENTER, | ||
EXIT, | ||
} | ||
|
||
enum class Position { | ||
TOP, | ||
BOTTOM, | ||
} | ||
|
||
enum class Alpha { | ||
IN, | ||
OUT, | ||
} | ||
} | ||
|
||
class FlashAnimBuilderRetriever(private val context: Context) { | ||
fun animateBar() = FlashAnimBarBuilder(context) | ||
fun animateIcon() = FlashAnimIconBuilder(context) | ||
} |
187 changes: 187 additions & 0 deletions
187
flashbar/src/main/java/com/andrognito/flashbar/FlashAnimIconBuilder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
package com.andrognito.flashbar | ||
|
||
import android.content.Context | ||
import android.support.annotation.AnimRes | ||
import android.support.annotation.InterpolatorRes | ||
import android.view.animation.Animation | ||
import android.view.animation.AnimationSet | ||
import android.view.animation.AnimationUtils | ||
import android.view.animation.Interpolator | ||
import com.andrognito.flashbar.FlashAnim.Alpha.IN | ||
import com.andrognito.flashbar.FlashAnim.Alpha.OUT | ||
import com.andrognito.flashbar.FlashAnim.Position.BOTTOM | ||
import com.andrognito.flashbar.FlashAnim.Position.TOP | ||
import com.andrognito.flashbar.FlashAnim.Type.ENTER | ||
import com.andrognito.flashbar.FlashAnim.Type.EXIT | ||
|
||
abstract class BaseFlashAnimBuilder(private val context: Context) { | ||
private val DEFAULT_ANIM_DURATION = context.resources | ||
.getInteger(R.integer.default_animation_duration).toLong() | ||
|
||
private val INTERPOLATOR_LINEAR = AnimationUtils.loadInterpolator(context, | ||
android.R.anim.linear_interpolator) | ||
private val INTERPOLATOR_ACCELERATE = AnimationUtils.loadInterpolator(context, | ||
android.R.anim.accelerate_interpolator) | ||
private val INTERPOLATOR_DECELERATE = AnimationUtils.loadInterpolator(context, | ||
android.R.anim.decelerate_interpolator) | ||
private val INTERPOLATOR_ACCELERATE_DECELERATE = AnimationUtils.loadInterpolator(context, | ||
android.R.anim.accelerate_decelerate_interpolator) | ||
private val INTERPOLATOR_OVERSHOOT = AnimationUtils.loadInterpolator(context, | ||
android.R.anim.overshoot_interpolator) | ||
private val INTERPOLATOR_ANTICIPATE_OVERSHOOT = AnimationUtils.loadInterpolator(context, | ||
android.R.anim.anticipate_overshoot_interpolator) | ||
|
||
protected val ANIM_SLIDE_FROM_TOP = AnimationUtils.loadAnimation(context, R.anim.anim_enter_top) | ||
protected val ANIM_SLIDE_FROM_BOTTOM = AnimationUtils.loadAnimation(context, R.anim.anim_enter_bottom) | ||
protected val ANIM_SLIDE_TO_TOP = AnimationUtils.loadAnimation(context, R.anim.anim_exit_top) | ||
protected val ANIM_SLIDE_TO_BOTTOM = AnimationUtils.loadAnimation(context, R.anim.anim_exit_bottom) | ||
protected val ANIM_ALPHA_IN = AnimationUtils.loadAnimation(context, R.anim.anim_alpha_enter) | ||
protected val ANIM_ALPHA_OUT = AnimationUtils.loadAnimation(context, R.anim.anim_alpha_exit) | ||
|
||
protected var duration: Long = DEFAULT_ANIM_DURATION | ||
protected var interpolator: Interpolator = INTERPOLATOR_LINEAR | ||
protected var animation: Animation? = null | ||
protected var alpha: FlashAnim.Alpha? = null | ||
|
||
fun accelerate() = apply { | ||
this.interpolator = INTERPOLATOR_ACCELERATE | ||
} | ||
|
||
fun decelerate() = apply { | ||
this.interpolator = INTERPOLATOR_DECELERATE | ||
} | ||
|
||
fun accelerateDecelerate() = apply { | ||
this.interpolator = INTERPOLATOR_ACCELERATE_DECELERATE | ||
} | ||
|
||
fun overshoot() = apply { | ||
this.interpolator = INTERPOLATOR_OVERSHOOT | ||
} | ||
|
||
fun anticipateOvershoot() = apply { | ||
this.interpolator = INTERPOLATOR_ANTICIPATE_OVERSHOOT | ||
} | ||
|
||
fun interpolator(interpolator: Interpolator) = apply { | ||
this.interpolator = interpolator | ||
} | ||
|
||
fun interpolator(@InterpolatorRes id: Int) = apply { | ||
this.interpolator = AnimationUtils.loadInterpolator(context, id) | ||
} | ||
|
||
fun animation(animation: Animation) = apply { | ||
this.animation = animation | ||
} | ||
|
||
fun animation(@AnimRes id: Int) = apply { | ||
this.animation = AnimationUtils.loadAnimation(context, id) | ||
} | ||
|
||
fun alphaIn() = apply { this.alpha = IN } | ||
|
||
fun alphaOut() = apply { this.alpha = OUT } | ||
|
||
fun duration(millis: Long) = apply { | ||
this.duration = millis | ||
} | ||
|
||
abstract fun build(): FlashAnim | ||
} | ||
|
||
class FlashAnimIconBuilder(context: Context) : BaseFlashAnimBuilder(context) { | ||
|
||
private val ANIM_PULSE = AnimationUtils.loadAnimation(context, R.anim.anim_pulse) | ||
|
||
fun pulse() = apply { this.animation = ANIM_PULSE } | ||
|
||
override fun build(): FlashAnim { | ||
val flashAnim = FlashAnim() | ||
val animationSet = AnimationSet(false) | ||
animationSet.fillAfter = true | ||
animationSet.addAnimation(animation) | ||
animationSet.duration = duration | ||
animationSet.interpolator = interpolator | ||
|
||
if (alpha != null) { | ||
when (alpha) { | ||
IN -> animationSet.addAnimation(ANIM_ALPHA_IN) | ||
OUT -> animationSet.addAnimation(ANIM_ALPHA_OUT) | ||
} | ||
} | ||
|
||
flashAnim.animation = animationSet | ||
return flashAnim | ||
} | ||
} | ||
|
||
class FlashAnimBarBuilder(context: Context) : BaseFlashAnimBuilder(context) { | ||
|
||
private var type: FlashAnim.Type? = null | ||
private var position: FlashAnim.Position? = null | ||
private var alphaEnabled: Boolean = false | ||
|
||
fun enterFrom(position: FlashAnim.Position) = apply { | ||
require(this.type == null && this.position == null, | ||
{ "Animation position is already initialized" }) | ||
|
||
this.type = ENTER | ||
this.position = position | ||
} | ||
|
||
fun exitFrom(position: FlashAnim.Position) = apply { | ||
require(this.type == null && this.position == null, | ||
{ "Animation position is already initialized" }) | ||
|
||
this.type = EXIT | ||
this.position = position | ||
} | ||
|
||
fun alpha() = apply { this.alphaEnabled = true } | ||
|
||
override fun build(): FlashAnim { | ||
require(type != null && position != null, | ||
{ "You must specify the animation position" }) | ||
|
||
val flashAnim = FlashAnim() | ||
val animationSet = AnimationSet(false) | ||
animationSet.fillAfter = true | ||
animationSet.duration = duration | ||
animationSet.interpolator = interpolator | ||
|
||
// Only if custom animation is not applied | ||
if (animation == null) { | ||
when (type) { | ||
ENTER -> { | ||
when (position) { | ||
TOP -> animation = ANIM_SLIDE_FROM_TOP | ||
BOTTOM -> animation = ANIM_SLIDE_FROM_BOTTOM | ||
} | ||
} | ||
EXIT -> { | ||
when (position) { | ||
TOP -> animation = ANIM_SLIDE_TO_TOP | ||
BOTTOM -> animation = ANIM_SLIDE_TO_BOTTOM | ||
} | ||
} | ||
} | ||
} | ||
animationSet.addAnimation(animation) | ||
|
||
if (alphaEnabled) { | ||
when (type) { | ||
ENTER -> animationSet.addAnimation(ANIM_ALPHA_IN) | ||
EXIT -> animationSet.addAnimation(ANIM_ALPHA_OUT) | ||
} | ||
} else if (alpha != null) { | ||
when (alpha) { | ||
IN -> animationSet.addAnimation(ANIM_ALPHA_IN) | ||
OUT -> animationSet.addAnimation(ANIM_ALPHA_OUT) | ||
} | ||
} | ||
|
||
flashAnim.animation = animationSet | ||
return flashAnim | ||
} | ||
} |
Oops, something went wrong.