Created
January 26, 2018 10:22
-
-
Save EmmanuelGuther/bb7febc3e8291f6409ad2fd481c0e2fe to your computer and use it in GitHub Desktop.
This file contains hidden or 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
/** | |
* 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