Skip to content

Instantly share code, notes, and snippets.

@EmmanuelGuther
Created January 26, 2018 10:22
Show Gist options
  • Save EmmanuelGuther/bb7febc3e8291f6409ad2fd481c0e2fe to your computer and use it in GitHub Desktop.
Save EmmanuelGuther/bb7febc3e8291f6409ad2fd481c0e2fe to your computer and use it in GitHub Desktop.
/**
* Created by emmanuelguther on 26/01/2018.
*/
class RepeteableTransitionDrawable(layers: Array<Drawable>) : LayerDrawable(layers) {
/**
* The current state ofx the transition. One of [.TRANSITION_STARTING], [.TRANSITION_RUNNING] and [.TRANSITION_NONE]
*/
private var mTransitionState = TRANSITION_NONE
private var mReverse: Boolean = false
private var mStartTimeMillis: Long = 0
private var mFrom: Int = 0
private var mTo: Int = 0
private var mDuration: Int = 0
private var mOriginalDuration: Int = 0
private var mAlpha = 0
/**
* Indicates whether the cross fade is enabled for this transition.
*
* @return True if cross fading is enabled, false otherwise.
*/
/**
* Enables or disables the cross fade of the drawables. When cross fade is disabled, the first drawable is always drawn opaque. With cross fade enabled, the first drawable is drawn with the
* opposite alpha of the second drawable. Cross fade is disabled by default.
*
* @param enabled True to enable cross fading, false otherwise.
*/
var isCrossFadeEnabled: Boolean = false
private var currentRepeatedCount = 0
var repeatCount = 1
/**
* Begin the second layer on top of the first layer.
*
* @param durationMillis The length of the transition in milliseconds
*/
fun startTransition(durationMillis: Int) {
if (mTransitionState == TRANSITION_RUNNING)
return
Log.d(TAG, "startTransition")
mFrom = 0
mTo = 255
mAlpha = 0
mOriginalDuration = durationMillis
mDuration = mOriginalDuration
mReverse = false
mTransitionState = TRANSITION_STARTING
currentRepeatedCount = 0
invalidateSelf()
}
/**
* Show only the first layer.
*/
fun resetTransition() {
Log.d(TAG, "resetTransition")
mAlpha = 0
mTransitionState = TRANSITION_NONE
currentRepeatedCount = 0
invalidateSelf()
}
/**
* Reverses the transition, picking up where the transition currently is. If the transition is not currently running, this will start the transition with the specified duration. If the transition
* is already running, the last known duration will be used.
*
* @param duration The duration to use if no transition is running.
*/
fun reverseTransition(duration: Int) {
val time = SystemClock.uptimeMillis()
// Animation is over
if (time - mStartTimeMillis >= mDuration) {
Log.d(TAG, "Animation is over, reversing")
if (mTo == 0) {
mFrom = 0
mTo = 255
mAlpha = 0
mReverse = false
} else {
mFrom = 255
mTo = 0
mAlpha = 255
mReverse = true
}
mOriginalDuration = duration
mDuration = mOriginalDuration
mTransitionState = TRANSITION_STARTING
invalidateSelf()
return
}
Log.d(TAG, "Animation is not over yet, changing animation direction. Time elapsed : " + (time - mStartTimeMillis))
mReverse = !mReverse
mFrom = mAlpha
mTo = if (mReverse) 0 else 255
mDuration = (if (mReverse) time - mStartTimeMillis else mOriginalDuration - (time - mStartTimeMillis)).toInt()
mTransitionState = TRANSITION_STARTING
}
override fun draw(canvas: Canvas) {
var done = true
when (mTransitionState) {
TRANSITION_STARTING -> {
mStartTimeMillis = SystemClock.uptimeMillis()
done = false
mTransitionState = TRANSITION_RUNNING
}
TRANSITION_RUNNING -> if (mStartTimeMillis >= 0) {
var normalized = (SystemClock.uptimeMillis() - mStartTimeMillis).toFloat() / mDuration
done = normalized >= 1.0f
normalized = Math.min(normalized, 1.0f)
mAlpha = (mFrom + (mTo - mFrom) * normalized).toInt()
}
}
val alpha = mAlpha
val crossFade = isCrossFadeEnabled
if (done) {
Log.d(TAG, "done inside onDraw")
// the setAlpha() calls below trigger invalidation and redraw. If we're done, just draw
// the appropriate drawable[s] and return
if (!crossFade || alpha == 0) {
getDrawable(0).draw(canvas)
}
if (alpha == 0xFF) {
getDrawable(1).draw(canvas)
}
if (mTransitionState == TRANSITION_RUNNING) {
currentRepeatedCount++
Log.d(TAG, "currentRepeatedCount: $currentRepeatedCount, repeatCount: $repeatCount, mTransitionState: $mTransitionState")
if (currentRepeatedCount < repeatCount) {
mTransitionState = TRANSITION_NONE
reverseTransition(mDuration)
} else {
currentRepeatedCount = 0
mTransitionState = TRANSITION_NONE
}
}
return
}
var d: Drawable
d = getDrawable(0)
if (crossFade) {
d.alpha = 255 - alpha
}
d.draw(canvas)
if (crossFade) {
d.alpha = 0xFF
}
if (alpha > 0) {
d = getDrawable(1)
d.alpha = alpha
d.draw(canvas)
d.alpha = 0xFF
}
if (!done) {
invalidateSelf()
}
}
companion object {
private val TAG = "RepeatTrannDrawable"
/**
* A transition is about to start.
*/
private val TRANSITION_STARTING = 0
/**
* The transition has started and the animation is in progress
*/
private val TRANSITION_RUNNING = 1
/**
* No transition will be applied
*/
private val TRANSITION_NONE = 2
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment